Skip to content

Commit

Permalink
[PRD-3898] Transfer restrictions integration specs (#22)
Browse files Browse the repository at this point in the history
* add max holders group validation

* initialize active holder by default

* refactor test environment to setup each envs separately

* add initialize data specs

* add initialize holder specs

* add initialize holdergroup specs

* add initialize group specs

* add transfer restrictions specs to CI

* add initialize associated account specs

* add initialize transfer rule specs

* fix ts lint

* add transfer group not allowed when locked until is zero

* refactor test to commitment name

* update transfer restrictions idl

* add set allow transfer rule specs

* add set holder group max specs

* add set holder max specs

* update filename

* add set lockup escrow account specs

* add validation of tokenlock discriminator

* add tokenlock discriminator error

* remove solana-program dependency from tokenlock

* add holder to the group on security associated account initialization

* update idl

* add update wallet group specs

* update idl

* fix ts lint

* add extra account data validation on transfer hook

* fix specs

* add pause specs

* add holders count validation for init sec assoc token specs

* add revoke holder group specs

* add revoke holder group specs

* revoke holder without holder group and group

* add wallet presence in group and holder before revokes

* add revoke holder specs

* add revoke security token account specs

* add explicit error that wallet new group must be differ from existing

* add explicit error that wallet new group must be differ from existing

* does not increment holderIds for already initialized one

* update idl

* fix specs

* add enforce transfer restrictions specs

* remove obsolete commented code

* fix spec
  • Loading branch information
makarychev authored Aug 9, 2024
1 parent acd8dd4 commit c97853b
Show file tree
Hide file tree
Showing 67 changed files with 5,410 additions and 219 deletions.
2 changes: 1 addition & 1 deletion Anchor.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ types = "app/src/idl/"


[scripts]
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/*.ts tests/tokenlock/*.ts tests/access_control/*.ts"
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/*.ts tests/tokenlock/*.ts tests/access_control/*.ts tests/transfer_restrictions/*.ts"
122 changes: 118 additions & 4 deletions app/src/idl/transfer_restrictions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,6 @@ export type TransferRestrictions = {
},
{
"name": "group",
"writable": true,
"pda": {
"seeds": [
{
Expand Down Expand Up @@ -365,7 +364,8 @@ export type TransferRestrictions = {
}
},
{
"name": "group"
"name": "group",
"writable": true
},
{
"name": "holder",
Expand Down Expand Up @@ -946,6 +946,80 @@ export type TransferRestrictions = {
]
}
},
{
"name": "transferRestrictionData",
"writable": true,
"pda": {
"seeds": [
{
"kind": "const",
"value": [
116,
114,
100
]
},
{
"kind": "account",
"path": "transfer_restriction_data.security_token_mint",
"account": "transferRestrictionData"
}
]
}
},
{
"name": "authorityWalletRole",
"writable": true
},
{
"name": "payer",
"writable": true,
"signer": true
},
{
"name": "systemProgram",
"address": "11111111111111111111111111111111"
}
],
"args": []
},
{
"name": "revokeHolderGroup",
"discriminator": [
33,
153,
183,
187,
204,
120,
164,
40
],
"accounts": [
{
"name": "holder",
"pda": {
"seeds": [
{
"kind": "const",
"value": [
116,
114,
104
]
},
{
"kind": "account",
"path": "transferRestrictionData"
},
{
"kind": "account",
"path": "holder.id",
"account": "transferRestrictionHolder"
}
]
}
},
{
"name": "holderGroup",
"writable": true,
Expand Down Expand Up @@ -1894,8 +1968,8 @@ export type TransferRestrictions = {
},
{
"code": 6002,
"name": "transferRuleLocked",
"msg": "Transfer rule locked"
"name": "transferRuleNotAllowedUntilLater",
"msg": "Transfer rule not allowed until later"
},
{
"code": 6003,
Expand Down Expand Up @@ -1931,6 +2005,46 @@ export type TransferRestrictions = {
"code": 6009,
"name": "invalidHolderIndex",
"msg": "Invalid transfer restriction holder index"
},
{
"code": 6010,
"name": "maxHoldersReachedInsideTheGroup",
"msg": "Max holders reached inside the group"
},
{
"code": 6011,
"name": "transferGroupNotApproved",
"msg": "Transfer group not approved"
},
{
"code": 6012,
"name": "incorrectTokenlockAccount",
"msg": "Wrong tokenlock account"
},
{
"code": 6013,
"name": "transferRuleAccountDataIsEmtpy",
"msg": "Transfer rule account data is empty"
},
{
"code": 6014,
"name": "securityAssociatedAccountDataIsEmtpy",
"msg": "Security associated account data is empty"
},
{
"code": 6015,
"name": "transferRestrictionsAccountDataIsEmtpy",
"msg": "Transfer restrictions account data is empty"
},
{
"code": 6016,
"name": "noWalletsInGroup",
"msg": "No wallets in group"
},
{
"code": 6017,
"name": "newGroupIsTheSameAsTheCurrentGroup",
"msg": "New group is the same as the current group"
}
],
"types": [
Expand Down
1 change: 0 additions & 1 deletion programs/tokenlock/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
anchor-lang = "0.30.1"
anchor-spl = "0.30.1"
hex = "0.4.3"
solana-program = "1.18.15"
sha2 = "0.10.2"
access-control = { path = "../access-control", features = ["cpi"] }
transfer-restrictions = { path = "../transfer-restrictions", features = ["cpi"] }
Expand Down
3 changes: 1 addition & 2 deletions programs/tokenlock/src/instructions/cancel_timelock.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use anchor_lang::{prelude::*, Discriminator};
use anchor_lang::{prelude::*, solana_program::program_memory::sol_memcmp, Discriminator};
use anchor_spl::token_interface::{Mint, Token2022, TokenAccount};
use solana_program::program_memory::sol_memcmp;
use transfer_restrictions::program::TransferRestrictions;

use crate::{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use access_control::{
program::AccessControl as AccessControlProgram, AccessControl, WalletRole, ADMIN_ROLES,
};
use anchor_lang::{prelude::*, Discriminator};
use solana_program::program_memory::sol_memcmp;
use anchor_lang::{prelude::*, solana_program::program_memory::sol_memcmp, Discriminator};

use crate::{
utils, ReleaseSchedule, TimelockData, TokenLockData, TokenLockDataWrapper, TokenlockErrors,
Expand Down
7 changes: 4 additions & 3 deletions programs/tokenlock/src/instructions/initialize_timelock.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use access_control::{program::AccessControl as AccessControlProgram, AccessControl, WalletRole, ADMIN_ROLES};
use anchor_lang::{prelude::*, Discriminator};
use solana_program::program_memory::sol_memcmp;
use access_control::{
program::AccessControl as AccessControlProgram, AccessControl, WalletRole, ADMIN_ROLES,
};
use anchor_lang::{prelude::*, solana_program::program_memory::sol_memcmp, Discriminator};

use crate::{TimelockData, TokenLockData, TokenLockDataWrapper, TokenlockErrors};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use access_control::{
use access_control::cpi::accounts::MintSecurities;
use anchor_lang::{prelude::*, Discriminator};
use anchor_spl::token_interface::{Mint, Token2022, TokenAccount};
use solana_program::program_memory::{sol_memcmp, sol_memcpy};
use anchor_lang::solana_program::program_memory::{sol_memcmp, sol_memcpy};

use crate::TOKENLOCK_PDA_SEED;
use crate::{
Expand Down
5 changes: 2 additions & 3 deletions programs/tokenlock/src/instructions/transfer_from.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use anchor_lang::{prelude::*, Discriminator};
use anchor_lang::{prelude::*, solana_program::program_memory::sol_memcmp, Discriminator};
use anchor_spl::token_interface::{Mint, Token2022, TokenAccount};
use solana_program::program_memory::sol_memcmp;
use transfer_restrictions::program::TransferRestrictions;

use crate::{
Expand Down Expand Up @@ -127,7 +126,7 @@ pub fn transfer<'info>(

let to = &ctx.accounts.to;
// if recipient owner is a signer we skip enforcing transfer restrictions
if ctx.accounts.authority.key() != to.owner {
if ctx.accounts.authority.key() != to.owner {
if ctx.remaining_accounts.len() == 0
|| ctx.remaining_accounts[0].key()
!= TokenLockDataWrapper::transfer_restriction_data(&tokenlock_account_data)
Expand Down
3 changes: 1 addition & 2 deletions programs/tokenlock/src/instructions/transfer_timelock.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use anchor_lang::{prelude::*, Discriminator};
use anchor_lang::{prelude::*, solana_program::program_memory::sol_memcmp, Discriminator};
use anchor_spl::token_interface::{Mint, Token2022, TokenAccount};
use solana_program::program_memory::sol_memcmp;
use transfer_restrictions::program::TransferRestrictions;

use crate::{
Expand Down
3 changes: 1 addition & 2 deletions programs/tokenlock/src/states/release_schedule.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

use anchor_lang::prelude::*;
use solana_program::program_memory::sol_memcmp;
use anchor_lang::{prelude::*, solana_program::program_memory::sol_memcmp};

#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct ReleaseSchedule {
Expand Down
3 changes: 1 addition & 2 deletions programs/tokenlock/src/states/timelock_data.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use anchor_lang::prelude::*;
use solana_program::program_memory::sol_memcmp;
use anchor_lang::{prelude::*, solana_program::program_memory::sol_memcmp};

use crate::{common::PUBKEY_SIZE, ReleaseSchedule, TokenLockDataWrapper};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub struct InitializeHolderGroup<'info> {
)]
pub transfer_restriction_data: Account<'info, TransferRestrictionData>,

#[account(mut,
#[account(
seeds = [
TRANSFER_RESTRICTION_GROUP_PREFIX.as_bytes(),
&transfer_restriction_data.key().to_bytes(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub struct InitializeSecurityAssociatedAccount<'info> {
bump,
)]
pub security_associated_account: Account<'info, SecurityAssociatedAccount>,
#[account(
#[account(mut,
constraint = group.transfer_restriction_data == transfer_restriction_data.key(),
)]
pub group: Account<'info, TransferRestrictionGroup>,
Expand Down
3 changes: 3 additions & 0 deletions programs/transfer-restrictions/src/contexts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ pub use revoke_security_associated_account::*;
pub mod revoke_holder;
pub use revoke_holder::*;

pub mod revoke_holder_group;
pub use revoke_holder_group::*;

pub mod set_lockup_escrow_account;
pub use set_lockup_escrow_account::*;

Expand Down
27 changes: 2 additions & 25 deletions programs/transfer-restrictions/src/contexts/revoke_holder.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
HolderGroup, TransferRestrictionData, TransferRestrictionGroup, TransferRestrictionHolder, TRANSFER_RESTRICTION_DATA_PREFIX, TRANSFER_RESTRICTION_GROUP_PREFIX, TRANSFER_RESTRICTION_HOLDER_GROUP_PREFIX, TRANSFER_RESTRICTION_HOLDER_PREFIX
TransferRestrictionData, TransferRestrictionHolder, TRANSFER_RESTRICTION_DATA_PREFIX,
TRANSFER_RESTRICTION_HOLDER_PREFIX,
};
use access_control::{self, WalletRole};
use anchor_lang::prelude::*;
Expand All @@ -18,36 +19,12 @@ pub struct RevokeHolder<'info> {
)]
pub holder: Account<'info, TransferRestrictionHolder>,

#[account(mut,
close = payer,
seeds = [
TRANSFER_RESTRICTION_HOLDER_GROUP_PREFIX.as_bytes(),
&holder.key().to_bytes(),
&group.id.to_le_bytes(),
],
bump,
constraint = holder_group.holder == holder.key(),
constraint = holder_group.group == group.id,
)]
pub holder_group: Account<'info, HolderGroup>,

#[account(mut,
seeds = [TRANSFER_RESTRICTION_DATA_PREFIX.as_bytes(), &transfer_restriction_data.security_token_mint.key().to_bytes()],
bump,
)]
pub transfer_restriction_data: Account<'info, TransferRestrictionData>,

#[account(
seeds = [
TRANSFER_RESTRICTION_GROUP_PREFIX.as_bytes(),
&transfer_restriction_data.key().to_bytes(),
&group.id.to_le_bytes()
],
bump,
constraint = group.transfer_restriction_data == transfer_restriction_data.key(),
)]
pub group: Account<'info, TransferRestrictionGroup>,

#[account(mut,
constraint = authority_wallet_role.owner == payer.key(),
constraint = authority_wallet_role.access_control == transfer_restriction_data.access_control_account.key(),
Expand Down
59 changes: 59 additions & 0 deletions programs/transfer-restrictions/src/contexts/revoke_holder_group.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use crate::{
HolderGroup, TransferRestrictionData, TransferRestrictionGroup, TransferRestrictionHolder, TRANSFER_RESTRICTION_DATA_PREFIX, TRANSFER_RESTRICTION_GROUP_PREFIX, TRANSFER_RESTRICTION_HOLDER_GROUP_PREFIX, TRANSFER_RESTRICTION_HOLDER_PREFIX
};
use access_control::{self, WalletRole};
use anchor_lang::prelude::*;

#[derive(Accounts)]
pub struct RevokeHolderGroup<'info> {
#[account(
seeds = [
TRANSFER_RESTRICTION_HOLDER_PREFIX.as_bytes(),
&transfer_restriction_data.key().to_bytes(),
&holder.id.to_le_bytes(),
],
bump,
constraint = holder.transfer_restriction_data == transfer_restriction_data.key(),
)]
pub holder: Account<'info, TransferRestrictionHolder>,

#[account(mut,
close = payer,
seeds = [
TRANSFER_RESTRICTION_HOLDER_GROUP_PREFIX.as_bytes(),
&holder.key().to_bytes(),
&group.id.to_le_bytes(),
],
bump,
constraint = holder_group.holder == holder.key(),
constraint = holder_group.group == group.id,
)]
pub holder_group: Account<'info, HolderGroup>,

#[account(mut,
seeds = [TRANSFER_RESTRICTION_DATA_PREFIX.as_bytes(), &transfer_restriction_data.security_token_mint.key().to_bytes()],
bump,
)]
pub transfer_restriction_data: Account<'info, TransferRestrictionData>,

#[account(
seeds = [
TRANSFER_RESTRICTION_GROUP_PREFIX.as_bytes(),
&transfer_restriction_data.key().to_bytes(),
&group.id.to_le_bytes()
],
bump,
constraint = group.transfer_restriction_data == transfer_restriction_data.key(),
)]
pub group: Account<'info, TransferRestrictionGroup>,

#[account(mut,
constraint = authority_wallet_role.owner == payer.key(),
constraint = authority_wallet_role.access_control == transfer_restriction_data.access_control_account.key(),
)]
pub authority_wallet_role: Account<'info, WalletRole>,

#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
}
Loading

0 comments on commit c97853b

Please sign in to comment.