diff --git a/public/images/ccip/cct/cct-svm-diagrams/burnmint-pool-anatomy.svg b/public/images/ccip/cct/cct-svm-diagrams/burnmint-pool-anatomy.svg new file mode 100644 index 00000000000..5126bf88125 --- /dev/null +++ b/public/images/ccip/cct/cct-svm-diagrams/burnmint-pool-anatomy.svg @@ -0,0 +1,102 @@ +

EXTERNAL ACCOUNTS

PROGRAM-DERIVED ADDRESSES (PDAs)

BURN-MINT TOKEN POOL PROGRAM

Token Infrastructure

Option 1: Direct Transfer

Option 2: Multisig Configuration
Recommended for Production

Program Logic
• Burns tokens on outbound transfers
• Mints tokens on inbound transfers
• Requires mint authority control

Global Config PDA
Seeds: config

Pool State PDA
Seeds: ccip_tokenpool_config, mint

Pool Signer PDA
Seeds: ccip_tokenpool_signer, mint

Chain Config PDAs
Seeds: ccip_tokenpool_chainconfig, chain_selector, mint

Token Mint Account
Owner: SPL Token OR Token-2022

Pool Token Account
ATA: pool_signer + mint + token_program

SPL Token Multisig Account
• M-of-N signatures required
• Pool Signer PDA appears ≥M times
• Enables autonomous operation + governance

\ No newline at end of file diff --git a/public/images/ccip/cct/cct-svm-diagrams/cct-svm-accepting-administrator-role.png b/public/images/ccip/cct/cct-svm-diagrams/cct-svm-accepting-administrator-role.png deleted file mode 100644 index 6cd6505847e..00000000000 Binary files a/public/images/ccip/cct/cct-svm-diagrams/cct-svm-accepting-administrator-role.png and /dev/null differ diff --git a/public/images/ccip/cct/cct-svm-diagrams/cct-svm-proposing-administrator.png b/public/images/ccip/cct/cct-svm-diagrams/cct-svm-proposing-administrator.png deleted file mode 100644 index 28ec2a1cbfd..00000000000 Binary files a/public/images/ccip/cct/cct-svm-diagrams/cct-svm-proposing-administrator.png and /dev/null differ diff --git a/public/images/ccip/cct/cct-svm-diagrams/cct-svm-set-pool.png b/public/images/ccip/cct/cct-svm-diagrams/cct-svm-set-pool.png deleted file mode 100644 index 935aa799135..00000000000 Binary files a/public/images/ccip/cct/cct-svm-diagrams/cct-svm-set-pool.png and /dev/null differ diff --git a/public/images/ccip/cct/cct-svm-diagrams/cct-svm-transfer-administrator-role.png b/public/images/ccip/cct/cct-svm-diagrams/cct-svm-transfer-administrator-role.png deleted file mode 100644 index 5e99b18dfbc..00000000000 Binary files a/public/images/ccip/cct/cct-svm-diagrams/cct-svm-transfer-administrator-role.png and /dev/null differ diff --git a/public/images/ccip/cct/cct-svm-diagrams/lockrelease-pool-anatomy.svg b/public/images/ccip/cct/cct-svm-diagrams/lockrelease-pool-anatomy.svg new file mode 100644 index 00000000000..f7642093e16 --- /dev/null +++ b/public/images/ccip/cct/cct-svm-diagrams/lockrelease-pool-anatomy.svg @@ -0,0 +1,102 @@ +

EXTERNAL ACCOUNTS

PROGRAM ACCOUNTS

LOCK-RELEASE TOKEN POOL PROGRAM

Rebalancer Liquidity

Token Infrastructure

Transfer only
No mint authority needed

Transfers tokens to/from
via provide/withdraw liquidity

Program Logic
• Locks tokens in pool
• Releases tokens from pool
• Manages liquidity

Global Config PDA
Seeds: config

Pool State PDA
Seeds: pool_state_seed, mint
Additional: rebalancer, can_accept_liquidity

Pool Signer PDA
Seeds: pool_signer_seed, mint

Chain Config PDAs
Seeds: chain_config_seed, chain_selector, mint

Token Mint Account
Owner: SPL Token OR Token-2022

Pool Token Account
ATA: pool_signer + mint + token_program
Holds locked tokens

Any token account the rebalancer
can authorize transfers for

\ No newline at end of file diff --git a/public/images/ccip/cct/cct-svm-diagrams/solana_accept_admin.svg b/public/images/ccip/cct/cct-svm-diagrams/solana_accept_admin.svg new file mode 100644 index 00000000000..086acab561b --- /dev/null +++ b/public/images/ccip/cct/cct-svm-diagrams/solana_accept_admin.svg @@ -0,0 +1 @@ +title%20Accepting%20the%20Administrator%20Role%20(accept_admin_role_token_admin_registry)%0Aparticipant%20%22Pending%20Administrator%22%20as%20PendingAdmin%0Aparticipantgroup%20%230847F7%20**%3Ccolor%3A%23white%3EChainlink%20Router%20Program%3C%2Fcolor%3E**%0A%20%20participant%20%22Router%22%20as%20Router%0A%20%20participant%20%22TokenAdminRegistry%20PDA%22%20as%20Registry%0Aend%0Aactivate%20PendingAdmin%20%230847F7%0APendingAdmin-%3ERouter%3A%20accept_admin_role_token_admin_registry()%0Aactivate%20Router%20%238AA6F9%0Anote%20right%20of%20Router%20%23F8FAFF%3A%201)%20Anchor%20enforces%20authority%3D%3Dtoken_admin_registry.pending_administrator%0Anote%20right%20of%20Router%20%23F8FAFF%3A%202)%20Validate%20TokenAdminRegistry%20version%20%26%20seeds%0Aalt%20Authorized%20%26%20Valid%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%203)%20Update%20TokenAdminRegistry%20PDA%0A%20%20Router-%3ERegistry%3A%20%3Ccolor%3A%23white%3Eadministrator%20%3D%20pending_administrator%3C%2Fcolor%3E%0A%20%20activate%20Registry%20%238AA6F9%0A%20%20Registry--%3ERouter%3A%20%3Ccolor%3A%23white%3Esuccess%3C%2Fcolor%3E%0A%20%20deactivate%20Registry%0A%20%20%0A%20%20Router-%3ERegistry%3A%20%3Ccolor%3A%23white%3Epending_administrator%20%3D%20zero%20address%3C%2Fcolor%3E%0A%20%20activate%20Registry%20%238AA6F9%0A%20%20Registry--%3ERouter%3A%20%3Ccolor%3A%23white%3Esuccess%3C%2Fcolor%3E%0A%20%20deactivate%20Registry%0A%20%20%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%204)%20Emit%20AdministratorTransferred%20event%0A%20%20Router--%3EPendingAdmin%3A%20(success)%0Aelse%20Unauthorized%0A%20%20Router--%3EPendingAdmin%3A%20(error)%20Caller%20not%20pending%20admin%0Aend%0Adeactivate%20Router%0Adeactivate%20PendingAdminChainlink Router ProgramPending AdministratorRouterTokenAdminRegistry PDAAccepting the Administrator Role (accept_admin_role_token_admin_registry)accept_admin_role_token_admin_registry()1) Anchor enforces authority==token_admin_registry.pending_administrator2) Validate TokenAdminRegistry version & seeds3) Update TokenAdminRegistry PDAadministrator = pending_administratorsuccesspending_administrator = zero addresssuccess4) Emit AdministratorTransferred event(success)(error) Caller not pending adminalt[Authorized & Valid][Unauthorized] \ No newline at end of file diff --git a/public/images/ccip/cct/cct-svm-diagrams/solana_cct_flowchart.svg b/public/images/ccip/cct/cct-svm-diagrams/solana_cct_flowchart.svg new file mode 100644 index 00000000000..7f02afbe1ba --- /dev/null +++ b/public/images/ccip/cct/cct-svm-diagrams/solana_cct_flowchart.svg @@ -0,0 +1,102 @@ +

Yes - Direct control or governance multisig

No - Mint authority not accessible

SPL Token Multisig

Self-Serve Mode

Self-Deployed Standard

Custom Pools

Yes

No

Yes

No - LockRelease

Direct Transfer

SPL Token Multisig Setup

Self-Service Available

Manual Assistance Required

Decision Point

Start Integration

Do you control mint authority?

Self-Service Registration Available

Manual Registration Required

Choose Deployment Approach

Can sign as mint authority?

Deploy Standard Pool Program

Build & Deploy Custom Pool

Initialize Pool from Existing Programs

Request Assisted Pool Initialization

Initialize Pool from Your Program

Initialize Pool from Your Program

Create ATA for Pool Signer PDA

BurnMint Pool?

Choose Mint Authority Transfer

Create Address Lookup Table

Transfer mint authority to Pool Signer PDA

Create SPL M-of-N token multisig
with Pool Signer PDA appearing M times
for autonomous operation

Transfer mint authority to SPL token multisig

Call set_pool Instruction

Configure Pool Settings

Cross-Chain Transfers Enabled

\ No newline at end of file diff --git a/public/images/ccip/cct/cct-svm-diagrams/solana_owner_override_pending_administrator.svg b/public/images/ccip/cct/cct-svm-diagrams/solana_owner_override_pending_administrator.svg new file mode 100644 index 00000000000..a7c2303d9db --- /dev/null +++ b/public/images/ccip/cct/cct-svm-diagrams/solana_owner_override_pending_administrator.svg @@ -0,0 +1 @@ +title%20Override%20Pending%20Administrator%20(owner_override_pending_administrator)%0Aparticipant%20%22Token%20Mint%20Authority%22%20as%20MintAuth%0Aparticipantgroup%20%230847F7%20**%3Ccolor%3A%23white%3EChainlink%20Router%20Program%3C%2Fcolor%3E**%0A%20%20participant%20%22Router%22%20as%20Router%0A%20%20participant%20%22TokenAdminRegistry%20PDA%22%20as%20Registry%0Aend%0Aactivate%20MintAuth%20%230847F7%0AMintAuth-%3ERouter%3A%20owner_override_pending_administrator(new_pending_admin)%0Aactivate%20Router%20%238AA6F9%0Anote%20right%20of%20Router%20%23F8FAFF%3A%20(1)%20Anchor%20enforces%20authority%20%3D%3D%20mint.mint_authority%0Aalt%20Authorized%20%26%20Valid%20State%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%20(2)%20Validate%20administrator%20%3D%3D%20zero%20address%5Cn(no%20admin%20has%20been%20accepted%20yet)%0A%20%20Router-%3ERouter%3A%20%3Ccolor%3A%23white%3ECheck%20administrator%20empty%0A%20%20%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%20(3)%20Override%20pending%20administrator%0A%20%20Router-%3ERegistry%3A%20%3Ccolor%3A%23white%3Epending_administrator%20%3D%20new_pending_admin%3C%2Fcolor%3E%0A%20%20activate%20Registry%20%238AA6F9%0A%20%20note%20right%20of%20Registry%20%23F8FAFF%3A%20Previous%20pending%20admin%5Cncan%20no%20longer%20accept%20the%20role%0A%20%20Registry--%3ERouter%3A%20%3Ccolor%3A%23white%3Esuccess%3C%2Fcolor%3E%0A%20%20deactivate%20Registry%0A%20%20Router--%3EMintAuth%3A%20(success)%0Aelse%20Unauthorized%0A%20%20Router--%3EMintAuth%3A%20(error)%20Caller%20not%20mint%20authority%0Aelse%20Invalid%20State%0A%20%20Router--%3EMintAuth%3A%20(error)%20Administrator%20already%20accepted%0Aend%0Adeactivate%20Router%0Adeactivate%20MintAuthChainlink Router ProgramToken Mint AuthorityRouterTokenAdminRegistry PDAOverride Pending Administrator (owner_override_pending_administrator)owner_override_pending_administrator(new_pending_admin)(1) Anchor enforces authority == mint.mint_authority(2) Validate administrator == zero address(no admin has been accepted yet)Check administrator empty(3) Override pending administratorpending_administrator = new_pending_adminPrevious pending admincan no longer accept the rolesuccess(success)(error) Caller not mint authority(error) Administrator already acceptedalt[Authorized & Valid State][Unauthorized][Invalid State] \ No newline at end of file diff --git a/public/images/ccip/cct/cct-svm-diagrams/solana_owner_propose.svg b/public/images/ccip/cct/cct-svm-diagrams/solana_owner_propose.svg new file mode 100644 index 00000000000..ad070c310b2 --- /dev/null +++ b/public/images/ccip/cct/cct-svm-diagrams/solana_owner_propose.svg @@ -0,0 +1 @@ +title%20Self-Service%20Registration%3A%20Propose%20Administrator%20(owner_propose_administrator)%0Aparticipant%20%22Token%20Administrator%22%20as%20TA%0Aparticipantgroup%20%230847F7%20**%3Ccolor%3A%23white%3EChainlink%20Router%20Program%3C%2Fcolor%3E**%0A%20%20participant%20%22Router%22%20as%20Router%0A%20%20participant%20%22TokenAdminRegistry%20PDA%22%20as%20Registry%0Aend%0Aactivate%20TA%20%230847F7%0ATA-%3ERouter%3A%20owner_propose_administrator(token_admin_registry_admin)%0Aactivate%20Router%20%238AA6F9%0Anote%20right%20of%20Router%20%23F8FAFF%3A%201)%20Anchor%20enforces%5Cn%20authority%20%3D%3D%20mint.mint_authority%0Anote%20right%20of%20Router%20%23F8FAFF%3A%202)%20Validate%20new_admin%20!%3D%20zero%20address%0Aalt%20Authorized%20%26%20Valid%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%203)%20CREATE%20new%20TokenAdminRegistry%20PDA%0A%20%20Router-%3ERegistry%3A%20%3Ccolor%3A%23white%3Einitialize(version%3D2%2C%20administrator%3Dzero%2C%20pending_administrator%3DnewAdmin%2C%20mint%2C%20etc.)%3C%2Fcolor%3E%0A%20%20activate%20Registry%20%238AA6F9%0A%20%20Registry--%3ERouter%3A%20%3Ccolor%3A%23white%3Esuccess%3C%2Fcolor%3E%0A%20%20deactivate%20Registry%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%204)%20Emit%20AdministratorTransferRequested%20event%0A%20%20Router--%3ETA%3A%20(success)%0Aelse%20Unauthorized%20or%20Invalid%0A%20%20Router--%3ETA%3A%20(error)%20Unauthorized%20or%20Zero%20Address%0Aend%0Adeactivate%20Router%0Adeactivate%20TAChainlink Router ProgramToken AdministratorRouterTokenAdminRegistry PDASelf-Service Registration: Propose Administrator (owner_propose_administrator)owner_propose_administrator(token_admin_registry_admin)1) Anchor enforces authority == mint.mint_authority2) Validate new_admin != zero address3) CREATE new TokenAdminRegistry PDAinitialize(version=2, administrator=zero, pending_administrator=newAdmin, mint, etc.)success4) Emit AdministratorTransferRequested event(success)(error) Unauthorized or Zero Addressalt[Authorized & Valid][Unauthorized or Invalid] \ No newline at end of file diff --git a/public/images/ccip/cct/cct-svm-diagrams/solana_set_pool.svg b/public/images/ccip/cct/cct-svm-diagrams/solana_set_pool.svg new file mode 100644 index 00000000000..ebd93d8e792 --- /dev/null +++ b/public/images/ccip/cct/cct-svm-diagrams/solana_set_pool.svg @@ -0,0 +1 @@ +title%20set_pool%20Instruction%0Aparticipant%20%22Token%20Administrator%22%20as%20Admin%0Aparticipantgroup%20%230847F7%20**%3Ccolor%3A%23white%3EChainlink%20Router%20Program%3C%2Fcolor%3E**%0A%20%20participant%20%22Router%22%20as%20Router%0A%20%20participant%20%22TokenAdminRegistry%20PDA%22%20as%20Registry%0Aend%0Aactivate%20Admin%20%230847F7%0A%0AAdmin-%3ERouter%3A%20set_pool(writable_indexes)%0Aactivate%20Router%20%238AA6F9%0Anote%20right%20of%20Router%20%23F8FAFF%3A%20(1)%20Anchor%20enforces%20authority%20%3D%3D%20registry.administrator%0Aalt%20Authorized%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%20(2)%20Store%20new%20ALT%20address%20in%20registry%5CnReset%20old%20writable%20permissions%20%26%20apply%20new%20indexes%0A%20%20Router-%3ERegistry%3A%20%3Ccolor%3A%23white%3Eupdate%20lookup_table%20%26%20writable_indexes%3C%2Fcolor%3E%0A%20%20activate%20Registry%20%238AA6F9%0A%20%20Registry--%3ERouter%3A%20%3Ccolor%3A%23white%3Esuccess%3C%2Fcolor%3E%0A%20%20deactivate%20Registry%0A%20%20alt%20pool_lookuptable%20!%3D%20zero%20address%0A%20%20%20%20note%20right%20of%20Router%20%23F8FAFF%3A%20(3)%20Validate%20ALT%20has%20%E2%89%A59%20required%20accounts%5CnCheck%20token%20mint%20owner%20matches%20token%20program%5CnVerify%20all%20mandatory%20PDA%20addresses%20match%20expected%20values%0A%20%20%20%20Router-%3ERouter%3A%20%3Ccolor%3A%23white%3EValidate%20Look-Up%20Table%0A%20%20%20%20note%20right%20of%20Router%20%23F8FAFF%3A%20On%20success%2C%20token%20is%20enabled%20for%20CCIP%0A%20%20else%20Zero%20address%0A%20%20%20%20note%20right%20of%20Router%20%23F8FAFF%3A%20Delist%20this%20token%20from%20CCIP%0A%20%20end%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%20(4)%20Emit%20PoolSet%20event%0A%20%20Router--%3EAdmin%3A%20(success)%0Aelse%20Unauthorized%0A%20%20Router--%3EAdmin%3A%20(error)%20Caller%20not%20current%20token%20admin%0Aend%0Adeactivate%20Router%0Adeactivate%20AdminChainlink Router ProgramToken AdministratorRouterTokenAdminRegistry PDAset_pool Instructionset_pool(writable_indexes)(1) Anchor enforces authority == registry.administrator(2) Store new ALT address in registryReset old writable permissions & apply new indexesupdate lookup_table & writable_indexessuccess(3) Validate ALT has ≥9 required accountsCheck token mint owner matches token programVerify all mandatory PDA addresses match expected valuesValidate Look-Up TableOn success, token is enabled for CCIPDelist this token from CCIP(4) Emit PoolSet event(success)(error) Caller not current token adminalt[Authorized][Unauthorized]alt[pool_lookuptable != zero address][Zero address] \ No newline at end of file diff --git a/public/images/ccip/cct/cct-svm-diagrams/solana_set_pool_supports_auto_derivation.svg b/public/images/ccip/cct/cct-svm-diagrams/solana_set_pool_supports_auto_derivation.svg new file mode 100644 index 00000000000..6b7f107a444 --- /dev/null +++ b/public/images/ccip/cct/cct-svm-diagrams/solana_set_pool_supports_auto_derivation.svg @@ -0,0 +1 @@ +title%20set_pool_supports_auto_derivation%20Instruction%0Aparticipant%20%22Token%20Administrator%22%20as%20Admin%0Aparticipantgroup%20%230847F7%20**%3Ccolor%3A%23white%3EChainlink%20Router%20Program%3C%2Fcolor%3E**%0A%20%20participant%20%22Router%22%20as%20Router%0A%20%20participant%20%22TokenAdminRegistry%20PDA%22%20as%20Registry%0Aend%0Aactivate%20Admin%20%230847F7%0AAdmin-%3ERouter%3A%20set_pool_supports_auto_derivation(mint%2C%20supports_auto_derivation)%0Aactivate%20Router%20%238AA6F9%0Anote%20right%20of%20Router%20%23F8FAFF%3A%20(1)%20Anchor%20enforces%20authority%20%3D%3D%20registry.administrator%0Aalt%20Authorized%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%20(2)%20Update%20auto-derivation%20support%20flag%0A%20%20Router-%3ERegistry%3A%20%3Ccolor%3A%23white%3Esupports_auto_derivation%20%3D%20new_value%3C%2Fcolor%3E%0A%20%20activate%20Registry%20%238AA6F9%0A%20%20note%20right%20of%20Registry%20%23F8FAFF%3A%20Flag%20determines%20how%20account%5Cnvalidation%20works%20during%20transfers%0A%20%20Registry--%3ERouter%3A%20%3Ccolor%3A%23white%3Esuccess%3C%2Fcolor%3E%0A%20%20deactivate%20Registry%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%20(3)%20Emit%20PoolEdited%20event%0A%20%20Router--%3EAdmin%3A%20(success)%0Aelse%20Unauthorized%0A%20%20Router--%3EAdmin%3A%20(error)%20Caller%20not%20current%20token%20admin%0Aend%0Adeactivate%20Router%0Adeactivate%20AdminChainlink Router ProgramToken AdministratorRouterTokenAdminRegistry PDAset_pool_supports_auto_derivation Instructionset_pool_supports_auto_derivation(mint, supports_auto_derivation)(1) Anchor enforces authority == registry.administrator(2) Update auto-derivation support flagsupports_auto_derivation = new_valueFlag determines how accountvalidation works during transferssuccess(3) Emit PoolEdited event(success)(error) Caller not current token adminalt[Authorized][Unauthorized] \ No newline at end of file diff --git a/public/images/ccip/cct/cct-svm-diagrams/solana_transfer_admin_role.svg b/public/images/ccip/cct/cct-svm-diagrams/solana_transfer_admin_role.svg new file mode 100644 index 00000000000..6c4ba11620b --- /dev/null +++ b/public/images/ccip/cct/cct-svm-diagrams/solana_transfer_admin_role.svg @@ -0,0 +1 @@ +title%20Transfer%20Administrator%20Role%20(transfer_admin_role_token_admin_registry)%0Aparticipant%20%22Current%20Administrator%22%20as%20CurrAdmin%0Aparticipantgroup%20%230847F7%20**%3Ccolor%3A%23white%3EChainlink%20Router%20Program%3C%2Fcolor%3E**%0A%20%20participant%20%22Router%22%20as%20Router%0A%20%20participant%20%22TokenAdminRegistry%20PDA%22%20as%20Registry%0Aend%0Aparticipant%20%22Proposed%20Administrator%22%20as%20PropAdmin%0Aactivate%20CurrAdmin%20%230847F7%0ACurrAdmin-%3ERouter%3A%20transfer_admin_role_token_admin_registry(newAdmin)%0Aactivate%20Router%20%238AA6F9%0Anote%20right%20of%20Router%20%23F8FAFF%3A%201)%20Anchor%20enforces%20caller%20%3D%3D%20registry.administrator%0Aalt%20Authorized%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%202)%20Update%20pending_administrator%20%3D%20newAdmin%0A%20%20Router-%3ERegistry%3A%20%3Ccolor%3A%23white%3Epending_administrator%20%3D%20newAdmin%3C%2Fcolor%3E%0A%20%20activate%20Registry%20%238AA6F9%0A%20%20note%20right%20of%20Registry%20%23F8FAFF%3A%20administrator%20unchanged%2C%5Cnpending_admin%20%3D%20newAdmin%0A%20%20Registry--%3ERouter%3A%20%3Ccolor%3A%23white%3Esuccess%3C%2Fcolor%3E%0A%20%20deactivate%20Registry%0A%20%20%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%203)%20Emit%20AdministratorTransferRequested%20event%0A%20%20Router--%3ECurrAdmin%3A%20(success)%0Aelse%20Unauthorized%0A%20%20Router--%3ECurrAdmin%3A%20(error)%20Caller%20not%20current%20admin%0Aend%0Adeactivate%20Router%0Adeactivate%20CurrAdmin%0Aactivate%20PropAdmin%20%230847F7%0APropAdmin-%3ERouter%3A%20%3Ccolor%3A%23white%3Eaccept_admin_role_token_admin_registry()%0Aactivate%20Router%20%238AA6F9%0Anote%20right%20of%20Router%20%23F8FAFF%3A%204)%20Anchor%20enforces%20caller%20%3D%3D%20pending_administrator%0Aalt%20Authorized%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%205)%20Finalize%20admin%20transfer%0A%20%20Router-%3ERegistry%3A%20%3Ccolor%3A%23white%3Eadministrator%20%3D%20pending_administrator%3C%2Fcolor%3E%0A%20%20activate%20Registry%20%238AA6F9%0A%20%20Registry--%3ERouter%3A%20%3Ccolor%3A%23white%3Esuccess%3C%2Fcolor%3E%0A%20%20deactivate%20Registry%0A%20%20%0A%20%20Router-%3ERegistry%3A%20%3Ccolor%3A%23white%3Epending_administrator%20%3D%20zero%20address%3C%2Fcolor%3E%0A%20%20activate%20Registry%20%238AA6F9%0A%20%20Registry--%3ERouter%3A%20%3Ccolor%3A%23white%3Esuccess%3C%2Fcolor%3E%0A%20%20deactivate%20Registry%0A%20%20%0A%20%20note%20right%20of%20Router%20%23F8FAFF%3A%206)%20Emit%20AdministratorTransferred%20event%0A%20%20Router--%3EPropAdmin%3A%20%3Ccolor%3A%23white%3E(success)%0Aelse%20Unauthorized%0A%20%20Router--%3EPropAdmin%3A%20%3Ccolor%3A%23white%3E(error)%20Caller%20not%20pending%20admin%0Aend%0Adeactivate%20Router%0Adeactivate%20PropAdminChainlink Router ProgramCurrent AdministratorRouterTokenAdminRegistry PDAProposed AdministratorTransfer Administrator Role (transfer_admin_role_token_admin_registry)transfer_admin_role_token_admin_registry(newAdmin)1) Anchor enforces caller == registry.administrator2) Update pending_administrator = newAdminpending_administrator = newAdminadministrator unchanged,pending_admin = newAdminsuccess3) Emit AdministratorTransferRequested event(success)(error) Caller not current adminaccept_admin_role_token_admin_registry()4) Anchor enforces caller == pending_administrator5) Finalize admin transferadministrator = pending_administratorsuccesspending_administrator = zero addresssuccess6) Emit AdministratorTransferred event(success)(error) Caller not pending adminalt[Authorized][Unauthorized]alt[Authorized][Unauthorized] \ No newline at end of file diff --git a/src/config/sidebar.ts b/src/config/sidebar.ts index 21e36a9715e..e5e9a033a89 100644 --- a/src/config/sidebar.ts +++ b/src/config/sidebar.ts @@ -8,7 +8,7 @@ import { SIDEBAR_SECTIONS } from "./sidebarSections.ts" import evmCcipV150Contents from "./sidebar/ccip/api-reference/evm/v1_5_0.json" with { type: "json" } import evmCcipV151Contents from "./sidebar/ccip/api-reference/evm/v1_5_1.json" with { type: "json" } import evmCcipV160Contents from "./sidebar/ccip/api-reference/evm/v1_6_0.json" with { type: "json" } -import svmCcipV160Contents from "./sidebar/ccip/api-reference/svm/v1_6_0.json" with { type: "json" } +import svmCcipV011Contents from "./sidebar/ccip/api-reference/svm/v0_1_1.json" with { type: "json" } import chainlinkLocalV021Contents from "./sidebar/chainlink-local/api-reference/v0_2_1.json" with { type: "json" } import chainlinkLocalV022Contents from "./sidebar/chainlink-local/api-reference/v0_2_2.json" with { type: "json" } import chainlinkLocalV023Contents from "./sidebar/chainlink-local/api-reference/v0_2_3.json" with { type: "json" } @@ -1244,6 +1244,10 @@ export const SIDEBAR: Partial> = { title: "SVM", url: "ccip/concepts/cross-chain-token/svm", children: [ + { + title: "Architecture", + url: "ccip/concepts/cross-chain-token/svm/architecture", + }, { title: "Tokens", url: "ccip/concepts/cross-chain-token/svm/tokens", @@ -1253,8 +1257,8 @@ export const SIDEBAR: Partial> = { url: "ccip/concepts/cross-chain-token/svm/token-pools", }, { - title: "Architecture", - url: "ccip/concepts/cross-chain-token/svm/architecture", + title: "Integration Guide", + url: "ccip/concepts/cross-chain-token/svm/integration-guide", }, { title: "Registration and Administration", @@ -1502,10 +1506,10 @@ export const SIDEBAR: Partial> = { url: "ccip/api-reference/svm", children: [ { - title: "v1.6.0 (Latest)", - url: "ccip/api-reference/svm/v1.6.0", + title: "v0.1.1 (Latest)", + url: "ccip/api-reference/svm/v0.1.1", isCollapsible: true, - children: svmCcipV160Contents, + children: svmCcipV011Contents, }, ], }, diff --git a/src/config/sidebar/ccip/api-reference/svm/v0_1_1.json b/src/config/sidebar/ccip/api-reference/svm/v0_1_1.json new file mode 100644 index 00000000000..f87184d2647 --- /dev/null +++ b/src/config/sidebar/ccip/api-reference/svm/v0_1_1.json @@ -0,0 +1,34 @@ +[ + { + "title": "Messages", + "url": "ccip/api-reference/svm/v0.1.1/messages" + }, + { + "title": "Router", + "url": "ccip/api-reference/svm/v0.1.1/router" + }, + { + "title": "Receiver", + "url": "ccip/api-reference/svm/v0.1.1/receiver" + }, + { + "title": "Base Token Pool Library", + "url": "ccip/api-reference/svm/v0.1.1/base-token-pool" + }, + { + "title": "BurnMint Token Pool", + "url": "ccip/api-reference/svm/v0.1.1/burn-mint-token-pool" + }, + { + "title": "Lock-Release Token Pool", + "url": "ccip/api-reference/svm/v0.1.1/lock-release-token-pool" + }, + { + "title": "Errors", + "url": "ccip/api-reference/svm/v0.1.1/errors" + }, + { + "title": "Events", + "url": "ccip/api-reference/svm/v0.1.1/events" + } +] diff --git a/src/config/sidebar/ccip/api-reference/svm/v1_6_0.json b/src/config/sidebar/ccip/api-reference/svm/v1_6_0.json deleted file mode 100644 index 48fc78032c7..00000000000 --- a/src/config/sidebar/ccip/api-reference/svm/v1_6_0.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "title": "Messages", - "url": "ccip/api-reference/svm/v1.6.0/messages" - }, - { - "title": "Router", - "url": "ccip/api-reference/svm/v1.6.0/router" - }, - { - "title": "Receiver", - "url": "ccip/api-reference/svm/v1.6.0/receiver" - }, - { - "title": "Errors", - "url": "ccip/api-reference/svm/v1.6.0/errors" - }, - { - "title": "Events", - "url": "ccip/api-reference/svm/v1.6.0/events" - } -] diff --git a/src/config/versions/index.ts b/src/config/versions/index.ts index dbf208ec2a5..e9d3a227dbe 100644 --- a/src/config/versions/index.ts +++ b/src/config/versions/index.ts @@ -31,10 +31,10 @@ export const VERSIONS = { }, }, svm: { - LATEST: "v1.6.0", - ALL: ["v1.6.0"] as const, + LATEST: "v0.1.1", + ALL: ["v0.1.1"] as const, RELEASE_DATES: { - "v1.6.0": "2025-05-19T00:00:00Z", // 19 May 2025 + "v0.1.1": "2023-10-04T00:00:00Z", // Placeholder release date – update when known }, }, // Default for backward compatibility diff --git a/src/content/ccip/api-reference/svm/v0.1.1/base-token-pool.mdx b/src/content/ccip/api-reference/svm/v0.1.1/base-token-pool.mdx new file mode 100644 index 00000000000..7ff5774dff8 --- /dev/null +++ b/src/content/ccip/api-reference/svm/v0.1.1/base-token-pool.mdx @@ -0,0 +1,457 @@ +--- +section: ccip +date: Last Modified +title: "CCIP v0.1.1 SVM Base Token Pool Library Reference" +metadata: + description: "Complete API documentation for the Base Token Pool library that provides shared functionality and common components for CCIP token pool implementations on SVM-based blockchains like Solana. Covers data structures, rate limiting, validation functions, and core utilities for token pool development." + excerpt: "Base Token Pool, SVM token pool library, Solana token pools, shared token pool functionality, rate limiting, token pool validation, cross-chain token transfers, token pool development, anchor library" +--- + +import { Aside } from "@components" +import CcipCommon from "@features/ccip/CcipCommon.astro" + +## Base Token Pool Library + +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs/base-token-pool) + +The Base Token Pool library provides foundational components and shared functionality for CCIP token pool implementations on SVM-based blockchains. This library is not deployable as a standalone program but serves as a dependency for concrete token pool implementations like BurnMint and Lock-Release pools. + + + +### Core Components + +The Base Token Pool library provides several key modules: + +#### Common Module (`common.rs`) + +Contains shared data structures, constants, validation functions, and events used across all token pool implementations. + +#### Rate Limiter Module (`rate_limiter.rs`) + +Implements token bucket rate limiting functionality to control cross-chain transfer rates. + +### Data Structures + +#### Core Configuration Structures + +##### `BaseConfig` + +The fundamental configuration structure used by all token pools. + +```rust +pub struct BaseConfig { + // Token configuration + pub token_program: Pubkey, // SPL Token or Token-2022 program ID + pub mint: Pubkey, // Token mint address + pub decimals: u8, // Token decimals + pub pool_signer: Pubkey, // Pool signer PDA + pub pool_token_account: Pubkey, // Pool's associated token account + + // Ownership and administration + pub owner: Pubkey, // Current pool owner + pub proposed_owner: Pubkey, // Proposed new owner (for ownership transfer) + pub rate_limit_admin: Pubkey, // Rate limit administrator (currently unused - rate limits managed by pool owner) + + // CCIP integration + pub router_onramp_authority: Pubkey, // Router's onramp authority PDA + pub router: Pubkey, // CCIP Router program address + pub rmn_remote: Pubkey, // RMN Remote program address + + // Lock-Release specific (unused in BurnMint pools) + pub rebalancer: Pubkey, // Rebalancer address for liquidity management + pub can_accept_liquidity: bool, // Whether pool accepts liquidity operations + + // Access control + pub list_enabled: bool, // Whether allowlist is enabled + pub allow_list: Vec, // Allowlisted addresses for pool operations +} +``` + +**Key Methods:** + +- `init()`: Initializes BaseConfig with default values +- `transfer_ownership()`: Proposes ownership transfer +- `accept_ownership()`: Accepts proposed ownership transfer +- `set_router()`: Updates router address and derives new onramp authority +- `set_rmn()`: Updates RMN remote address +- `set_rebalancer()`: Sets rebalancer address (Lock-Release pools only) +- `set_can_accept_liquidity()`: Enables/disables liquidity operations + +##### `BaseChain` + +Configuration for a specific remote chain destination. + +```rust +pub struct BaseChain { + pub remote: RemoteConfig, // Remote chain token and pool configuration + pub inbound_rate_limit: RateLimitTokenBucket, // Rate limiting for incoming transfers + pub outbound_rate_limit: RateLimitTokenBucket, // Rate limiting for outgoing transfers +} +``` + +**Key Methods:** + +- `set()`: Updates remote chain configuration +- `append_remote_pool_addresses()`: Adds remote pool addresses +- `set_chain_rate_limit()`: Configures rate limits for the chain + +##### `RemoteConfig` + +Configuration for tokens and pools on remote chains. + +```rust +pub struct RemoteConfig { + pub pool_addresses: Vec, // Remote pool addresses (supports multiple versions) + pub token_address: RemoteAddress, // Remote token address + pub decimals: u8, // Remote token decimals +} +``` + +##### `RemoteAddress` + +Represents an address on a remote chain (supports various address formats). + +```rust +pub struct RemoteAddress { + pub address: Vec, // Address bytes (max 64 bytes) +} +``` + +#### Cross-Chain Transfer Structures + +##### `LockOrBurnInV1` + +Input parameters for locking or burning tokens (source chain operation). + +```rust +pub struct LockOrBurnInV1 { + pub receiver: Vec, // Recipient address on destination chain + pub remote_chain_selector: u64, // Destination chain ID + pub original_sender: Pubkey, // Original transaction sender + pub amount: u64, // Amount to lock/burn (local decimals) + pub local_token: Pubkey, // Local token mint address + pub msg_total_nonce: u64, // Message nonce from onramp +} +``` + +##### `LockOrBurnOutV1` + +Output from lock or burn operations. + +```rust +pub struct LockOrBurnOutV1 { + pub dest_token_address: RemoteAddress, // Remote token address + pub dest_pool_data: Vec, // ABI-encoded local token decimals +} +``` + +##### `ReleaseOrMintInV1` + +Input parameters for releasing or minting tokens (destination chain operation). + +```rust +pub struct ReleaseOrMintInV1 { + pub original_sender: RemoteAddress, // Original sender on source chain + pub remote_chain_selector: u64, // Source chain ID + pub receiver: Pubkey, // Token recipient on this chain + pub amount: [u8; 32], // Amount in source decimals (u256) + pub local_token: Pubkey, // Local token mint address + pub source_pool_address: RemoteAddress, // Source pool address (must be validated) + pub source_pool_data: Vec, // Data from source pool + pub offchain_token_data: Vec, // Untrusted offchain data +} +``` + +##### `ReleaseOrMintOutV1` + +Output from release or mint operations. + +```rust +pub struct ReleaseOrMintOutV1 { + pub destination_amount: u64, // Amount released/minted (local decimals) +} +``` + +### Rate Limiting + +The library provides comprehensive rate limiting functionality using a token bucket algorithm. + +#### `RateLimitTokenBucket` + +Implements rate limiting for cross-chain transfers. + +```rust +pub struct RateLimitTokenBucket { + pub tokens: u64, // Current tokens in bucket + pub last_updated: u64, // Last refill timestamp + cfg: RateLimitConfig, // Rate limit configuration +} +``` + +**Key Methods:** + +- `consume()`: Attempts to consume tokens from bucket +- `set_token_bucket_config()`: Updates rate limit configuration + +#### `RateLimitConfig` + +Configuration for rate limiting behavior. + +```rust +pub struct RateLimitConfig { + pub enabled: bool, // Whether rate limiting is enabled + pub capacity: u64, // Maximum tokens in bucket + pub rate: u64, // Tokens per second refill rate +} +``` + +**Validation Rules:** + +- When enabled: `rate < capacity` and `rate != 0` +- When disabled: `rate == 0` and `capacity == 0` + +### Constants and Seeds + +The library defines critical constants used for PDA derivation across all pool implementations: + +```rust +// PDA Seeds +pub const POOL_CHAINCONFIG_SEED: &[u8] = b"ccip_tokenpool_chainconfig"; +pub const POOL_STATE_SEED: &[u8] = b"ccip_tokenpool_config"; +pub const POOL_SIGNER_SEED: &[u8] = b"ccip_tokenpool_signer"; +pub const CONFIG_SEED: &[u8] = b"config"; + +// Router Integration +pub const EXTERNAL_TOKEN_POOLS_SIGNER: &[u8] = b"external_token_pools_signer"; +pub const ALLOWED_OFFRAMP: &[u8] = b"allowed_offramp"; + +// Other Constants +pub const ANCHOR_DISCRIMINATOR: usize = 8; +``` + + + +### Validation Functions + +The library provides critical validation functions that ensure security and correctness of cross-chain operations. + +#### `validate_lock_or_burn` + +Validates parameters for locking or burning tokens on the source chain. + +```rust +pub fn validate_lock_or_burn<'info>( + lock_or_burn_in: &LockOrBurnInV1, + config_mint: Pubkey, + outbound_rate_limit: &mut RateLimitTokenBucket, + allow_list_enabled: bool, + allow_list: &[Pubkey], + rmn_remote: AccountInfo<'info>, + rmn_remote_curses: AccountInfo<'info>, + rmn_remote_config: AccountInfo<'info>, +) -> Result<()> +``` + +**Validation Checks:** + +1. **Token Validation**: Ensures `local_token` matches the pool's configured mint +2. **Allowlist Check**: Validates `original_sender` is allowlisted (if enabled) +3. **Curse Check**: Verifies destination chain is not cursed via RMN Remote CPI +4. **Rate Limiting**: Consumes tokens from outbound rate limit bucket + +#### `validate_release_or_mint` + +Validates parameters for releasing or minting tokens on the destination chain. + +```rust +pub fn validate_release_or_mint<'info>( + release_or_mint_in: &ReleaseOrMintInV1, + parsed_amount: u64, + config_mint: Pubkey, + pool_addresses: &[RemoteAddress], + inbound_rate_limit: &mut RateLimitTokenBucket, + rmn_remote: AccountInfo<'info>, + rmn_remote_curses: AccountInfo<'info>, + rmn_remote_config: AccountInfo<'info>, +) -> Result<()> +``` + +**Validation Checks:** + +1. **Token Validation**: Ensures `local_token` matches the pool's configured mint +1. **Source Pool Validation**: Verifies `source_pool_address` is in the configured pool addresses list +1. **Curse Check**: Verifies source chain is not cursed via RMN Remote CPI +1. **Rate Limiting**: Consumes tokens from inbound rate limit bucket + +#### `verify_uncursed_cpi` + +Performs CPI to RMN Remote to verify a chain is not cursed. + +```rust +pub fn verify_uncursed_cpi<'info>( + rmn_remote: AccountInfo<'info>, + rmn_remote_config: AccountInfo<'info>, + rmn_remote_curses: AccountInfo<'info>, + chain_selector: u64, +) -> Result<()> +``` + +### Utility Functions + +#### `to_svm_token_amount` + +Converts cross-chain token amounts to local SVM amounts, handling decimal differences. + +```rust +pub fn to_svm_token_amount( + incoming_amount_bytes: [u8; 32], // LE encoded u256 from source chain + incoming_decimal: u8, // Source token decimals + local_decimal: u8, // Local token decimals +) -> Result +``` + +**Conversion Logic:** + +- **More incoming decimals**: Divides by `10^(incoming_decimal - local_decimal)` +- **Fewer incoming decimals**: Multiplies by `10^(local_decimal - incoming_decimal)` +- **Equal decimals**: No conversion needed +- **Overflow protection**: Validates result fits in u64 + +### Account Meta Utilities + +#### `CcipAccountMeta` + +Serializable version of Solana's `AccountMeta` for cross-program communication. + +```rust +pub struct CcipAccountMeta { + pub pubkey: Pubkey, + pub is_signer: bool, + pub is_writable: bool, +} +``` + +#### `ToMeta` Trait + +Provides convenient methods for creating `CcipAccountMeta` instances. + +```rust +pub trait ToMeta { + fn readonly(self) -> CcipAccountMeta; + fn writable(self) -> CcipAccountMeta; + fn signer(self) -> CcipAccountMeta; +} +``` + +### Error Types + +The library defines comprehensive error types used across all pool implementations: + +```rust +pub enum CcipTokenPoolError { + // Authorization errors + InvalidInitPoolPermissions, + Unauthorized, + InvalidPoolCaller, + + // Configuration errors + InvalidInputs, + InvalidVersion, + InvalidRMNRemoteAddress, + + // Token operation errors + InvalidSender, + InvalidSourcePoolAddress, + InvalidToken, + InvalidTokenAmountConversion, + + // Allowlist errors + AllowlistKeyAlreadyExisted, + AllowlistKeyDidNotExist, + + // Remote pool errors + RemotePoolAddressAlreadyExisted, + NonemptyPoolAddressesInit, + + // Rate limiting errors (RL prefix) + RLBucketOverfilled, + RLMaxCapacityExceeded, + RLRateLimitReached, + RLInvalidRateLimitRate, + RLDisabledNonZeroRateLimit, + + // Lock-Release specific errors + LiquidityNotAccepted, + TransferZeroTokensNotAllowed, + + // Other + InvalidDerivationStage, +} +``` + +### Events + +The library defines events that are emitted by pool implementations. See the [Events API Reference](/ccip/api-reference/svm/v0.1.1/events) for detailed documentation of all events including: + +- Configuration events (`GlobalConfigUpdated`, `RemoteChainConfigured`, etc.) +- Token operation events (`Burned`, `Minted`, `Locked`, `Released`) +- Administrative events (`OwnershipTransferred`, `RouterUpdated`, etc.) +- Rate limiting events (`TokensConsumed`, `ConfigChanged`) + +### Usage by Pool Implementations + +The Base Token Pool library is used by concrete pool implementations as follows: + +#### Import Pattern + +```rust +use base_token_pool::{ + common::*, + rate_limiter::*, +}; +``` + +#### Structure Embedding + +Pool implementations embed base structures: + +```rust +#[account] +#[derive(InitSpace)] +pub struct State { + pub version: u8, + pub config: BaseConfig, // Embedded base configuration +} + +#[account] +#[derive(InitSpace)] +pub struct ChainConfig { + pub base: BaseChain, // Embedded base chain configuration +} +``` + +#### Validation Integration + +Pool operations call base validation functions: + +```rust +// In lock_or_burn_tokens instruction +validate_lock_or_burn( + &lock_or_burn, + ctx.accounts.state.config.mint, + &mut ctx.accounts.chain_config.base.outbound_rate_limit, + ctx.accounts.state.config.list_enabled, + &ctx.accounts.state.config.allow_list, + ctx.accounts.rmn_remote.to_account_info(), + ctx.accounts.rmn_remote_curses.to_account_info(), + ctx.accounts.rmn_remote_config.to_account_info(), +)?; +``` + +This shared foundation ensures consistency, security, and maintainability across all CCIP token pool implementations on SVM-based blockchains. diff --git a/src/content/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool.mdx b/src/content/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool.mdx new file mode 100644 index 00000000000..3c866177379 --- /dev/null +++ b/src/content/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool.mdx @@ -0,0 +1,677 @@ +--- +section: ccip +date: Last Modified +title: "CCIP v0.1.1 SVM BurnMint Token Pool API Reference" +metadata: + description: "Comprehensive API documentation for the CCIP BurnMint Token Pool program on SVM-based blockchains like Solana. Complete guide covering burn and mint operations, token pool configuration, cross-chain token transfers, multisig management, and access control for seamless interoperability." + excerpt: "BurnMint Token Pool, SVM burn mint pool, Solana token pool, cross-chain token transfers, burn and mint operations, token pool configuration, multisig management, access control, CCIP token pools" +--- + +import { Aside, ClickToZoom } from "@components" +import CcipCommon from "@features/ccip/CcipCommon.astro" + +## BurnMint Token Pool + +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs/burnmint-token-pool) + +Below is a complete API reference for the CCIP BurnMint Token Pool program instructions. This pool implementation burns tokens on the source chain and mints them on the destination chain. + +### Global Configuration + +These instructions manage the global configuration of the BurnMint Token Pool program. + +#### `init_global_config` + +Initializes the global configuration for the BurnMint Token Pool program. This must be called once during initial setup. + +```rust +fn init_global_config( + ctx: Context, + router_address: Pubkey, + rmn_address: Pubkey, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ---------------- | -------- | --------------------------------------- | +| `router_address` | `Pubkey` | The default CCIP Router program address | +| `rmn_address` | `Pubkey` | The default RMN Remote program address | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ---------------- | ----------------------------------- | --------- | ------------------------------------------------------------------------------------------- | +| `config` | `Account` | Yes | Global pool config PDA to initialize.
**Derivation**: `["config"]` under this program. | +| `authority` | `Signer<'info>` | Yes | Must be the program upgrade authority. | +| `system_program` | `Program<'info, System>` | No | Standard System Program. | +| `program` | `Program<'info, BurnmintTokenPool>` | No | The BurnMint Token Pool program. | +| `program_data` | `Account<'info, ProgramData>` | No | Program data account for upgrade authority verification. | + +##### Authorization + +- **Caller**: Must be the program upgrade authority + +#### `update_self_served_allowed` + +Updates whether self-service pool initialization is allowed. + +```rust +fn update_self_served_allowed( + ctx: Context, + self_served_allowed: bool, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| --------------------- | ------ | ------------------------------------------------------- | +| `self_served_allowed` | `bool` | Whether mint authorities can initialize their own pools | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| -------------- | ----------------------------------- | --------- | ----------------------------------------------------------------------------- | +| `config` | `Account` | Yes | Global pool config PDA.
**Derivation**: `["config"]` under this program. | +| `authority` | `Signer<'info>` | No | Must be the program upgrade authority. | +| `program` | `Program<'info, BurnmintTokenPool>` | No | The BurnMint Token Pool program. | +| `program_data` | `Account<'info, ProgramData>` | No | Program data account for upgrade authority verification. | + +##### Authorization + +- **Caller**: Must be the program upgrade authority + +#### `update_default_router` + +Updates the default router address used for new token pools. + +```rust +fn update_default_router( + ctx: Context, + router_address: Pubkey, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ---------------- | -------- | ------------------------------------------- | +| `router_address` | `Pubkey` | The new default CCIP Router program address | + +##### Context (Accounts) + +Same as `update_self_served_allowed`. + +##### Authorization + +- **Caller**: Must be the program upgrade authority + +#### `update_default_rmn` + +Updates the default RMN Remote address used for new token pools. + +```rust +fn update_default_rmn( + ctx: Context, + rmn_address: Pubkey, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ------------- | -------- | ------------------------------------------ | +| `rmn_address` | `Pubkey` | The new default RMN Remote program address | + +##### Context (Accounts) + +Same as `update_self_served_allowed`. + +##### Authorization + +- **Caller**: Must be the program upgrade authority + +### Pool Initialization & Management + +These instructions handle individual token pool lifecycle management. + +#### `initialize` + +Initializes a new token pool for a specific SPL token mint. + +```rust +fn initialize(ctx: Context) -> Result<()>; +``` + +##### Parameters + +This instruction takes no additional parameters. + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ---------------- | ----------------------------------- | --------- | -------------------------------------------------------------------------------------------------------- | +| `state` | `Account` | Yes | Pool state PDA to initialize.
**Derivation**: `["ccip_tokenpool_config", mint]` under this program. | +| `mint` | `InterfaceAccount<'info, Mint>` | No | The SPL token mint to create a pool for. | +| `authority` | `Signer<'info>` | Yes | Pool initializer (see Authorization below). | +| `system_program` | `Program<'info, System>` | No | Standard System Program. | +| `program` | `Program<'info, BurnmintTokenPool>` | No | The BurnMint Token Pool program. | +| `program_data` | `Account<'info, ProgramData>` | No | Program data account for upgrade authority verification. | +| `config` | `Account` | No | Global pool config PDA.
**Derivation**: `["config"]` under this program. | + +##### Authorization + +- **Program Upgrade Authority**: Can always initialize pools +- **Mint Authority**: Can initialize pools when `self_served_allowed` is true + +#### `transfer_mint_authority_to_multisig` + +Transfers the mint authority of the token to a multisig account that includes the pool signer as a required signer. + +```rust +fn transfer_mint_authority_to_multisig( + ctx: Context, +) -> Result<()>; +``` + +##### Parameters + +This instruction takes no additional parameters. + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ----------------------------- | ----------------------------------- | --------- | ------------------------------------------------------------------------------------------- | +| `state` | `Account` | Yes | Pool state PDA.
**Derivation**: `["ccip_tokenpool_config", mint]` under this program. | +| `mint` | `InterfaceAccount<'info, Mint>` | Yes | The SPL token mint. | +| `token_program` | `Interface<'info, TokenInterface>` | No | Token program (SPL Token or Token-2022). | +| `pool_signer` | `UncheckedAccount<'info>` | No | Pool signer PDA.
**Derivation**: `["ccip_tokenpool_signer", mint]` under this program. | +| `authority` | `Signer<'info>` | No | Must be the program upgrade authority. | +| `new_multisig_mint_authority` | `UncheckedAccount<'info>` | No | The new multisig account that will become the mint authority. | +| `program` | `Program<'info, BurnmintTokenPool>` | No | The BurnMint Token Pool program. | +| `program_data` | `Account<'info, ProgramData>` | No | Program data account for upgrade authority verification. | + +##### Authorization + +- **Caller**: Must be the program upgrade authority + +##### Multisig Requirements + +Must use SPL Token Multisig with Pool Signer PDA configured as a required signer. For detailed configuration requirements, validation rules, and examples, see [Mint Authority Management](/ccip/concepts/cross-chain-token/svm/token-pools#mint-authority-management). + +#### `transfer_ownership` + +Initiates transfer of pool ownership to a new owner. + +```rust +fn transfer_ownership( + ctx: Context, + proposed_owner: Pubkey, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ---------------- | -------- | ---------------------------------------- | +| `proposed_owner` | `Pubkey` | The public key of the proposed new owner | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ----------- | ------------------------------- | --------- | ------------------------------------------------------------------------------------------ | +| `state` | `Account` | Yes | Pool state PDA.
**Derivation**: `["ccip_tokenpool_config", mint]` under this program. | +| `mint` | `InterfaceAccount<'info, Mint>` | No | The SPL token mint. | +| `authority` | `Signer<'info>` | No | Must be the current pool owner. | + +##### Authorization + +- **Caller**: Must be the current pool owner + +#### `accept_ownership` + +Accepts pool ownership by the proposed owner. + +```rust +fn accept_ownership(ctx: Context) -> Result<()>; +``` + +##### Parameters + +This instruction takes no additional parameters. + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ----------- | ------------------------------- | --------- | ------------------------------------------------------------------------------------------ | +| `state` | `Account` | Yes | Pool state PDA.
**Derivation**: `["ccip_tokenpool_config", mint]` under this program. | +| `mint` | `InterfaceAccount<'info, Mint>` | No | The SPL token mint. | +| `authority` | `Signer<'info>` | No | Must be the proposed owner. | + +##### Authorization + +- **Caller**: Must be the proposed owner stored in the pool state + +#### `set_router` + +Updates the router address for an existing pool. + +```rust +fn set_router( + ctx: Context, + new_router: Pubkey, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ------------ | -------- | ----------------------------------- | +| `new_router` | `Pubkey` | The new CCIP Router program address | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| -------------- | ----------------------------------- | --------- | ------------------------------------------------------------------------------------------ | +| `state` | `Account` | No | Pool state PDA.
**Derivation**: `["ccip_tokenpool_config", mint]` under this program. | +| `mint` | `InterfaceAccount<'info, Mint>` | No | The SPL token mint. | +| `authority` | `Signer<'info>` | Yes | Must be program upgrade authority and pool owner. | +| `program` | `Program<'info, BurnmintTokenPool>` | No | The BurnMint Token Pool program. | +| `program_data` | `Account<'info, ProgramData>` | No | Program data account for upgrade authority verification. | + +##### Authorization + +- **Caller**: Must be the program upgrade authority AND the pool owner + +#### `set_rmn` + +Updates the RMN Remote address for an existing pool. + +```rust +fn set_rmn( + ctx: Context, + rmn_address: Pubkey, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ------------- | -------- | ---------------------------------- | +| `rmn_address` | `Pubkey` | The new RMN Remote program address | + +##### Context (Accounts) + +Same as `set_router`. + +##### Authorization + +- **Caller**: Must be the program upgrade authority AND the pool owner + +### Chain Configuration + +These instructions manage per-destination-chain configuration for token pools. + +#### `init_chain_remote_config` + +Initializes configuration for a specific remote destination chain. + +```rust +fn init_chain_remote_config( + ctx: Context, + remote_chain_selector: u64, + mint: Pubkey, + cfg: RemoteConfig, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ----------------------- | -------------- | ----------------------------------------------------------- | +| `remote_chain_selector` | `u64` | The destination chain selector | +| `mint` | `Pubkey` | The SPL token mint | +| `cfg` | `RemoteConfig` | Remote chain configuration (must have empty pool addresses) | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ---------------- | ------------------------ | --------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| `state` | `Account` | No | Pool state PDA.
**Derivation**: `["ccip_tokenpool_config", mint]` under this program. | +| `chain_config` | `Account` | Yes | Chain config PDA to initialize.
**Derivation**: `["ccip_tokenpool_chainconfig", remote_chain_selector, mint]` under this program. | +| `authority` | `Signer<'info>` | Yes | Must be the pool owner. | +| `system_program` | `Program<'info, System>` | No | Standard System Program. | + +##### Authorization + +- **Caller**: Must be the pool owner + +#### `edit_chain_remote_config` + +Updates configuration for an existing remote destination chain. + +```rust +fn edit_chain_remote_config( + ctx: Context, + remote_chain_selector: u64, + mint: Pubkey, + cfg: RemoteConfig, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ----------------------- | -------------- | ---------------------------------- | +| `remote_chain_selector` | `u64` | The destination chain selector | +| `mint` | `Pubkey` | The SPL token mint | +| `cfg` | `RemoteConfig` | Updated remote chain configuration | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ---------------- | ------------------------ | --------- | --------------------------------------------------------------------------------------------------------------------------------- | +| `state` | `Account` | No | Pool state PDA.
**Derivation**: `["ccip_tokenpool_config", mint]` under this program. | +| `chain_config` | `Account` | Yes | Existing chain config PDA.
**Derivation**: `["ccip_tokenpool_chainconfig", remote_chain_selector, mint]` under this program. | +| `authority` | `Signer<'info>` | Yes | Must be the pool owner. | +| `system_program` | `Program<'info, System>` | No | Standard System Program. | + +##### Authorization + +- **Caller**: Must be the pool owner + +#### `append_remote_pool_addresses` + +Adds additional remote pool addresses to an existing chain configuration. + +```rust +fn append_remote_pool_addresses( + ctx: Context, + remote_chain_selector: u64, + mint: Pubkey, + addresses: Vec, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ----------------------- | -------------------- | ------------------------------ | +| `remote_chain_selector` | `u64` | The destination chain selector | +| `mint` | `Pubkey` | The SPL token mint | +| `addresses` | `Vec` | Remote pool addresses to add | + +##### Context (Accounts) + +Same as `edit_chain_remote_config`. + +##### Authorization + +- **Caller**: Must be the pool owner + +#### `set_chain_rate_limit` + +Configures rate limits for inbound and outbound transfers to/from a specific chain. + +```rust +fn set_chain_rate_limit( + ctx: Context, + remote_chain_selector: u64, + mint: Pubkey, + inbound: RateLimitConfig, + outbound: RateLimitConfig, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ----------------------- | ----------------- | ----------------------------------------------- | +| `remote_chain_selector` | `u64` | The destination chain selector | +| `mint` | `Pubkey` | The SPL token mint | +| `inbound` | `RateLimitConfig` | Rate limit configuration for inbound transfers | +| `outbound` | `RateLimitConfig` | Rate limit configuration for outbound transfers | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| -------------- | ---------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------ | +| `state` | `Account` | No | Pool state PDA.
**Derivation**: `["ccip_tokenpool_config", mint]` under this program. | +| `chain_config` | `Account` | Yes | Chain config PDA.
**Derivation**: `["ccip_tokenpool_chainconfig", remote_chain_selector, mint]` under this program. | +| `authority` | `Signer<'info>` | Yes | Must be the pool owner. | + +##### Authorization + +- **Caller**: Must be the pool owner + +#### `delete_chain_config` + +Removes configuration for a specific remote destination chain. + +```rust +fn delete_chain_config( + ctx: Context, + remote_chain_selector: u64, + mint: Pubkey, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ----------------------- | -------- | ------------------------------ | +| `remote_chain_selector` | `u64` | The destination chain selector | +| `mint` | `Pubkey` | The SPL token mint | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| -------------- | ---------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `state` | `Account` | No | Pool state PDA.
**Derivation**: `["ccip_tokenpool_config", mint]` under this program. | +| `chain_config` | `Account` | Yes | Chain config PDA to delete.
**Derivation**: `["ccip_tokenpool_chainconfig", remote_chain_selector, mint]` under this program. | +| `authority` | `Signer<'info>` | Yes | Must be the pool owner. | + +##### Authorization + +- **Caller**: Must be the pool owner + +### Access Control + +These instructions manage allowlists for token transfers. + +#### `configure_allow_list` + +Configures the allowlist for the token pool, adding addresses and enabling/disabling the allowlist. + +```rust +fn configure_allow_list( + ctx: Context, + add: Vec, + enabled: bool, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| --------- | ------------- | --------------------------------- | +| `add` | `Vec` | Addresses to add to the allowlist | +| `enabled` | `bool` | Whether to enable the allowlist | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ---------------- | ------------------------------- | --------- | ------------------------------------------------------------------------------------------ | +| `state` | `Account` | Yes | Pool state PDA.
**Derivation**: `["ccip_tokenpool_config", mint]` under this program. | +| `mint` | `InterfaceAccount<'info, Mint>` | No | The SPL token mint. | +| `authority` | `Signer<'info>` | Yes | Must be the pool owner. | +| `system_program` | `Program<'info, System>` | No | Standard System Program. | + +##### Authorization + +- **Caller**: Must be the pool owner + +#### `remove_from_allow_list` + +Removes addresses from the allowlist. + +```rust +fn remove_from_allow_list( + ctx: Context, + remove: Vec, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| -------- | ------------- | -------------------------------------- | +| `remove` | `Vec` | Addresses to remove from the allowlist | + +##### Context (Accounts) + +Same as `configure_allow_list`. + +##### Authorization + +- **Caller**: Must be the pool owner + +### Cross-Chain Operations + +These instructions handle the core cross-chain token transfer operations. + +#### `lock_or_burn_tokens` + +Burns tokens on the source chain as part of a cross-chain transfer (OnRamp operation). + +```rust +fn lock_or_burn_tokens( + ctx: Context, + lock_or_burn: LockOrBurnInV1, +) -> Result; +``` + +##### Parameters + +| Name | Type | Description | +| -------------- | ---------------- | --------------------------------- | +| `lock_or_burn` | `LockOrBurnInV1` | Cross-chain transfer request data | + +##### Return Value + +| Type | Description | +| ----------------- | ------------------------------------------------ | +| `LockOrBurnOutV1` | Contains destination token address and pool data | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| -------------------- | --------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------ | +| `authority` | `Signer<'info>` | No | Must be the Router's onramp authority. | +| `state` | `Account` | No | Pool state PDA.
**Derivation**: `["ccip_tokenpool_config", mint]` under this program. | +| `token_program` | `Interface<'info, TokenInterface>` | No | Token program (SPL Token or Token-2022). | +| `mint` | `InterfaceAccount<'info, Mint>` | Yes | The SPL token mint. | +| `pool_signer` | `UncheckedAccount<'info>` | No | Pool signer PDA.
**Derivation**: `["ccip_tokenpool_signer", mint]` under this program. | +| `pool_token_account` | `InterfaceAccount<'info, TokenAccount>` | Yes | Pool's token account (ATA for pool_signer). | +| `rmn_remote` | `UncheckedAccount<'info>` | No | RMN Remote program address. | +| `rmn_remote_curses` | `UncheckedAccount<'info>` | No | RMN curses PDA. | +| `rmn_remote_config` | `UncheckedAccount<'info>` | No | RMN config PDA. | +| `chain_config` | `Account` | Yes | Chain config PDA.
**Derivation**: `["ccip_tokenpool_chainconfig", remote_chain_selector, mint]` under this program. | + +##### Authorization + +- **Caller**: Must be the Router's designated onramp authority + +#### `release_or_mint_tokens` + +Mints tokens on the destination chain as part of a cross-chain transfer (OffRamp operation). + +```rust +fn release_or_mint_tokens( + ctx: Context, + release_or_mint: ReleaseOrMintInV1, +) -> Result; +``` + +##### Parameters + +| Name | Type | Description | +| ----------------- | ------------------- | ------------------------------------ | +| `release_or_mint` | `ReleaseOrMintInV1` | Cross-chain transfer completion data | + +##### Return Value + +| Type | Description | +| -------------------- | -------------------------------------- | +| `ReleaseOrMintOutV1` | Contains the destination amount minted | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ------------------------ | --------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------ | +| `authority` | `Signer<'info>` | No | Offramp authority derived from external token pools signer. | +| `offramp_program` | `UncheckedAccount<'info>` | No | The offramp program for PDA derivation. | +| `allowed_offramp` | `UncheckedAccount<'info>` | No | Router's allowed offramp PDA. | +| `state` | `Account` | No | Pool state PDA.
**Derivation**: `["ccip_tokenpool_config", mint]` under this program. | +| `token_program` | `Interface<'info, TokenInterface>` | No | Token program (SPL Token or Token-2022). | +| `mint` | `InterfaceAccount<'info, Mint>` | Yes | The SPL token mint. | +| `pool_signer` | `UncheckedAccount<'info>` | No | Pool signer PDA.
**Derivation**: `["ccip_tokenpool_signer", mint]` under this program. | +| `pool_token_account` | `InterfaceAccount<'info, TokenAccount>` | Yes | Pool's token account (ATA for pool_signer). | +| `chain_config` | `Account` | Yes | Chain config PDA.
**Derivation**: `["ccip_tokenpool_chainconfig", remote_chain_selector, mint]` under this program. | +| `rmn_remote` | `UncheckedAccount<'info>` | No | RMN Remote program address. | +| `rmn_remote_curses` | `UncheckedAccount<'info>` | No | RMN curses PDA. | +| `rmn_remote_config` | `UncheckedAccount<'info>` | No | RMN config PDA. | +| `receiver_token_account` | `InterfaceAccount<'info, TokenAccount>` | Yes | Receiver's token account (ATA for the recipient). | + +##### Authorization + +- **Caller**: Must be an authorized offramp with valid Router approval + +### Utility Instructions + +#### `type_version` + +Returns the program type and version information. + +```rust +fn type_version(ctx: Context) -> Result; +``` + +##### Parameters + +This instruction takes no additional parameters. + +##### Return Value + +| Type | Description | +| -------- | ------------------------------------ | +| `String` | Program type and version information | + +#### `initialize_state_version` + +Permissionless instruction to initialize the state version for pools that were created before versioning was implemented. + +```rust +fn initialize_state_version( + ctx: Context, + mint: Pubkey, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ------ | -------- | ------------------ | +| `mint` | `Pubkey` | The SPL token mint | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ------- | ---------------- | --------- | --------------------------------------------------------------------------------------------------------------------- | +| `state` | `Account` | Yes | Pool state PDA with uninitialized version.
**Derivation**: `["ccip_tokenpool_config", mint]` under this program. | + +##### Authorization + +- **Permissionless**: Anyone can call this instruction diff --git a/src/content/ccip/api-reference/svm/v0.1.1/errors.mdx b/src/content/ccip/api-reference/svm/v0.1.1/errors.mdx new file mode 100644 index 00000000000..3af4d0d4bd9 --- /dev/null +++ b/src/content/ccip/api-reference/svm/v0.1.1/errors.mdx @@ -0,0 +1,121 @@ +--- +section: ccip +date: Last Modified +title: "CCIP v0.1.1 SVM Errors API Reference" +metadata: + description: "Complete API documentation for CCIP error codes and handling on SVM-based blockchains like Solana. Comprehensive reference covering router errors, token pool errors, shared errors, error resolution strategies, and debugging guidance for cross-chain development." + excerpt: "CCIP errors, SVM error codes, Solana errors, cross-chain errors, router errors, token pool errors, error handling, debugging, error resolution, blockchain troubleshooting" +--- + +import { Aside } from "@components" +import CcipCommon from "@features/ccip/CcipCommon.astro" + +## Errors + +### Router + +The Router program uses error codes starting from **7000** (Anchor's base custom error code 6000 + offset 1000). + +#### Common Errors + +| Error Code | Symbol | Description | +| ---------- | ---------------------------- | ------------------------------------------------------------------------------------- | +| **7000** | `Unauthorized` | The signer is not authorized to perform this operation. | +| **7002** | `InvalidVersion` | The on-chain state has a version number higher than expected or zero (uninitialized). | +| **7017** | `InvalidInputsChainSelector` | The provided chain selector is invalid (e.g., zero when it shouldn't be). | + +#### Message Sending Errors (`ccip_send`, `get_fee`) + +| Error Code | Symbol | Description | +| ---------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **7001** | `InvalidRMNRemoteAddress` | The RMN Remote program address does not match the configured address. | +| **7003** | `InvalidInputsMint` | The mint account input is invalid or doesn't match expected requirements. | +| **7004** | `FeeTokenMismatch` | The fee token doesn't match the expected token for the transfer. | +| **7005** | `ReachedMaxSequenceNumber` | The sequence number cannot be incremented further (u64 overflow). This is very unlikely. | +| **7006** | `InvalidInputsTokenIndices` | The sub-slice token index calculations are invalid, or `token_indexes.len()` doesn't match the number of tokens. | +| **7007** | `InvalidInputsPoolAccounts` | The passed "pool sub-slice" accounts do not match the expected PDAs for the token pool's configuration. | +| **7008** | `InvalidInputsTokenAccounts` | The user token or pool token account is invalid (wrong ATAs or minted by a different token). | +| **7009** | `InvalidInputsTokenAdminRegistryAccounts` | The `token_admin_registry` passed does not match the expected PDA or has invalid state. | +| **7010** | `InvalidInputsLookupTableAccounts` | The Address Lookup Table (ALT) provided is invalid or does not match what the `token_admin_registry` expects. | +| **7011** | `InvalidInputsLookupTableAccountWritable` | One or more accounts in the lookup table are incorrectly marked as writable / non-writable. | +| **7012** | `InvalidInputsTokenAmount` | An attempt was made to send a token amount of zero. | +| **7014** | `InvalidInputsAtaAddress` | The associated token account address does not match what was expected. | +| **7015** | `InvalidInputsAtaWritable` | The user's fee-token ATA is not flagged as writable when it needs to be debited. | +| **7017** | `InsufficientLamports` | Users paying with native SOL have insufficient lamports to cover the required fee transfer. | +| **7018** | `InsufficientFunds` | Insufficient funds in a token account. | +| **7019** | `SourceTokenDataTooLarge` | The returned "dest_pool_data" from `lockOrBurnOut` is larger than the allowed `CCIP_LOCK_OR_BURN_V1_RET_BYTES`, or larger than the `dest_bytes_overhead`. | +| **7022** | `SenderNotAllowed` | The sender (caller) is not in the `allowed_senders` list for that destination chain, and the allow-list is enabled. | + +#### Token Administration Errors + +| Error Code | Symbol | Description | +| ---------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------- | +| **7020** | `InvalidTokenAdminRegistryInputsZeroAddress` | The proposed administrator cannot be the zero address. | +| **7021** | `InvalidTokenAdminRegistryProposedAdmin` | An already owned registry cannot have its administrator proposed again, or invalid admin state. | + +#### Administrative Operation Errors + +| Error Code | Symbol | Description | +| ---------- | -------------------------------- | -------------------------------------------------------------------------------- | +| **7013** | `InvalidInputsTransferAllAmount` | When using `transfer_all` flag, the desired amount must be zero. | +| **7023** | `InvalidCodeVersion` | The specified code version is invalid or not supported. | +| **7024** | `InvalidCcipVersionRollback` | Invalid rollback attempt on the CCIP version; may have already been rolled back. | +| **7006** | `RedundantOwnerProposal` | The proposed owner is the same as the current owner. | + +#### Account Derivation Errors + +| Error Code | Symbol | Description | +| ---------- | ------------------------------------------- | -------------------------------------------------------------------------------- | +| **7025** | `InvalidAccountListForPdaDerivation` | The account list provided for PDA derivation is invalid or incomplete. | +| **7026** | `InvalidDerivationStage` | Unexpected or invalid account derivation stage specified. | +| **7027** | `InvalidNonceVersion` | The nonce account has an invalid version that doesn't match expected values. | +| **7028** | `InvalidTokenPoolAccountDerivationResponse` | Token pool returned an unexpected or invalid derivation response. | +| **7029** | `AccountDerivationResponseTooLarge` | The account derivation response is too large to fit in the instruction response. | + +### BurnMint Token Pool + +The BurnMint Token Pool program uses error codes starting from **6000** (Anchor's default base). + +| Error Code | Symbol | Description | +| ---------- | ----------------------------------- | ---------------------------------------------------------------------------------------- | +| **6000** | `InvalidMultisig` | Invalid multisig mint authority or multisig account. | +| **6001** | `MintAuthorityAlreadySet` | The mint authority has already been transferred to the specified multisig. | +| **6002** | `FixedMintToken` | Token has no mint authority (fixed supply), preventing minting operations. | +| **6003** | `UnsupportedTokenProgram` | The token program is not supported (must be SPL Token or Token-2022). | +| **6004** | `InvalidToken2022Multisig` | Invalid multisig account data for Token-2022 program. | +| **6005** | `InvalidSPLTokenMultisig` | Invalid multisig account data for SPL Token program. | +| **6006** | `PoolSignerNotInMultisig` | Pool signer PDA must appear at least `threshold` times as a signer in the multisig. | +| **6007** | `MultisigMustHaveAtLeastTwoSigners` | Multisig account must have at least 2 valid signers. | +| **6008** | `MultisigMustHaveMoreThanOneSigner` | Multisig account must require at least 1 signature (threshold ≥ 1). | +| **6009** | `InvalidMultisigOwner` | Multisig account owner must match the token program ID. | +| **6010** | `InvalidMultisigThreshold` | Invalid multisig threshold: required signatures cannot exceed total signers. | +| **6011** | `InvalidMultisigThresholdTooHigh` | Invalid multisig threshold: required signatures cannot exceed available outside signers. | + +## Shared Token Pool Errors + +The Base Token Pool library defines shared errors (`CcipTokenPoolError`) that are used by both BurnMint and Lock-Release token pool implementations. These errors are returned by validation functions and common operations across all pool types. + +| Error Code | Symbol | Description | +| ---------- | --------------------------------- | -------------------------------------------------------------------------- | +| **6012** | `InvalidInitPoolPermissions` | Pool authority does not match token mint owner during initialization. | +| **6013** | `InvalidRMNRemoteAddress` | The provided RMN Remote address is invalid or doesn't match configuration. | +| **6014** | `Unauthorized` | The signer is not authorized to perform this operation. | +| **6015** | `InvalidInputs` | Invalid input parameters provided to the instruction. | +| **6016** | `InvalidVersion` | Invalid state version encountered during operation. | +| **6017** | `InvalidPoolCaller` | Caller is not an authorized ramp on the router. | +| **6018** | `InvalidSender` | Sender is not allowed when allowlist is enabled. | +| **6019** | `InvalidSourcePoolAddress` | Invalid source pool address provided for cross-chain operation. | +| **6020** | `InvalidToken` | Invalid token address or token mismatch. | +| **6021** | `InvalidTokenAmountConversion` | Failed to convert token amounts between different decimal systems. | +| **6022** | `AllowlistKeyAlreadyExisted` | Attempted to add a key that already exists in the allowlist. | +| **6023** | `AllowlistKeyDidNotExist` | Attempted to remove a key that doesn't exist in the allowlist. | +| **6024** | `RemotePoolAddressAlreadyExisted` | Remote pool address already exists in the configuration. | +| **6025** | `NonemptyPoolAddressesInit` | Pool addresses must be empty during initialization. | +| **6026** | `InvalidDerivationStage` | Unexpected account derivation stage encountered. | +| **6027** | `RLBucketOverfilled` | Rate limit bucket overfilled during operation. | +| **6028** | `RLMaxCapacityExceeded` | Request exceeds maximum rate limit capacity. | +| **6029** | `RLRateLimitReached` | Rate limit reached, transfer temporarily blocked. | +| **6030** | `RLInvalidRateLimitRate` | Invalid rate limit rate configuration. | +| **6031** | `RLDisabledNonZeroRateLimit` | Non-zero rate limit values provided when rate limiting is disabled. | +| **6032** | `LiquidityNotAccepted` | Liquidity operations are not currently accepted by this pool. | +| **6033** | `TransferZeroTokensNotAllowed` | Transferring zero tokens is not allowed in liquidity operations. | diff --git a/src/content/ccip/api-reference/svm/v0.1.1/events.mdx b/src/content/ccip/api-reference/svm/v0.1.1/events.mdx new file mode 100644 index 00000000000..d71b90f3f5b --- /dev/null +++ b/src/content/ccip/api-reference/svm/v0.1.1/events.mdx @@ -0,0 +1,493 @@ +--- +section: ccip +date: Last Modified +title: "CCIP v0.1.1 SVM Events API Reference" +metadata: + description: "Comprehensive API documentation for CCIP events on SVM-based blockchains like Solana. Complete reference covering router events, token pool events, message events, configuration events, and execution events for cross-chain monitoring and debugging." + excerpt: "CCIP events, SVM events, Solana events, cross-chain events, router events, token pool events, message events, execution events, event monitoring, blockchain logging" +--- + +import { Aside } from "@components" +import CcipCommon from "@features/ccip/CcipCommon.astro" + +## Events + +### Router + +The Router program emits various events to provide transparency and enable off-chain monitoring of cross-chain operations. + +#### Message Events + +##### `CCIPMessageSent` + +Emitted when a cross-chain message is successfully sent via `ccip_send`. + +```rust +#[event] +pub struct CCIPMessageSent { + /// The chain selector identifying the destination chain. + pub dest_chain_selector: u64, + /// The sequence number for this message, specific to the destination chain. + pub sequence_number: u64, + /// The full SVM2AnyRampMessage describing the cross-chain payload and tokens being sent. + pub message: SVM2AnyRampMessage, +} +``` + +| Field | Type | Description | +| --------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `dest_chain_selector` | `u64` | The **chain selector** for the destination chain. Think of it as the chain's unique ID in the CCIP ecosystem (e.g., 1 for Ethereum Mainnet, 10 for Optimism, etc.). | +| `sequence_number` | `u64` | Monotonically increments each time you successfully call `ccip_send` for a particular destination chain. It is unique **per** chain in the sense that each chain has its own separate sequence. | +| `message` | `SVM2AnyRampMessage` | The cross-chain message payload itself. It includes:
• The sender's address
• Arbitrary `data` payload
• Token transfer details
• Fees and more | + +#### Token Administration Events + +##### `AdministratorTransferRequested` + +Emitted when a token administrator role transfer is initiated via `owner_propose_administrator`, `ccip_admin_propose_administrator`, or `transfer_admin_role_token_admin_registry`. + +```rust +#[event] +pub struct AdministratorTransferRequested { + pub token: Pubkey, + pub current_admin: Pubkey, + pub new_admin: Pubkey, +} +``` + +| Field | Type | Description | +| --------------- | -------- | --------------------------------------------------------------- | +| `token` | `Pubkey` | The SPL token mint address | +| `current_admin` | `Pubkey` | The current administrator (may be zero on initial registration) | +| `new_admin` | `Pubkey` | The proposed new administrator | + +##### `AdministratorTransferred` + +Emitted when a token administrator role transfer is completed via `accept_admin_role_token_admin_registry`. + +```rust +#[event] +pub struct AdministratorTransferred { + pub token: Pubkey, + pub new_admin: Pubkey, +} +``` + +| Field | Type | Description | +| ----------- | -------- | ---------------------------- | +| `token` | `Pubkey` | The SPL token mint address | +| `new_admin` | `Pubkey` | The new active administrator | + +##### `PoolSet` + +Emitted when a token pool Address Lookup Table is configured via `set_pool`. + +```rust +#[event] +pub struct PoolSet { + pub token: Pubkey, + pub previous_pool_lookup_table: Pubkey, + pub new_pool_lookup_table: Pubkey, +} +``` + +| Field | Type | Description | +| ---------------------------- | -------- | ------------------------------------------------------- | +| `token` | `Pubkey` | The SPL token mint address | +| `previous_pool_lookup_table` | `Pubkey` | The previous Address Lookup Table (zero if first time) | +| `new_pool_lookup_table` | `Pubkey` | The new Address Lookup Table (zero to delist from CCIP) | + +### BurnMint Token Pool + +The BurnMint Token Pool program emits events related to pool configuration, token operations, and mint authority management. + +#### Global Configuration Events + +##### `GlobalConfigUpdated` + +Emitted when the global pool configuration is updated via `init_global_config`, `update_self_served_allowed`, `update_default_router`, or `update_default_rmn`. + +```rust +#[event] +pub struct GlobalConfigUpdated { + pub self_served_allowed: bool, + pub router: Pubkey, + pub rmn_remote: Pubkey, +} +``` + +| Field | Type | Description | +| --------------------- | -------- | --------------------------------------------------- | +| `self_served_allowed` | `bool` | Whether self-service pool initialization is allowed | +| `router` | `Pubkey` | The default CCIP Router program address | +| `rmn_remote` | `Pubkey` | The default RMN Remote program address | + +#### Token Operations Events + +##### `Burned` + +Emitted when tokens are burned via `lock_or_burn_tokens` during cross-chain transfers. + +```rust +#[event] +pub struct Burned { + pub sender: Pubkey, + pub amount: u64, + pub mint: Pubkey, +} +``` + +| Field | Type | Description | +| -------- | -------- | ----------------------------------- | +| `sender` | `Pubkey` | The account that initiated the burn | +| `amount` | `u64` | The amount of tokens burned | +| `mint` | `Pubkey` | The SPL token mint address | + +##### `Minted` + +Emitted when tokens are minted via `release_or_mint_tokens` during cross-chain transfers. + +```rust +#[event] +pub struct Minted { + pub sender: Pubkey, + pub recipient: Pubkey, + pub amount: u64, + pub mint: Pubkey, +} +``` + +| Field | Type | Description | +| ----------- | -------- | --------------------------------------- | +| `sender` | `Pubkey` | The pool signer that authorized minting | +| `recipient` | `Pubkey` | The account receiving the minted tokens | +| `amount` | `u64` | The amount of tokens minted | +| `mint` | `Pubkey` | The SPL token mint address | + +#### Administrative Events + +##### `MintAuthorityTransferred` + +Emitted when the mint authority is transferred to a multisig via `transfer_mint_authority_to_multisig`. + +```rust +#[event] +pub struct MintAuthorityTransferred { + pub mint: Pubkey, + pub old_mint_authority: Pubkey, + pub new_mint_authority: Pubkey, +} +``` + +| Field | Type | Description | +| -------------------- | -------- | ------------------------------- | +| `mint` | `Pubkey` | The SPL token mint address | +| `old_mint_authority` | `Pubkey` | The previous mint authority | +| `new_mint_authority` | `Pubkey` | The new multisig mint authority | + +##### `RemoteChainRemoved` + +Emitted when a remote chain configuration is deleted via `delete_chain_config`. + +```rust +#[event] +pub struct RemoteChainRemoved { + pub chain_selector: u64, + pub mint: Pubkey, +} +``` + +| Field | Type | Description | +| ---------------- | -------- | -------------------------- | +| `chain_selector` | `u64` | The removed chain selector | +| `mint` | `Pubkey` | The SPL token mint address | + +### Lock-Release Token Pool + +The Lock-Release Token Pool program emits events related to token locking and releasing operations, as well as liquidity management. + +#### Token Operations Events + +##### `Locked` + +Emitted when tokens are locked in the pool via `lock_or_burn_tokens` during cross-chain transfers. + +```rust +#[event] +pub struct Locked { + pub sender: Pubkey, + pub amount: u64, + pub mint: Pubkey, +} +``` + +| Field | Type | Description | +| -------- | -------- | ----------------------------------- | +| `sender` | `Pubkey` | The account that initiated the lock | +| `amount` | `u64` | The amount of tokens locked | +| `mint` | `Pubkey` | The SPL token mint address | + +##### `Released` + +Emitted when tokens are released from the pool via `release_or_mint_tokens` during cross-chain transfers. + +```rust +#[event] +pub struct Released { + pub sender: Pubkey, + pub recipient: Pubkey, + pub amount: u64, + pub mint: Pubkey, +} +``` + +| Field | Type | Description | +| ----------- | -------- | ------------------------------------ | +| `sender` | `Pubkey` | The pool signer that released tokens | +| `recipient` | `Pubkey` | The account that received the tokens | +| `amount` | `u64` | The amount of tokens released | +| `mint` | `Pubkey` | The SPL token mint address | + +#### Configuration Events + +##### `GlobalConfigUpdated` + +This event is shared with the BurnMint Token Pool and is documented in the [BurnMint Token Pool section](#globalconfigupdated). + +##### `RemoteChainRemoved` + +This event is shared with the BurnMint Token Pool and is documented in the [BurnMint Token Pool section](#remotechainremoved). + +## Shared Token Pool Events + +The Base Token Pool library defines additional events that are used by both BurnMint and Lock-Release token pool implementations. These events cover configuration management, ownership operations, and rate limiting. + +### Pool Configuration Events + +#### `RemoteChainConfigured` + +Emitted when a remote chain configuration is updated via `edit_chain_remote_config` or `init_chain_remote_config`. + +```rust +#[event] +pub struct RemoteChainConfigured { + pub chain_selector: u64, + pub token: RemoteAddress, + pub previous_token: RemoteAddress, + pub pool_addresses: Vec, + pub previous_pool_addresses: Vec, + pub mint: Pubkey, +} +``` + +| Field | Type | Description | +| ------------------------- | -------------------- | ---------------------------------- | +| `chain_selector` | `u64` | The remote chain selector | +| `token` | `RemoteAddress` | The new remote token address | +| `previous_token` | `RemoteAddress` | The previous remote token address | +| `pool_addresses` | `Vec` | The new remote pool addresses | +| `previous_pool_addresses` | `Vec` | The previous remote pool addresses | +| `mint` | `Pubkey` | The SPL token mint address | + +#### `RateLimitConfigured` + +Emitted when rate limits are updated via `set_chain_rate_limit`. + +```rust +#[event] +pub struct RateLimitConfigured { + pub chain_selector: u64, + pub outbound_rate_limit: RateLimitConfig, + pub inbound_rate_limit: RateLimitConfig, + pub mint: Pubkey, +} +``` + +| Field | Type | Description | +| --------------------- | ----------------- | ---------------------------- | +| `chain_selector` | `u64` | The remote chain selector | +| `outbound_rate_limit` | `RateLimitConfig` | Outbound rate limit settings | +| `inbound_rate_limit` | `RateLimitConfig` | Inbound rate limit settings | +| `mint` | `Pubkey` | The SPL token mint address | + +#### `RemotePoolsAppended` + +Emitted when remote pool addresses are added via `append_remote_pool_addresses`. + +```rust +#[event] +pub struct RemotePoolsAppended { + pub chain_selector: u64, + pub pool_addresses: Vec, + pub previous_pool_addresses: Vec, + pub mint: Pubkey, +} +``` + +| Field | Type | Description | +| ------------------------- | -------------------- | -------------------------------- | +| `chain_selector` | `u64` | The remote chain selector | +| `pool_addresses` | `Vec` | The updated pool addresses list | +| `previous_pool_addresses` | `Vec` | The previous pool addresses list | +| `mint` | `Pubkey` | The SPL token mint address | + +### Administrative Events + +#### `TokenPoolInitialized` + +Emitted when a new token pool is initialized via the `initialize` instruction. + +```rust +#[event] +pub struct TokenPoolInitialized { + pub mint: Pubkey, + pub token_program: Pubkey, + pub owner: Pubkey, +} +``` + +| Field | Type | Description | +| --------------- | -------- | -------------------------- | +| `mint` | `Pubkey` | The SPL token mint address | +| `token_program` | `Pubkey` | The token program ID | +| `owner` | `Pubkey` | The initial pool owner | + +#### `OwnershipTransferRequested` + +Emitted when ownership transfer is proposed via `transfer_ownership`. + +```rust +#[event] +pub struct OwnershipTransferRequested { + pub from: Pubkey, + pub to: Pubkey, + pub mint: Pubkey, +} +``` + +| Field | Type | Description | +| ------ | -------- | -------------------------- | +| `from` | `Pubkey` | The current owner | +| `to` | `Pubkey` | The proposed new owner | +| `mint` | `Pubkey` | The SPL token mint address | + +#### `OwnershipTransferred` + +Emitted when ownership transfer is completed via `accept_ownership`. + +```rust +#[event] +pub struct OwnershipTransferred { + pub from: Pubkey, + pub to: Pubkey, + pub mint: Pubkey, +} +``` + +| Field | Type | Description | +| ------ | -------- | -------------------------- | +| `from` | `Pubkey` | The previous owner | +| `to` | `Pubkey` | The new owner | +| `mint` | `Pubkey` | The SPL token mint address | + +#### `RouterUpdated` + +Emitted when the router address is updated via `set_router`. + +```rust +#[event] +pub struct RouterUpdated { + pub old_router: Pubkey, + pub new_router: Pubkey, + pub mint: Pubkey, +} +``` + +| Field | Type | Description | +| ------------ | -------- | -------------------------- | +| `old_router` | `Pubkey` | The previous router | +| `new_router` | `Pubkey` | The new router | +| `mint` | `Pubkey` | The SPL token mint address | + +#### `RmnRemoteUpdated` + +Emitted when the RMN remote address is updated via `set_rmn`. + +```rust +#[event] +pub struct RmnRemoteUpdated { + pub old_rmn_remote: Pubkey, + pub new_rmn_remote: Pubkey, + pub mint: Pubkey, +} +``` + +| Field | Type | Description | +| ---------------- | -------- | -------------------------- | +| `old_rmn_remote` | `Pubkey` | The previous RMN remote | +| `new_rmn_remote` | `Pubkey` | The new RMN remote | +| `mint` | `Pubkey` | The SPL token mint address | + +### Rate Limiting Events + +#### `TokensConsumed` + +Emitted when tokens are consumed from the rate limit bucket during transfer operations. + +```rust +#[event] +pub struct TokensConsumed { + pub tokens: u64, +} +``` + +| Field | Type | Description | +| -------- | ----- | ------------------------------------- | +| `tokens` | `u64` | Number of tokens consumed from bucket | + +#### `ConfigChanged` + +Emitted when rate limit configuration is updated via `set_token_bucket_config`. + +```rust +#[event] +pub struct ConfigChanged { + pub config: RateLimitConfig, +} +``` + +| Field | Type | Description | +| -------- | ----------------- | -------------------------------- | +| `config` | `RateLimitConfig` | The new rate limit configuration | + +### OffRamp + +The OffRamp program emits events related to message execution during the cross-chain message delivery process. + +#### Message Execution Events + +##### `ExecutionStateChanged` + +Emitted during message execution to track the progress of cross-chain message delivery. This event is emitted twice during the execution process: + +1. When the message state changes to `InProgress` (execution started) +1. When the message state changes to `Success` (execution completed) + +```rust +#[event] +pub struct ExecutionStateChanged { + pub source_chain_selector: u64, + pub sequence_number: u64, + pub message_id: [u8; 32], + pub message_hash: [u8; 32], + pub state: MessageExecutionState, +} +``` + +| Field | Type | Description | +| ----------------------- | ----------------------- | --------------------------------------------------- | +| `source_chain_selector` | `u64` | The chain selector of the source chain | +| `sequence_number` | `u64` | The sequence number of the message being executed | +| `message_id` | `[u8; 32]` | Unique identifier for the cross-chain message | +| `message_hash` | `[u8; 32]` | Hash of the message content | +| `state` | `MessageExecutionState` | Current execution state (`InProgress` or `Success`) | diff --git a/src/content/ccip/api-reference/svm/v0.1.1/index.mdx b/src/content/ccip/api-reference/svm/v0.1.1/index.mdx new file mode 100644 index 00000000000..2493bbc25a8 --- /dev/null +++ b/src/content/ccip/api-reference/svm/v0.1.1/index.mdx @@ -0,0 +1,36 @@ +--- +section: ccip +date: Last Modified +title: "CCIP v0.1.1 SVM API Reference" +metadata: + description: "Complete API reference documentation for Chainlink CCIP v0.1.1 on SVM-based blockchains including Solana. Comprehensive guide covering message structures, router functionality, token pools, receiver implementation, events, and error handling for cross-chain interoperability and token transfers." + excerpt: "CCIP SVM API, Solana cross-chain, blockchain interoperability, token transfers, message routing, onchain programs, anchor framework, token pools, burn mint, lock release, receiver implementation" +isIndex: true +--- + +import { Aside } from "@components" +import CcipCommon from "@features/ccip/CcipCommon.astro" + + + +## API References + +### Core Components + +- [Messages](/ccip/api-reference/svm/v0.1.1/messages) - Message structures and extra args for cross-chain messaging +- [Router](/ccip/api-reference/svm/v0.1.1/router) - Instructions for sending messages and managing CCIP routing on Solana +- [Receiver](/ccip/api-reference/svm/v0.1.1/receiver) - Implementation guide for CCIP message receivers on SVM blockchains + +### Token Pool Components + +- [Base Token Pool Library](/ccip/api-reference/svm/v0.1.1/base-token-pool) - Shared library providing common functionality for all token pool implementations +- [BurnMint Token Pool](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool) - Token pool implementation using burn and mint strategy for cross-chain transfers +- [Lock-Release Token Pool](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool) - Token pool implementation using lock and release strategy with liquidity management + +### Reference Materials + +- [Events](/ccip/api-reference/svm/v0.1.1/events) - Event emissions for tracking cross-chain messages and token operations +- [Errors](/ccip/api-reference/svm/v0.1.1/errors) - Comprehensive list of CCIP error codes and troubleshooting guidance diff --git a/src/content/ccip/api-reference/svm/v0.1.1/lock-release-token-pool.mdx b/src/content/ccip/api-reference/svm/v0.1.1/lock-release-token-pool.mdx new file mode 100644 index 00000000000..31306595cac --- /dev/null +++ b/src/content/ccip/api-reference/svm/v0.1.1/lock-release-token-pool.mdx @@ -0,0 +1,686 @@ +--- +section: ccip +date: Last Modified +title: "CCIP v0.1.1 SVM Lock-Release Token Pool API Reference" +metadata: + description: "Comprehensive API documentation for the Lock-Release Token Pool program on SVM-based blockchains like Solana. Complete guide covering lock and release operations, liquidity management, token pool configuration, cross-chain token transfers, and rebalancer functionality for seamless interoperability." + excerpt: "Lock-Release Token Pool, SVM lock release pool, Solana token pool, cross-chain token transfers, lock and release operations, liquidity management, token pool configuration, rebalancer, CCIP token pools" +--- + +import { Aside } from "@components" +import CcipCommon from "@features/ccip/CcipCommon.astro" + +## Lock-Release Token Pool + +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs/lockrelease-token-pool) + +The Lock-Release Token Pool program implements a token pool that uses a lock/release strategy for cross-chain transfers. When tokens are sent cross-chain, they are locked in the pool on the source chain and released from the pool on the destination chain. + +**Program ID**: `8eqh8wppT9c5rw4ERqNCffvU6cNFJWff9WmkcYtmGiqC` + +### Instructions + +The Lock-Release Token Pool program provides 24 instructions organized into 6 categories: + +#### Global Configuration + +These instructions manage program-wide settings that apply to all pools deployed from this program. + +##### `init_global_config` + +Initializes the global configuration for the Lock-Release Token Pool program. Only callable by the program's upgrade authority. + +```rust +pub fn init_global_config( + ctx: Context, + router_address: Pubkey, + rmn_address: Pubkey, +) -> Result<()> +``` + +**Parameters:** + +- `router_address`: Default CCIP Router program address for new pools +- `rmn_address`: Default RMN Remote program address for security validation + +**Context Accounts:** + +- `config`: Global Config PDA (`seeds: ["config"]`) - initialized by this instruction +- `authority`: Program upgrade authority (signer, pays for account creation) +- `system_program`: Solana System Program +- `program`: Lock-Release Token Pool program account +- `program_data`: Program data account for upgrade authority validation + +**Authorization:** Program upgrade authority only + +**PDA Derivation:** + +``` +Global Config PDA = find_program_address(["config"], program_id) +``` + +##### `update_self_served_allowed` + +Updates whether self-service pool initialization is allowed. + +```rust +pub fn update_self_served_allowed( + ctx: Context, + self_served_allowed: bool, +) -> Result<()> +``` + +**Parameters:** + +- `self_served_allowed`: Whether to allow users to initialize pools for tokens they control + +**Context Accounts:** + +- `config`: Global Config PDA (mutable) +- `authority`: Program upgrade authority (signer) +- `program`: Lock-Release Token Pool program account +- `program_data`: Program data account for upgrade authority validation + +**Authorization:** Program upgrade authority only + +##### `update_default_router` + +Updates the default router address for new pools. + +```rust +pub fn update_default_router( + ctx: Context, + router_address: Pubkey, +) -> Result<()> +``` + +**Parameters:** + +- `router_address`: New default router program address + +**Context Accounts:** Same as `update_self_served_allowed` + +**Authorization:** Program upgrade authority only + +##### `update_default_rmn` + +Updates the default RMN remote address for new pools. + +```rust +pub fn update_default_rmn( + ctx: Context, + rmn_address: Pubkey, +) -> Result<()> +``` + +**Parameters:** + +- `rmn_address`: New default RMN remote program address + +**Context Accounts:** Same as `update_self_served_allowed` + +**Authorization:** Program upgrade authority only + +#### Pool Initialization & Management + +These instructions handle individual pool lifecycle management and configuration. + +##### `initialize` + +Initializes a new Lock-Release Token Pool for a specific token. + +```rust +pub fn initialize(ctx: Context) -> Result<()> +``` + +**Context Accounts:** + +- `state`: Pool State PDA (`seeds: ["ccip_tokenpool_config", mint]`) - initialized by this instruction +- `mint`: Token mint account that this pool will manage +- `authority`: Pool initializer (signer, pays for account creation) +- `system_program`: Solana System Program +- `program`: Lock-Release Token Pool program account +- `program_data`: Program data account for authorization validation +- `config`: Global Config PDA for default settings + +**Authorization:** + +- Program upgrade authority, OR +- Token mint authority (when `self_served_allowed` is true in global config) + +**PDA Derivation:** + +``` +Pool State PDA = find_program_address(["ccip_tokenpool_config", mint], program_id) +Pool Signer PDA = find_program_address(["ccip_tokenpool_signer", mint], program_id) +``` + + + +##### `type_version` + +Returns the program type and version information. + +```rust +pub fn type_version(_ctx: Context) -> Result +``` + +**Returns:** Program type and version string (e.g., "LockReleaseTokenPool 1.6.0") + +**Context Accounts:** + +- `clock`: Clock sysvar (unused but required by Anchor) + +**Authorization:** None (permissionless) + +##### `transfer_ownership` + +Proposes a new owner for the pool. The proposed owner must call `accept_ownership` to complete the transfer. + +```rust +pub fn transfer_ownership( + ctx: Context, + proposed_owner: Pubkey, +) -> Result<()> +``` + +**Parameters:** + +- `proposed_owner`: Address of the proposed new pool owner + +**Context Accounts:** + +- `state`: Pool State PDA (mutable) +- `mint`: Token mint account +- `authority`: Current pool owner (signer) + +**Authorization:** Current pool owner only + +##### `accept_ownership` + +Accepts ownership of a pool that was proposed via `transfer_ownership`. + +```rust +pub fn accept_ownership(ctx: Context) -> Result<()> +``` + +**Context Accounts:** + +- `state`: Pool State PDA (mutable) +- `mint`: Token mint account +- `authority`: Proposed owner (signer) + +**Authorization:** Proposed owner only + +##### `set_router` + +Updates the router address for this pool. + +```rust +pub fn set_router( + ctx: Context, + new_router: Pubkey, +) -> Result<()> +``` + +**Parameters:** + +- `new_router`: New router program address + +**Context Accounts:** + +- `state`: Pool State PDA (mutable) +- `mint`: Token mint account +- `authority`: Program upgrade authority (signer) +- `program`: Lock-Release Token Pool program account +- `program_data`: Program data account for authorization validation + +**Authorization:** Program upgrade authority only (and pool must be owned by upgrade authority) + +##### `set_rmn` + +Updates the RMN remote address for this pool. + +```rust +pub fn set_rmn( + ctx: Context, + rmn_address: Pubkey, +) -> Result<()> +``` + +**Parameters:** + +- `rmn_address`: New RMN remote program address + +**Context Accounts:** Same as `set_router` + +**Authorization:** Program upgrade authority only (and pool must be owned by upgrade authority) + +##### `initialize_state_version` + +Sets the pool's version field if it was not set during initialization. Permissionless utility instruction. + +```rust +pub fn initialize_state_version( + ctx: Context, + _mint: Pubkey, +) -> Result<()> +``` + +**Parameters:** + +- `_mint`: Token mint address (used for PDA derivation) + +**Context Accounts:** + +- `state`: Pool State PDA (mutable) - must have uninitialized version + +**Authorization:** None (permissionless) + +#### Chain Configuration + +These instructions manage per-destination chain settings including rate limits and remote pool addresses. + +##### `init_chain_remote_config` + +Initializes configuration for a remote destination chain. + +```rust +pub fn init_chain_remote_config( + ctx: Context, + remote_chain_selector: u64, + mint: Pubkey, + cfg: RemoteConfig, +) -> Result<()> +``` + +**Parameters:** + +- `remote_chain_selector`: Destination chain identifier +- `mint`: Token mint address +- `cfg`: Remote chain configuration (must have empty `pool_addresses`) + +**Context Accounts:** + +- `state`: Pool State PDA +- `chain_config`: Chain Config PDA (`seeds: ["ccip_tokenpool_chainconfig", chain_selector, mint]`) - initialized by this instruction +- `authority`: Pool owner (signer, pays for account creation) +- `system_program`: Solana System Program + +**Authorization:** Pool owner only + +**PDA Derivation:** + +``` +Chain Config PDA = find_program_address( + ["ccip_tokenpool_chainconfig", remote_chain_selector.to_le_bytes(), mint], + program_id +) +``` + +##### `edit_chain_remote_config` + +Updates the remote configuration for an existing chain. + +```rust +pub fn edit_chain_remote_config( + ctx: Context, + remote_chain_selector: u64, + mint: Pubkey, + cfg: RemoteConfig, +) -> Result<()> +``` + +**Parameters:** + +- `remote_chain_selector`: Destination chain identifier +- `mint`: Token mint address +- `cfg`: Updated remote chain configuration + +**Context Accounts:** + +- `state`: Pool State PDA +- `chain_config`: Chain Config PDA (mutable, resized as needed) +- `authority`: Pool owner (signer, pays for resize) +- `system_program`: Solana System Program + +**Authorization:** Pool owner only + +##### `append_remote_pool_addresses` + +Adds remote pool addresses to an existing chain configuration. + +```rust +pub fn append_remote_pool_addresses( + ctx: Context, + remote_chain_selector: u64, + _mint: Pubkey, + addresses: Vec, +) -> Result<()> +``` + +**Parameters:** + +- `remote_chain_selector`: Destination chain identifier +- `_mint`: Token mint address (used for PDA derivation) +- `addresses`: List of remote pool addresses to add + +**Context Accounts:** + +- `state`: Pool State PDA +- `chain_config`: Chain Config PDA (mutable, resized as needed) +- `authority`: Pool owner (signer, pays for resize) +- `system_program`: Solana System Program + +**Authorization:** Pool owner only + +##### `set_chain_rate_limit` + +Configures rate limits for inbound and outbound transfers for a specific chain. + +```rust +pub fn set_chain_rate_limit( + ctx: Context, + remote_chain_selector: u64, + mint: Pubkey, + inbound: RateLimitConfig, + outbound: RateLimitConfig, +) -> Result<()> +``` + +**Parameters:** + +- `remote_chain_selector`: Destination chain identifier +- `mint`: Token mint address +- `inbound`: Rate limiting configuration for incoming transfers +- `outbound`: Rate limiting configuration for outgoing transfers + +**Context Accounts:** + +- `state`: Pool State PDA +- `chain_config`: Chain Config PDA (mutable) +- `authority`: Pool owner (signer) + +**Authorization:** Pool owner only + +##### `delete_chain_config` + +Deletes the configuration for a remote chain and closes the account. + +```rust +pub fn delete_chain_config( + _ctx: Context, + remote_chain_selector: u64, + mint: Pubkey, +) -> Result<()> +``` + +**Parameters:** + +- `remote_chain_selector`: Destination chain identifier +- `mint`: Token mint address + +**Context Accounts:** + +- `state`: Pool State PDA +- `chain_config`: Chain Config PDA (closed, rent returned to authority) +- `authority`: Pool owner (signer, receives rent) + +**Authorization:** Pool owner only + +#### Access Control + +These instructions manage the allowlist for senders authorized to use the pool. + +##### `configure_allow_list` + +Adds addresses to the allowlist and enables/disables allowlist enforcement. + +```rust +pub fn configure_allow_list( + ctx: Context, + add: Vec, + enabled: bool, +) -> Result<()> +``` + +**Parameters:** + +- `add`: List of addresses to add to allowlist +- `enabled`: Whether to enable allowlist enforcement + +**Context Accounts:** + +- `state`: Pool State PDA (mutable, resized as needed) +- `mint`: Token mint account +- `authority`: Pool owner (signer, pays for resize) +- `system_program`: Solana System Program + +**Authorization:** Pool owner only + +##### `remove_from_allow_list` + +Removes addresses from the allowlist. + +```rust +pub fn remove_from_allow_list( + ctx: Context, + remove: Vec, +) -> Result<()> +``` + +**Parameters:** + +- `remove`: List of addresses to remove from allowlist + +**Context Accounts:** + +- `state`: Pool State PDA (mutable, resized as needed) +- `mint`: Token mint account +- `authority`: Pool owner (signer, pays for resize) +- `system_program`: Solana System Program + +**Authorization:** Pool owner only + +#### Cross-Chain Operations + +These instructions handle the core lock/release operations for cross-chain transfers. + +##### `release_or_mint_tokens` + +Releases tokens from the pool to a receiver (destination chain operation). + +```rust +pub fn release_or_mint_tokens( + ctx: Context, + release_or_mint: ReleaseOrMintInV1, +) -> Result +``` + +**Parameters:** + +- `release_or_mint`: Release parameters including receiver, amount, and source chain info + +**Context Accounts:** + +- `authority`: OffRamp authority PDA (signer) - derived from OffRamp program +- `offramp_program`: OffRamp program account +- `allowed_offramp`: Router's allowed OffRamp PDA for validation +- `state`: Pool State PDA +- `token_program`: SPL Token or Token-2022 program +- `mint`: Token mint account (mutable) +- `pool_signer`: Pool Signer PDA +- `pool_token_account`: Pool's ATA holding locked tokens (mutable) +- `chain_config`: Chain Config PDA for source chain (mutable for rate limiting) +- `rmn_remote`: RMN Remote program +- `rmn_remote_curses`: RMN Remote curses PDA +- `rmn_remote_config`: RMN Remote config PDA +- `receiver_token_account`: Receiver's ATA for tokens (mutable) + +**Authorization:** Valid OffRamp program (validated via Router's allowed OffRamp PDA) + +**Returns:** + +```rust +ReleaseOrMintOutV1 { + destination_amount: u64, // Amount released in destination token decimals +} +``` + +##### `lock_or_burn_tokens` + +Locks tokens in the pool (source chain operation). + +```rust +pub fn lock_or_burn_tokens( + ctx: Context, + lock_or_burn: LockOrBurnInV1, +) -> Result +``` + +**Parameters:** + +- `lock_or_burn`: Lock parameters including amount and destination chain info + +**Context Accounts:** + +- `authority`: Router OnRamp authority (signer) +- `state`: Pool State PDA +- `token_program`: SPL Token or Token-2022 program +- `mint`: Token mint account (mutable) +- `pool_signer`: Pool Signer PDA +- `pool_token_account`: Pool's ATA for locked tokens (mutable) +- `rmn_remote`: RMN Remote program +- `rmn_remote_curses`: RMN Remote curses PDA +- `rmn_remote_config`: RMN Remote config PDA +- `chain_config`: Chain Config PDA for destination chain (mutable for rate limiting) + +**Authorization:** Router OnRamp authority only + +**Returns:** + +```rust +LockOrBurnOutV1 { + dest_token_address: Vec, // Remote token address + dest_pool_data: Vec, // ABI-encoded token decimals +} +``` + + + +#### Liquidity Management + +These instructions manage token liquidity within the pool for cross-chain operations. + +##### `set_rebalancer` + +Sets the address authorized to provide and withdraw liquidity. + +```rust +pub fn set_rebalancer( + ctx: Context, + rebalancer: Pubkey, +) -> Result<()> +``` + +**Parameters:** + +- `rebalancer`: Address authorized for liquidity operations + +**Context Accounts:** + +- `state`: Pool State PDA (mutable) +- `mint`: Token mint account +- `authority`: Pool owner (signer) + +**Authorization:** Pool owner only + +##### `set_can_accept_liquidity` + +Enables or disables liquidity operations for the pool. + +```rust +pub fn set_can_accept_liquidity( + ctx: Context, + allow: bool, +) -> Result<()> +``` + +**Parameters:** + +- `allow`: Whether to allow liquidity operations + +**Context Accounts:** Same as `set_rebalancer` + +**Authorization:** Pool owner only + +##### `provide_liquidity` + +Transfers tokens from the rebalancer to the pool to increase available liquidity. + +```rust +pub fn provide_liquidity( + ctx: Context, + amount: u64, +) -> Result<()> +``` + +**Parameters:** + +- `amount`: Amount of tokens to provide (must be > 0) + +**Context Accounts:** + +- `state`: Pool State PDA +- `token_program`: SPL Token or Token-2022 program +- `mint`: Token mint account (mutable) +- `pool_signer`: Pool Signer PDA +- `pool_token_account`: Pool's ATA for tokens (mutable, receives tokens) +- `remote_token_account`: Rebalancer's token account (mutable, sends tokens) +- `authority`: Rebalancer (signer) + +**Authorization:** Rebalancer only + +**Requirements:** + +- Pool must allow liquidity operations (`can_accept_liquidity` = true) +- Amount must be greater than zero + +##### `withdraw_liquidity` + +Transfers tokens from the pool to the rebalancer to decrease available liquidity. + +```rust +pub fn withdraw_liquidity( + ctx: Context, + amount: u64, +) -> Result<()> +``` + +**Parameters:** + +- `amount`: Amount of tokens to withdraw (must be > 0) + +**Context Accounts:** + +- `state`: Pool State PDA +- `token_program`: SPL Token or Token-2022 program +- `mint`: Token mint account (mutable) +- `pool_signer`: Pool Signer PDA +- `pool_token_account`: Pool's ATA for tokens (mutable, sends tokens) +- `remote_token_account`: Rebalancer's token account (mutable, receives tokens) +- `authority`: Rebalancer (signer) + +**Authorization:** Rebalancer only + +**Requirements:** + +- Pool must allow liquidity operations (`can_accept_liquidity` = true) +- Amount must be greater than zero +- Pool must have sufficient token balance diff --git a/src/content/ccip/api-reference/svm/v1.6.0/messages.mdx b/src/content/ccip/api-reference/svm/v0.1.1/messages.mdx similarity index 96% rename from src/content/ccip/api-reference/svm/v1.6.0/messages.mdx rename to src/content/ccip/api-reference/svm/v0.1.1/messages.mdx index 4060fbb81b0..9d4513738ec 100644 --- a/src/content/ccip/api-reference/svm/v1.6.0/messages.mdx +++ b/src/content/ccip/api-reference/svm/v0.1.1/messages.mdx @@ -1,9 +1,10 @@ --- section: ccip date: Last Modified -title: "CCIP v1.6.0 SVM Messages API Reference" +title: "CCIP v0.1.1 SVM Messages API Reference" metadata: - description: "API documentation for CCIP message structures and extras args on SVM-based blockchains like Solana." + description: "Complete API documentation for CCIP message structures and extra arguments on SVM-based blockchains like Solana. Includes detailed specifications for cross-chain message formatting, token transfer data, receiver arguments, and message construction for seamless blockchain interoperability." + excerpt: "CCIP messages, SVM message structure, cross-chain messaging, Solana messages, token transfer data, receiver arguments, message formatting, blockchain interoperability, extra args" --- import { Aside } from "@components" diff --git a/src/content/ccip/api-reference/svm/v1.6.0/receiver.mdx b/src/content/ccip/api-reference/svm/v0.1.1/receiver.mdx similarity index 92% rename from src/content/ccip/api-reference/svm/v1.6.0/receiver.mdx rename to src/content/ccip/api-reference/svm/v0.1.1/receiver.mdx index 506b6af5acf..aae19f252be 100644 --- a/src/content/ccip/api-reference/svm/v1.6.0/receiver.mdx +++ b/src/content/ccip/api-reference/svm/v0.1.1/receiver.mdx @@ -1,9 +1,10 @@ --- section: ccip date: Last Modified -title: "CCIP v1.6.0 SVM Receiver API Reference" +title: "CCIP v0.1.1 SVM Receiver API Reference" metadata: - description: "API documentation for implementing CCIP receivers on SVM-based blockchains like Solana." + description: "Complete API documentation for implementing CCIP receivers on SVM-based blockchains like Solana. Detailed guide covering receiver trait implementation, message handling, cross-chain message processing, and receiver program development for blockchain interoperability." + excerpt: "CCIP receiver, SVM receiver implementation, Solana receiver, cross-chain receiver, message handling, receiver trait, ccip receive, blockchain interoperability, message processing" --- import { Aside } from "@components" @@ -11,6 +12,8 @@ import CcipCommon from "@features/ccip/CcipCommon.astro" ## Receiver +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs/example-ccip-receiver) + Below is a complete API reference for the `ccip_receive` instruction that must be implemented by any Solana program wishing to receive CCIP messages. ### `ccip_receive` @@ -28,7 +31,7 @@ pub fn ccip_receive( | Name | Type | Description | | --------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| `message` | `Any2SVMMessage` | The cross-chain message being delivered. See [Message Structure](/ccip/api-reference/svm/v1.6.0/messages#any2svmmessage) for details. | +| `message` | `Any2SVMMessage` | The cross-chain message being delivered. See [Message Structure](/ccip/api-reference/svm/v0.1.1/messages#any2svmmessage) for details. | #### Context (Accounts) diff --git a/src/content/ccip/api-reference/svm/v0.1.1/router.mdx b/src/content/ccip/api-reference/svm/v0.1.1/router.mdx new file mode 100644 index 00000000000..35e6f951cc8 --- /dev/null +++ b/src/content/ccip/api-reference/svm/v0.1.1/router.mdx @@ -0,0 +1,460 @@ +--- +section: ccip +date: Last Modified +title: "CCIP v0.1.1 SVM Router API Reference" +metadata: + description: "Comprehensive API documentation for the CCIP Router program on SVM-based blockchains like Solana. Complete guide covering message sending, token administration, fee calculation, destination chain configuration, and router management for cross-chain interoperability." + excerpt: "CCIP Router, SVM router program, Solana router, cross-chain routing, message sending, token administration, fee calculation, destination chains, router configuration, ccip_send" +--- + +import { Aside, ClickToZoom } from "@components" +import CcipCommon from "@features/ccip/CcipCommon.astro" + +## Router + +[Git Source](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs/ccip-router) + +Below is a complete API reference for the CCIP Router program instructions. + +### Message Sending + +#### `ccip_send` + +This instruction is the entry point for sending a cross-chain message from an SVM-based blockchain to a specified destination blockchain. + +```rust +fn ccip_send( + ctx: Context, + dest_chain_selector: u64, + message: SVM2AnyMessage, + token_indexes: Vec +) -> Result<[u8; 32]>; +``` + +##### Parameters + +| Name | Type | Description | +| ---------------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| `dest_chain_selector` | `u64` | The unique CCIP blockchain identifier of the destination blockchain. | +| `message` | `SVM2AnyMessage` | Read [Messages](/ccip/api-reference/svm/v0.1.1/messages#svm2anymessage) for more details. | +| `token_indexes` | `Vec` | Index offsets slicing the remaining accounts so each token's subset can be grouped (see [Context](#context-accounts)). | + +##### Context (Accounts) + +These are the required accounts passed alongside the instructions. For relevant PDAs, the instructions on how to derive seeds are given below. + +| Field | Type | Writable? | Description | +| ------------------------------------------------ | ---------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `config` | `Account` | No | Router config PDA.
**Derivation**: `["config"]` under the `ccip_router` program. | +| `dest_chain_state` | `Account` | Yes | Per-destination blockchain PDA for `sequence_number`, chain config, etc.
**Derivation**: `["dest_chain_state", dest_chain_selector]` under the `ccip_router` program. | +| `nonce` | `Account` | Yes | Current nonce PDA for `(authority, dest_chain_selector)`.
**Derivation**: `["nonce", dest_chain_selector, authority_pubkey]` under the `ccip_router` program. | +| `authority` | `Signer<'info>` | Yes | The user/wallet paying for the `ccip_send` transaction. Also, it must match the seeds in `nonce`. | +| `system_program` | `Program<'info, System>` | No | Standard System Program. | +| `fee_token_program` | `Interface<'info, TokenInterface>` | No | The token program used for fee payment (e.g., SPL Token). If paying with native SOL, this is just the `SystemProgramID`. | +| `fee_token_mint` | `InterfaceAccount<'info, Mint>` | No | Fee token mint. If paying in SPL, pass your chosen token mint. If paying in native SOL, a special "zero" mint (`Pubkey::default()`) or "[native mint](https://docs.rs/spl-token/latest/spl_token/native_mint/constant.ID.html)" (`native_mint::ID`) is used. | +| `fee_token_user_associated_account` | `UncheckedAccount<'info>` | Yes | If fees are paid in SPL, this is the user's ATA.
**Derivation**: It is derived via the Associated Token Program seeds: `[authority_pubkey, fee_token_program.key(), fee_token_mint.key() ]` under the relevant Token Program (Make sure you use the correct token program ID—**Token-2022** vs.SPL Token). If paying with native SOL, pass the zero address (`Pubkey::default())` and do not mark it writable. | +| `fee_token_receiver` | `InterfaceAccount<'info, TokenAccount>` | Yes | The ATA where all the fees are collected.
**Derivation**: from `[fee_billing_signer,fee_token_program.key(),fee_token_mint.key()]`. | +| `fee_billing_signer` | `UncheckedAccount<'info>` | No | PDA is the router's billing authority for transferring fees (native SOL or SPL tokens).
from fee_token_user_associated_account to fee_token_receiver.
**Derivation**: `["fee_billing_signer"]` under the `ccip_router` program. | +| `fee_quoter` | `UncheckedAccount<'info>` | No | The **Fee Quoter** program ID. | +| `fee_quoter_config` | `UncheckedAccount<'info>` | No | The global Fee Quoter config PDA.
**Derivation**: `["config"]` under the `fee_quoter` program. | +| `fee_quoter_dest_chain` | `UncheckedAccount<'info>` | No | Per-destination blockchain PDA in the Fee Quoter program. It stores chain-specific configuration (gas price data, limits, etc.) for SVM2Any messages.
**Derivation**: `["dest_chain",dest_chain_selector]` under the `fee_quoter` program. | +| `fee_quoter_billing_token_config` | `UncheckedAccount<'info>` | No | A per-fee-token PDA in the Fee Quoter program stores token-specific parameters (price data, billing premiums, etc.) used to calculate fees.
**Derivation**: If the message pays fees in native SOL, the seed uses the `native_mint::ID`; otherwise, it uses the SPL token's `mint` public key. `["fee_billing_token_config", seed]` under the `fee_quoter` program. | +| `fee_quoter_link_token_config` | `UncheckedAccount<'info>` | No | PDA containing the Fee Quoter's LINK token billing configuration (LINK price data, premium multipliers, etc.). The fee token amount is converted into "juels" using LINK's valuation from this account during fee calculation.
**Derivation**: `["fee_billing_token_config", link_token_mint]` under the `fee_quoter` program. | +| `rmn_remote` | `UncheckedAccount<'info>` | No | The RMN program ID used to verify if a given chain is cursed. | +| `rmn_remote_curses` | `UncheckedAccount<'info>` | No | PDA containing list of curses chain selectors and global curses.
**Derivation**: `["curses"]` under the `rmn_remote` program. | +| `rmn_remote_config` | `UncheckedAccount<'info>` | No | RMN config PDA, containing configuration that control how curse verification works.
**Derivation**: `["config"]` under the `rmn_remote` program. | +| `token_pools_signer` | `UncheckedAccount<'info>` | Yes | PDA with the authority to **CPI** into token pool logic (mint/burn, lock/release).
**Derivation**: `["external_token_pools_signer"]` under the `ccip_router` program. | +| `remaining_accounts` | `&[AccountInfo]` (slice) | Yes | You pass extra accounts for each token you wish to transfer (does not include fee tokens). Typically includes the sender ATA, the token pool config, token admin registry PDAs… etc. | + +##### How `remaining_accounts` and `token_indexes` Work + +When you call the Router's `ccip_send` instruction, you pass: + +1. A list of `token_amounts` you want to transfer cross-chain. +1. A slice of `remaining_accounts` containing the per-token PDAs (e.g., user token ATA, pool config, token admin registry PDA, etc.). +1. A `token_indexes` array tells the Router where in `remaining_accounts` each token's sub-slice begins. + +###### Reason for `remaining_accounts` + +On Solana, each Anchor instruction has a fixed set of named accounts. However, CCIP must handle any number of tokens, each requiring many accounts. Rather than define a massive static context, the Router uses Anchor's dynamic `ctx.remaining_accounts`: All token-specific accounts are packed into one slice. + +###### Reason for `token_indexes` + +The Router must figure out which segment of that slice corresponds to token #0, token #1, etc. So you provide an integer offset in `token_indexes[i]` indicating where the `i`th token's accounts begin inside `remaining_accounts`. + +The Router: + +- Slices out `[start..end)` for the `i`th token's accounts. The subslice is from start up to but **not** including end. This is how you indicate that the token i's accounts occupy positions start, start+1, …, end-1. +- Validates each account. +- Calls the appropriate token pool to the lock-or-burn operation on them. + +###### Structure of Each Token's Sub-slice + +Inside each token's sub-slice, the Router expects: + +1. The user's token account (ATA). +1. The token's chain PDAs. +1. Lookup table PDAs, token admin registry, pool program, pool config, pool signer, token program, the mint, etc. + +In total, it is typically **12 or more** accounts per token. Repeat that "per-token chunk" of ~12 accounts for each token if you have multiple tokens. These accounts are extracted in this order: + +| Index | Account | Description | +| ----- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 0 | `user_token_account` | ATA for `(authority, mint, token_program)`. | +| 1 | `token_billing_config` | Per-destination blockchain-specific fee overrides for a given token.
**Note**: In most cases, tokens do not have a custom billing fee structure. In these cases, CCIP uses the fallback default fee configuration.
PDA `["per_chain_per_token_config", dest_chain_selector, mint]` under the fee_quoter program. | +| 2 | `pool_chain_config` | PDA `["ccip_tokenpool_chainconfig", dest_chain_selector, mint]` under fee_quoter program. | +| 3 | `lookup_table` | Address Lookup Table that the token's admin registry claims. Must match the Token Admin Registry's `lookup_table` field. | +| 4 | `token_admin_registry` | PDA `["token_admin_registry", mint]` under the ccip_router program. | +| 5 | `pool_program` | The Token Pool program ID (for CPI calls). | +| 6 | `pool_config` | PDA `[ "ccip_tokenpool_config", mint ]` under the pool_program. | +| 7 | `pool_token_account` | ATA for (`pool_signer`, `mint`, `token_program`). | +| 8 | `pool_signer` | PDA `[ "ccip_tokenpool_signer", mint ]` under the pool_program. | +| 9 | `token_program` | Token program ID (e.g. `spl_token` or 2022). Also, it must match the mint's `owner`. | +| 10 | `mint` | The SPL Mint (public key) for this token. | +| 11 | `fee_token_config` | A token billing configuration account under the Fee Quoter program. It contains settings such as whether there is a specific pricing for the token, its pricing in USD, and any premium multipliers.
**Note**: In most cases, tokens do not have a custom billing fee structure. In these cases, CCIP uses the fallback default fee configuration.
PDA `["fee_billing_token_config", mint]` under the fee_quoter program. | +| 12 | `…` | Additional accounts are passed if required by the token pool. | + +###### Examples + +**One Token Transfer** + +Suppose you want to send **one token** (`myMint`) cross-chain: + +1. `token_amounts`: length = 1, e.g. `[{ token: myMint_pubkey, amount: 1000000 }]`. +1. `token_indexes`: `[1]`. Meaning: + - The 0th token's remaining_accounts sub-slice will be `[token_indexes[0] .. endOfArray)`, i.e. `[1..]`. + - The user's Associated Token Account (ATA) for that token is found at `remaining_accounts[0]`. +1. Your `remaining_accounts` must have: + - **1** user's ATA (the sender ATA for the single token). + - **12** pool-related accounts (pool config, chain config, token program, etc.). + That is **13** total. + + + +**Two Token Transfers** + +Suppose you want to send **two tokens** (`mintA` and `mintB`) cross-chain: + +1. `token_amounts`: length = 2, e.g. `[{ token: mintA_pubkey, amount: 1000000 },{ token: mintB_pubkey, amount: 2000000 } ]`. +1. `token_indexes` must be length=2 since there are two tokens, and token_indexes = [2, 14]. Explanation: + - After we skip the user ATAs at indices [0..2), we want the next 12 accounts for the first token to lie in `[2..14)`, and then the next 12 for the second token to lie in `[14..end)`. + - The Router program will use token_indexes: + 1. For the first token: The sub slice is [2..14). + 1. For the second token: The sub slice is [14…endOfArray). +1. Your `remaining_accounts` must have: + - **2** user ATAs (one for `mintA`, one for `mintB`). + - **12** pool accounts for `mintA`. + - **12** pool accounts for `mintB`. + +Thus `2 + 12 + 12 = 26` accounts in `remaining_accounts`. + + + +#### `get_fee` + +Queries the Router for the fee required to send a cross-chain message. This is a permissionless call that calculates fees without verifying curse status to avoid RMN CPI overhead. + +```rust +fn get_fee( + ctx: Context, + dest_chain_selector: u64, + message: SVM2AnyMessage, +) -> Result; +``` + +##### Parameters + +| Name | Type | Description | +| ---------------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `dest_chain_selector` | `u64` | The unique CCIP blockchain identifier of the destination blockchain. | +| `message` | `SVM2AnyMessage` | The message for which to calculate fees. Read [Messages](/ccip/api-reference/svm/v0.1.1/messages#svm2anymessage) for more details. | + +##### Return Value + +| Type | Description | +| --------------------------- | -------------------------------------------------------------------- | +| `GetFeeResult` | Contains fee amount, fee in juels (LINK), and the fee token address. | + +```rust +struct GetFeeResult { + pub amount: u64, // Fee amount in the specified fee token + pub juels: u128, // Fee value converted to LINK juels + pub token: Pubkey, // The fee token address +} +``` + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| --------------------------------- | -------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `config` | `Account` | No | Router config PDA.
**Derivation**: `["config"]` under the `ccip_router` program. | +| `dest_chain_state` | `Account` | No | Per-destination blockchain PDA for retrieving lane version.
**Derivation**: `["dest_chain_state", dest_chain_selector]` under the `ccip_router` program. | +| `fee_quoter` | `UncheckedAccount<'info>` | No | The **Fee Quoter** program ID. | +| `fee_quoter_config` | `UncheckedAccount<'info>` | No | The global Fee Quoter config PDA.
**Derivation**: `["config"]` under the `fee_quoter` program. | +| `fee_quoter_dest_chain` | `UncheckedAccount<'info>` | No | Per-destination blockchain PDA in the Fee Quoter program.
**Derivation**: `["dest_chain", dest_chain_selector]` under the `fee_quoter` program. | +| `fee_quoter_billing_token_config` | `UncheckedAccount<'info>` | No | Fee token billing configuration PDA.
**Derivation**: `["fee_billing_token_config", fee_token_mint]` under the `fee_quoter` program. Uses `native_mint::ID` if paying with native SOL. | +| `fee_quoter_link_token_config` | `UncheckedAccount<'info>` | No | LINK token billing configuration PDA for fee conversion.
**Derivation**: `["fee_billing_token_config", link_token_mint]` under the `fee_quoter` program. | +| `remaining_accounts` | `&[AccountInfo]` (slice) | No | Per-token billing configurations. See [Remaining Accounts Structure](#remaining-accounts-structure-for-get_fee) below. | + +##### Remaining Accounts Structure for `get_fee` + +The `remaining_accounts` must be provided in this specific order for each token being transferred: + +1. **Billing Token Config**: Token-specific billing configuration under the Fee Quoter program + - **Derivation**: `["fee_billing_token_config", token_mint]` under the `fee_quoter` program +2. **Per-Chain Per-Token Config**: Chain and token specific fee overrides under the Fee Quoter program + - **Derivation**: `["per_chain_per_token_config", dest_chain_selector, token_mint]` under the `fee_quoter` program + +**Example for 2 tokens:** + +``` +remaining_accounts = [ + billing_config_token_A, // Token A billing config + per_chain_config_token_A, // Token A per-chain config + billing_config_token_B, // Token B billing config + per_chain_config_token_B, // Token B per-chain config +] +``` + +##### Usage Notes + +- **Permissionless**: Anyone can call this instruction to query fees +- **No Curse Check**: Does not verify RMN curse status for performance +- **Fee Calculation**: Returns both the fee amount in the specified token and the equivalent value in LINK juels +- **Token Support**: Supports both native SOL and SPL token fee payments + +### Token Administration + +These instructions manage token administrator roles and token registration with CCIP. + +#### `owner_propose_administrator` + +Proposes a token administrator for a given SPL token. This is used for self-service registration when you control the token's mint authority. + +```rust +fn owner_propose_administrator( + ctx: Context, + token_admin_registry_admin: Pubkey, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ----------------------------------------- | --------------------- | --------------------------------------------------- | +| `token_admin_registry_admin` | `Pubkey` | The public key of the proposed token administrator. | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ---------------------- | -------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------ | +| `config` | `Account` | No | Router config PDA.
**Derivation**: `["config"]` under the `ccip_router` program. | +| `token_admin_registry` | `Account` | Yes | Token admin registry PDA to initialize.
**Derivation**: `["token_admin_registry", mint]` under the `ccip_router` program. | +| `mint` | `InterfaceAccount<'info, Mint>` | No | The SPL token mint for which to propose an administrator. | +| `authority` | `Signer<'info>` | Yes | Must be the mint authority of the SPL token. | +| `system_program` | `Program<'info, System>` | No | Standard System Program. | + +##### Authorization + +- **Caller**: Must be the SPL token's `mint_authority` +- **Registry State**: TokenAdminRegistry PDA must not already exist for this mint + +#### `owner_override_pending_administrator` + +Overrides the pending administrator before they accept the role. Can only be called by the token's mint authority. + +```rust +fn owner_override_pending_administrator( + ctx: Context, + token_admin_registry_admin: Pubkey, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ----------------------------------------- | --------------------- | ------------------------------------------------- | +| `token_admin_registry_admin` | `Pubkey` | The public key of the new proposed administrator. | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ---------------------- | -------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------- | +| `config` | `Account` | No | Router config PDA.
**Derivation**: `["config"]` under the `ccip_router` program. | +| `token_admin_registry` | `Account` | Yes | Existing token admin registry PDA.
**Derivation**: `["token_admin_registry", mint]` under the `ccip_router` program. | +| `mint` | `InterfaceAccount<'info, Mint>` | No | The SPL token mint. | +| `authority` | `Signer<'info>` | Yes | Must be the mint authority of the SPL token. | +| `system_program` | `Program<'info, System>` | No | Standard System Program. | + +##### Authorization + +- **Caller**: Must be the SPL token's `mint_authority` +- **Registry State**: TokenAdminRegistry PDA must exist but have no accepted administrator yet + +#### `ccip_admin_propose_administrator` + +Proposes a token administrator via CCIP governance. Used when the caller cannot access the mint authority. + +```rust +fn ccip_admin_propose_administrator( + ctx: Context, + token_admin_registry_admin: Pubkey, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ----------------------------------------- | --------------------- | --------------------------------------------------- | +| `token_admin_registry_admin` | `Pubkey` | The public key of the proposed token administrator. | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ---------------------- | -------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------ | +| `config` | `Account` | No | Router config PDA.
**Derivation**: `["config"]` under the `ccip_router` program. | +| `token_admin_registry` | `Account` | Yes | Token admin registry PDA to initialize.
**Derivation**: `["token_admin_registry", mint]` under the `ccip_router` program. | +| `mint` | `InterfaceAccount<'info, Mint>` | No | The SPL token mint for which to propose an administrator. | +| `authority` | `Signer<'info>` | Yes | Must be the Router program's upgrade authority. | +| `system_program` | `Program<'info, System>` | No | Standard System Program. | + +##### Authorization + +- **Caller**: Must be the Router program's upgrade authority +- **Registry State**: TokenAdminRegistry PDA must not already exist for this mint + +#### `accept_admin_role_token_admin_registry` + +Accepts the administrator role for a token. Must be called by the pending administrator to finalize registration. + +```rust +fn accept_admin_role_token_admin_registry( + ctx: Context, +) -> Result<()>; +``` + +##### Parameters + +This instruction takes no additional parameters. + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ---------------------- | -------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------- | +| `config` | `Account` | No | Router config PDA.
**Derivation**: `["config"]` under the `ccip_router` program. | +| `token_admin_registry` | `Account` | Yes | Existing token admin registry PDA.
**Derivation**: `["token_admin_registry", mint]` under the `ccip_router` program. | +| `mint` | `InterfaceAccount<'info, Mint>` | No | The SPL token mint. | +| `authority` | `Signer<'info>` | Yes | Must be the pending administrator listed in the token admin registry. | + +##### Authorization + +- **Caller**: Must match the `pending_administrator` field in the TokenAdminRegistry PDA +- **Registry State**: TokenAdminRegistry PDA must exist with a pending administrator + +#### `transfer_admin_role_token_admin_registry` + +Transfers the administrator role to a new administrator. This is a two-step process requiring the new admin to accept. + +```rust +fn transfer_admin_role_token_admin_registry( + ctx: Context, + new_admin: Pubkey, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ------------------------ | --------------------- | ---------------------------------------- | +| `new_admin` | `Pubkey` | The public key of the new administrator. | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ---------------------- | -------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------- | +| `config` | `Account` | No | Router config PDA.
**Derivation**: `["config"]` under the `ccip_router` program. | +| `token_admin_registry` | `Account` | Yes | Existing token admin registry PDA.
**Derivation**: `["token_admin_registry", mint]` under the `ccip_router` program. | +| `mint` | `InterfaceAccount<'info, Mint>` | No | The SPL token mint. | +| `authority` | `Signer<'info>` | Yes | Must be the current administrator of the token admin registry. | + +##### Authorization + +- **Caller**: Must be the current `administrator` listed in the TokenAdminRegistry PDA +- **Registry State**: TokenAdminRegistry PDA must exist with an active administrator + +#### `set_pool` + +Sets the Address Lookup Table that defines the token pool for cross-chain transfers. This enables or disables a token for CCIP. + +```rust +fn set_pool( + ctx: Context, + writable_indexes: Vec, +) -> Result<()>; +``` + +##### Parameters + +| Name | Type | Description | +| ------------------------------- | ---------------------- | -------------------------------------------------------------------------------------------- | +| `writable_indexes` | `Vec` | Bitmap of indexes in the lookup table that should be marked as writable during transactions. | + +##### Context (Accounts) + +| Field | Type | Writable? | Description | +| ---------------------- | -------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------- | +| `config` | `Account` | No | Router config PDA.
**Derivation**: `["config"]` under the `ccip_router` program. | +| `token_admin_registry` | `Account` | Yes | Existing token admin registry PDA.
**Derivation**: `["token_admin_registry", mint]` under the `ccip_router` program. | +| `mint` | `InterfaceAccount<'info, Mint>` | No | The SPL token mint. | +| `pool_lookuptable` | `UncheckedAccount<'info>` | No | Address Lookup Table containing the token pool accounts. Pass zero address to delist token from CCIP. | +| `authority` | `Signer<'info>` | Yes | Must be the current administrator of the token admin registry. | + +##### Authorization + +- **Caller**: Must be the current `administrator` listed in the TokenAdminRegistry PDA +- **Pool Validation**: If not zero address, the lookup table must contain at least the minimum required accounts + +##### Pool Status + +- **Enable Token**: Set `pool_lookuptable` to a valid Address Lookup Table with required pool accounts +- **Disable Token**: Set `pool_lookuptable` to zero address (`Pubkey::default()`) to delist from CCIP + +##### Address Lookup Table Requirements + +The `pool_lookuptable` must contain exactly these accounts in the specified order for proper CCIP token pool operations: + +| Index | Account | Derivation | Description | +| ----- | --------------------------- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | +| 0 | **Lookup Table Address** | N/A | The Address Lookup Table itself | +| 1 | **Token Admin Registry** | `["token_admin_registry", mint]` under Router program | Registry PDA for this token | +| 2 | **Pool Program** | N/A | The token pool program ID (e.g., BurnMint or LockRelease Token Pool program) | +| 3 | **Pool Config** | `["ccip_tokenpool_config", mint]` under pool program | Token-specific pool configuration and settings | +| 4 | **Pool Token Account** | ATA of (pool_signer, mint, token_program) | Associated Token Account holding pool's tokens | +| 5 | **Pool Signer** | `["ccip_tokenpool_signer", mint]` under pool program | PDA with authority for token operations | +| 6 | **Token Program** | N/A | SPL Token program (`TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) or Token-2022 program (`TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`) | +| 7 | **Token Mint** | N/A | The SPL token mint address | +| 8 | **Fee Token Config** | `["fee_billing_token_config", mint]` under Fee Quoter | Fee token billing configuration PDA | +| 9 | **CCIP Router Pool Signer** | `["external_token_pools_signer", pool_program]` under Router | Router's signer PDA for the pool | + +**Notes:** + +- The ALT contains exactly 10 accounts as shown above +- Custom token pools may require additional accounts beyond these core 10 +- All PDA derivations must use the correct program IDs +- Pool Token Account must be the proper Associated Token Account for the Pool Signer +- Writable permissions are specified via the `writable_indexes` parameter + +**Creating the ALT:** + +1. Create a new Address Lookup Table +1. Add accounts in the exact order specified above +1. Ensure all PDA derivations are correct for your specific token and pool program +1. Call `set_pool` with the ALT address and appropriate `writable_indexes` + +For PDA derivation examples and account validation details, see the [Token Pool documentation](/ccip/concepts/cross-chain-token/svm/token-pools). diff --git a/src/content/ccip/api-reference/svm/v1.6.0/errors.mdx b/src/content/ccip/api-reference/svm/v1.6.0/errors.mdx deleted file mode 100644 index 94be1310eeb..00000000000 --- a/src/content/ccip/api-reference/svm/v1.6.0/errors.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -section: ccip -date: Last Modified -title: "CCIP v1.6.0 SVM Errors API Reference" -metadata: - description: "API documentation for CCIP errors on SVM-based blockchains like Solana." ---- - -import { Aside } from "@components" -import CcipCommon from "@features/ccip/CcipCommon.astro" - -## Errors - -### Router - -#### ccip_send - -| Error Code | Symbol | Description | -| ---------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **7001** | `InvalidInputsMint` | The mint account input is invalid. | -| **7002** | `InvalidVersion` | The on-chain state has a version number higher than expected or zero (uninitialized) when it shouldn't be. | -| **7003** | `FeeTokenMismatch` | The fee token doesn't match the minted token used for the transfer. | -| **7005** | `ReachedMaxSequenceNumber` | The sequence number cannot be incremented further (u64 overflow). This is very unlikely. | -| **7006** | `InvalidInputsTokenIndices` | The sub-slice token index calculations are invalid, or `token_indexes.len()` doesn't match the number of tokens. | -| **7007** | `InvalidInputsPoolAccounts` | The passed "pool sub-slice" accounts do not match the expected PDAs for the token pool's configuration. | -| **7008** | `InvalidInputsTokenAccounts` | The user token or pool token account is invalid (wrong ATAs or minted by a different token). | -| **7009** | `InvalidInputsConfigAccounts` | The required config PDAs do not match (e.g., the "billing" config or the "pool chain config" for that chain). | -| **7010** | `InvalidInputsTokenAdminRegistryAccounts` | The `token_admin_registry` passed does not match the expected PDA. | -| **7011** | `InvalidInputsLookupTableAccounts` | The Address Lookup Table (ALT) provided is invalid or does not match what the `token_admin_registry` expects. | -| **7012** | `InvalidInputsLookupTableAccountWritable` | One or more accounts in the lookup table are incorrectly marked as writable / non-writable. | -| **7013** | `InvalidInputsTokenAmount` | An attempt was made to send a token amount of zero. | -| **7015** | `InvalidInputsAtaAddress` | The associated token account address does not match what was expected. | -| **7016** | `InvalidInputsAtaWritable` | If the user's fee-token ATA is not flagged as writable, we need to debit it. | -| **7018** | `InsufficientLamports` | Users paying with native SOL have insufficient lamports to cover the required fee transfer. | -| **7019** | `InsufficientFunds` | Insufficient funds in a token account. | -| **7020** | `SourceTokenDataTooLarge` | The returned "dest_pool_data" from `lockOrBurnOut` is larger than the allowed `CCIP_LOCK_OR_BURN_V1_RET_BYTES`, or larger than the `dest_bytes_overhead`. | -| **7023** | `SenderNotAllowed` | The sender (caller) is not in the `allowed_senders` list for that destination chain, and the allow-list is enabled. | diff --git a/src/content/ccip/api-reference/svm/v1.6.0/events.mdx b/src/content/ccip/api-reference/svm/v1.6.0/events.mdx deleted file mode 100644 index e49cf24d07e..00000000000 --- a/src/content/ccip/api-reference/svm/v1.6.0/events.mdx +++ /dev/null @@ -1,36 +0,0 @@ ---- -section: ccip -date: Last Modified -title: "CCIP v1.6.0 SVM Events API Reference" -metadata: - description: "API documentation for CCIP events on SVM-based blockchains like Solana." ---- - -import { Aside } from "@components" -import CcipCommon from "@features/ccip/CcipCommon.astro" - -## Events - -### Router - -#### `ccip_send` - -When the `ccip_send` instruction completes successfully, the Router emits a single event, `CCIPMessageSent`. - -```rust -#[event] -pub struct CCIPMessageSent { - /// The chain selector identifying the destination chain. - pub dest_chain_selector: u64, - /// The sequence number for this message, specific to the destination chain. - pub sequence_number: u64, - /// The full SVM2AnyRampMessage describing the cross-chain payload and tokens being sent. - pub message: SVM2AnyRampMessage, -} -``` - -| Field | Type | Description | -| --------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `dest_chain_selector` | `u64` | The **chain selector** for the destination chain. Think of it as the chain's unique ID in the CCIP ecosystem (e.g., 1 for Ethereum Mainnet, 10 for Optimism, etc.). | -| `sequence_number` | `u64` | Monotonically increments each time you successfully call `ccip_send` for a particular destination chain. It is unique **per** chain in the sense that each chain has its own separate sequence. | -| `message` | `SVM2AnyRampMessage` | The cross-chain message payload itself. It includes:
• The sender's address
• Arbitrary `data` payload
• Token transfer details
• Fees and more | diff --git a/src/content/ccip/api-reference/svm/v1.6.0/index.mdx b/src/content/ccip/api-reference/svm/v1.6.0/index.mdx deleted file mode 100644 index 28279e4db7b..00000000000 --- a/src/content/ccip/api-reference/svm/v1.6.0/index.mdx +++ /dev/null @@ -1,28 +0,0 @@ ---- -section: ccip -date: Last Modified -title: "CCIP v1.6.0 SVM API Reference" -metadata: - description: "API reference documentation for Chainlink CCIP v1.6.0 on SVM-based blockchains like Solana. Includes message structures, router functionality, events, and error handling for cross-chain interoperability." -isIndex: true ---- - -import { Aside } from "@components" -import CcipCommon from "@features/ccip/CcipCommon.astro" - - - -## API References - -### Core Components - -- [Messages](/ccip/api-reference/svm/v1.6.0/messages) - Message structures and extra args for cross-chain messaging -- [Router](/ccip/api-reference/svm/v1.6.0/router) - Instructions for sending messages through CCIP on Solana -- [Events](/ccip/api-reference/svm/v1.6.0/events) - Event emissions for tracking cross-chain messages - -### Error Handling - -- [Errors](/ccip/api-reference/svm/v1.6.0/errors) - Comprehensive list of CCIP error codes for SVM blockchains diff --git a/src/content/ccip/api-reference/svm/v1.6.0/router.mdx b/src/content/ccip/api-reference/svm/v1.6.0/router.mdx deleted file mode 100644 index c1d15243249..00000000000 --- a/src/content/ccip/api-reference/svm/v1.6.0/router.mdx +++ /dev/null @@ -1,152 +0,0 @@ ---- -section: ccip -date: Last Modified -title: "CCIP v1.6.0 SVM Router API Reference" -metadata: - description: "API documentation for CCIP router on SVM-based blockchains like Solana." ---- - -import { Aside, ClickToZoom } from "@components" -import CcipCommon from "@features/ccip/CcipCommon.astro" - -## Router - -Below is a complete API reference for the `ccip_send` instruction from the CCIP Router program. - -### `ccip_send` - -This instruction is the entry point for sending a cross-chain message from an SVM-based blockchain to a specified destination blockchain. - -```rust -fn ccip_send( - ctx: Context, - dest_chain_selector: u64, - message: SVM2AnyMessage, - token_indexes: Vec -) -> Result<[u8; 32]>; -``` - -#### Parameters - -| Name | Type | Description | -| ---------------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------- | -| `dest_chain_selector` | `u64` | The unique CCIP blockchain identifier of the destination blockchain. | -| `message` | `SVM2AnyMessage` | Read [Messages](/ccip/api-reference/svm/v1.6.0/messages#svm2anymessage) for more details. | -| `token_indexes` | `Vec` | Index offsets slicing the remaining accounts so each token's subset can be grouped (see [Context](#context-accounts)). | - -#### Context (Accounts) - -These are the required accounts passed alongside the instructions. For relevant PDAs, the instructions on how to derive seeds are given below. - -| Field | Type | Writable? | Description | -| ------------------------------------------------ | ---------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `config` | `Account` | No | Router config PDA.
**Derivation**: `["config"]` under the `ccip_router` program. | -| `dest_chain_state` | `Account` | Yes | Per-destination blockchain PDA for `sequence_number`, chain config, etc.
**Derivation**: `["dest_chain_state", dest_chain_selector]` under the `ccip_router` program. | -| `nonce` | `Account` | Yes | Current nonce PDA for `(authority, dest_chain_selector)`.
**Derivation**: `["nonce", dest_chain_selector, authority_pubkey]` under the `ccip_router` program. | -| `authority` | `Signer<'info>` | Yes | The user/wallet paying for the `ccip_send` transaction. Also, it must match the seeds in `nonce`. | -| `system_program` | `Program<'info, System>` | No | Standard System Program. | -| `fee_token_program` | `Interface<'info, TokenInterface>` | No | The token program used for fee payment (e.g., SPL Token). If paying with native SOL, this is just the `SystemProgramID`. | -| `fee_token_mint` | `InterfaceAccount<'info, Mint>` | No | Fee token mint. If paying in SPL, pass your chosen token mint. If paying in native SOL, a special "zero" mint (`Pubkey::default()`) or "[native mint](https://docs.rs/spl-token/latest/spl_token/native_mint/constant.ID.html)" (`native_mint::ID`) is used. | -| `fee_token_user_associated_account` | `UncheckedAccount<'info>` | Yes | If fees are paid in SPL, this is the user's ATA.
**Derivation**: It is derived via the Associated Token Program seeds: `[authority_pubkey, fee_token_program.key(), fee_token_mint.key() ]` under the relevant Token Program (Make sure you use the correct token program ID—**Token-2022** vs.SPL Token). If paying with native SOL, pass the zero address (`Pubkey::default())` and do not mark it writable. | -| `fee_token_receiver` | `InterfaceAccount<'info, TokenAccount>` | Yes | The ATA where all the fees are collected.
**Derivation**: from `[fee_billing_signer,fee_token_program.key(),fee_token_mint.key()]`. | -| `fee_billing_signer` | `UncheckedAccount<'info>` | No | PDA is the router's billing authority for transferring fees (native SOL or SPL tokens).
from fee_token_user_associated_account to fee_token_receiver.
**Derivation**: `["fee_billing_signer"]` under the `ccip_router` program. | -| `fee_quoter` | `UncheckedAccount<'info>` | No | The **Fee Quoter** program ID. | -| `fee_quoter_config` | `UncheckedAccount<'info>` | No | The global Fee Quoter config PDA.
**Derivation**: `["config"]` under the `fee_quoter` program. | -| `fee_quoter_dest_chain` | `UncheckedAccount<'info>` | No | Per-destination blockchain PDA in the Fee Quoter program. It stores chain-specific configuration (gas price data, limits, etc.) for SVM2Any messages.
**Derivation**: `["dest_chain",dest_chain_selector]` under the `fee_quoter` program. | -| `fee_quoter_billing_token_config` | `UncheckedAccount<'info>` | No | A per-fee-token PDA in the Fee Quoter program stores token-specific parameters (price data, billing premiums, etc.) used to calculate fees.
**Derivation**: If the message pays fees in native SOL, the seed uses the `native_mint::ID`; otherwise, it uses the SPL token's `mint` public key. `["fee_billing_token_config", seed]` under the `fee_quoter` program. | -| `fee_quoter_link_token_config` | `UncheckedAccount<'info>` | No | PDA containing the Fee Quoter's LINK token billing configuration (LINK price data, premium multipliers, etc.). The fee token amount is converted into "juels" using LINK's valuation from this account during fee calculation.
**Derivation**: `["fee_billing_token_config", link_token_mint]` under the `fee_quoter` program. | -| `rmn_remote` | `UncheckedAccount<'info>` | No | The RMN program ID used to verify if a given chain is cursed. | -| `rmn_remote_curses` | `UncheckedAccount<'info>` | No | PDA containing list of curses chain selectors and global curses.
**Derivation**: `["curses"]` under the `rmn_remote` program. | -| `rmn_remote_config` | `UncheckedAccount<'info>` | No | RMN config PDA, containing configuration that control how curse verification works.
**Derivation**: `["config"]` under the `rmn_remote` program. | -| `token_pools_signer` | `UncheckedAccount<'info>` | Yes | PDA with the authority to **CPI** into token pool logic (mint/burn, lock/release).
**Derivation**: `["external_token_pools_signer"]` under the `ccip_router` program. | -| `remaining_accounts` | `&[AccountInfo]` (slice) | Yes | You pass extra accounts for each token you wish to transfer (does not include fee tokens). Typically includes the sender ATA, the token pool config, token admin registry PDAs… etc. | - -#### How `remaining_accounts` and `token_indexes` Work - -When you call the Router's `ccip_send` instruction, you pass: - -1. A list of `token_amounts` you want to transfer cross-chain. -1. A slice of `remaining_accounts` containing the per-token PDAs (e.g., user token ATA, pool config, token admin registry PDA, etc.). -1. A `token_indexes` array tells the Router where in `remaining_accounts` each token's sub-slice begins. - -##### Reason for `remaining_accounts` - -On Solana, each Anchor instruction has a fixed set of named accounts. However, CCIP must handle any number of tokens, each requiring many accounts. Rather than define a massive static context, the Router uses Anchor's dynamic `ctx.remaining_accounts`: All token-specific accounts are packed into one slice. - -##### Reason for `token_indexes` - -The Router must figure out which segment of that slice corresponds to token #0, token #1, etc. So you provide an integer offset in `token_indexes[i]` indicating where the `i`th token's accounts begin inside `remaining_accounts`. - -The Router: - -- Slices out `[start..end)` for the `i`th token's accounts. The subslice is from start up to but **not** including end. This is how you indicate that the token i's accounts occupy positions start, start+1, …, end-1. -- Validates each account. -- Calls the appropriate token pool to the lock-or-burn operation on them. - -##### Structure of Each Token's Sub-slice - -Inside each token's sub-slice, the Router expects: - -1. The user's token account (ATA). -1. The token's chain PDAs. -1. Lookup table PDAs, token admin registry, pool program, pool config, pool signer, token program, the mint, etc. - -In total, it is typically **12 or more** accounts per token. Repeat that "per-token chunk" of ~12 accounts for each token if you have multiple tokens. These accounts are extracted in this order: - -| Index | Account | Description | -| ----- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 0 | `user_token_account` | ATA for `(authority, mint, token_program)`. | -| 1 | `token_billing_config` | Per-destination blockchain-specific fee overrides for a given token.
**Note**: In most cases, tokens do not have a custom billing fee structure. In these cases, CCIP uses the fallback default fee configuration.
PDA `["per_chain_per_token_config", dest_chain_selector, mint]` under the fee_quoter program. | -| 2 | `pool_chain_config` | PDA `["ccip_tokenpool_chainconfig", dest_chain_selector, mint]` under fee_quoter program. | -| 3 | `lookup_table` | Address Lookup Table that the token's admin registry claims. Must match the Token Admin Registry's `lookup_table` field. | -| 4 | `token_admin_registry` | PDA `["token_admin_registry", mint]` under the ccip_router program. | -| 5 | `pool_program` | The Token Pool program ID (for CPI calls). | -| 6 | `pool_config` | PDA `[ "ccip_tokenpool_config", mint ]` under the pool_program. | -| 7 | `pool_token_account` | ATA for (`pool_signer`, `mint`, `token_program`). | -| 8 | `pool_signer` | PDA `[ "ccip_tokenpool_signer", mint ]` under the pool_program. | -| 9 | `token_program` | Token program ID (e.g. `spl_token` or 2022). Also, it must match the mint's `owner`. | -| 10 | `mint` | The SPL Mint (public key) for this token. | -| 11 | `fee_token_config` | A token billing configuration account under the Fee Quoter program. It contains settings such as whether there is a specific pricing for the token, its pricing in USD, and any premium multipliers.
**Note**: In most cases, tokens do not have a custom billing fee structure. In these cases, CCIP uses the fallback default fee configuration.
PDA `["fee_billing_token_config", mint]` under the fee_quoter program. | -| 12 | `…` | Additional accounts are passed if required by the token pool. | - -##### Examples - -###### One Token Transfer - -Suppose you want to send **one token** (`myMint`) cross-chain: - -1. `token_amounts`: length = 1, e.g. `[{ token: myMint_pubkey, amount: 1000000 }]`. -1. `token_indexes`: `[1]`. Meaning: - - The 0th token's remaining_accounts sub-slice will be `[token_indexes[0] .. endOfArray)`, i.e. `[1..]`. - - The user's Associated Token Account (ATA) for that token is found at `remaining_accounts[0]`. -1. Your `remaining_accounts` must have: - - **1** user's ATA (the sender ATA for the single token). - - **12** pool-related accounts (pool config, chain config, token program, etc.). - That is **13** total. - - - -###### Two Token Transfers - -Suppose you want to send **two tokens** (`mintA` and `mintB`) cross-chain: - -1. `token_amounts`: length = 2, e.g. `[{ token: mintA_pubkey, amount: 1000000 },{ token: mintB_pubkey, amount: 2000000 } ]`. -1. `token_indexes` must be length=2 since there are two tokens, and token_indexes = [2, 14]. Explanation: - - After we skip the user ATAs at indices [0..2), we want the next 12 accounts for the first token to lie in `[2..14)`, and then the next 12 for the second token to lie in `[14..end)`. - - The Router program will use token_indexes: - 1. For the first token: The sub slice is [2..14). - 2. For the second token: The sub slice is [14…endOfArray). -1. Your `remaining_accounts` must have: - - **2** user ATAs (one for `mintA`, one for `mintB`). - - **12** pool accounts for `mintA`. - - **12** pool accounts for `mintB`. - -Thus `2 + 12 + 12 = 26` accounts in `remaining_accounts`. - - diff --git a/src/content/ccip/concepts/architecture/onchain/svm/components.mdx b/src/content/ccip/concepts/architecture/onchain/svm/components.mdx index b3ab1a8d29a..90058f5ac3d 100644 --- a/src/content/ccip/concepts/architecture/onchain/svm/components.mdx +++ b/src/content/ccip/concepts/architecture/onchain/svm/components.mdx @@ -38,7 +38,7 @@ This section provides more detail on the Onchain components. **Sender Responsibilities**: - Prepare a structured CCIP Message. -- Include all required accounts in the transaction context, due to the SVM account model. To learn more, read the `ccip_send` [API reference](/ccip/api-reference/svm/v1.6.0/router). +- Include all required accounts in the transaction context, due to the SVM account model. To learn more, read the `ccip_send` [API reference](/ccip/api-reference/svm/v0.1.1/router). - Retrieve a fee estimate from the Router. - Call the Router to send the message, as described in the Message Lifecycle section. - Authorization Mechanisms: @@ -53,12 +53,12 @@ This section provides more detail on the Onchain components. **Receiver Considerations**: -- **Data Processing**: If the CCIP Message contains a bytes payload or a programmable token transfer, the receiver must be a program implementing the `ccip_receive` function with a specific discriminator. To learn more, read the `ccip_receive` [API reference](/ccip/api-reference/svm/v1.6.0/messages). +- **Data Processing**: If the CCIP Message contains a bytes payload or a programmable token transfer, the receiver must be a program implementing the `ccip_receive` function with a specific discriminator. To learn more, read the `ccip_receive` [API reference](/ccip/api-reference/svm/v0.1.1/messages). - **Security Validation**: The receiver program should validate that the caller is an authorized OffRamp by checking the `ALLOWED_OFFRAMP` PDA from the Router program. **Additional Resources**: -- CCIP provides program examples for a Sender/Receiver in the [Programs folder](https://github.com/smartcontractkit/chainlink-ccip/tree/contracts-ccip-release/1.6.0/chains/solana/contracts/programs). +- CCIP provides program examples for a Sender/Receiver in the [Programs folder](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs). ## Router @@ -195,7 +195,7 @@ The FeeQuoter is a central component in Chainlink CCIP that maintains token and - Token Pools are deployed by token developers and exist independently of the core CCIP programs. - Token Pools are programs that interact with SPL token programs. -- Token pools follow standard models (Lock/Release and Burn/Mint), with audited code available in the [CCIP repository](https://github.com/smartcontractkit/chainlink-ccip/tree/contracts-ccip-release/1.6.0/chains/solana/contracts/programs). +- Token pools follow standard models (Lock/Release and Burn/Mint), with audited code available in the [CCIP repository](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs). - For tokens requiring bespoke logic before burn/mint/lock/release, custom pools can be built on top of the base pools. More details are available in the CCT documentation. ## Risk Management Network diff --git a/src/content/ccip/concepts/best-practices/svm.mdx b/src/content/ccip/concepts/best-practices/svm.mdx index 2c798087683..354639b7da2 100644 --- a/src/content/ccip/concepts/best-practices/svm.mdx +++ b/src/content/ccip/concepts/best-practices/svm.mdx @@ -22,7 +22,7 @@ Before you deploy your cross-chain dApps to mainnet, make sure that your dApps f ## Verify destination chain -Before calling the router's `ccip_send` [instruction](/ccip/api-reference/svm/v1.6.0/router#ccip_send), ensure your code verifies that the destination chain is supported by the CCIP Router. Sending messages to unsupported chains will fail and potentially waste transaction fees. +Before calling the router's `ccip_send` [instruction](/ccip/api-reference/svm/v0.1.1/router#ccip_send), ensure your code verifies that the destination chain is supported by the CCIP Router. Sending messages to unsupported chains will fail and potentially waste transaction fees. You can programmatically verify destination chain support using Solana PDAs (Program Derived Addresses). Here below is a JavaScript example of how to verify destination chain support: @@ -57,17 +57,17 @@ async function isDestinationChainSupported(connection, routerProgramId, destinat ## Verify source chain -When implementing the `ccip_receive` [method](/ccip/api-reference/svm/v1.6.0/receiver#ccip_receive) in a program residing on the destination chain, ensure to verify the source chain of the incoming CCIP message. This verification ensures that CCIP messages can only be received from trusted source chains. +When implementing the `ccip_receive` [method](/ccip/api-reference/svm/v0.1.1/receiver#ccip_receive) in a program residing on the destination chain, ensure to verify the source chain of the incoming CCIP message. This verification ensures that CCIP messages can only be received from trusted source chains. ## Verify sender -When implementing the [`ccip_receive`](/ccip/api-reference/svm/v1.6.0/receiver#ccip_receive) instruction in a program residing on the destination chain, it's important to validate the sender of the incoming CCIP message. This check ensures that CCIP messages are received only from trusted sender addresses. +When implementing the [`ccip_receive`](/ccip/api-reference/svm/v0.1.1/receiver#ccip_receive) instruction in a program residing on the destination chain, it's important to validate the sender of the incoming CCIP message. This check ensures that CCIP messages are received only from trusted sender addresses. **Note**: Depending on your use case, this verification might not always be necessary. ## Verify authority and allowed offramp -When you implement the [`ccip_receive`](/ccip/api-reference/svm/v1.6.0/receiver#ccip_receive) instruction in the program residing on the destination chain, validate that the `authority` account is the correct Offramp CPI signer PDA and that `allowed_offramp` is the correct PDA owned by the router program. This verification ensures that only the authorized CCIP Offramp program can call the `ccip_receive` function. +When you implement the [`ccip_receive`](/ccip/api-reference/svm/v0.1.1/receiver#ccip_receive) instruction in the program residing on the destination chain, validate that the `authority` account is the correct Offramp CPI signer PDA and that `allowed_offramp` is the correct PDA owned by the router program. This verification ensures that only the authorized CCIP Offramp program can call the `ccip_receive` function. **Example in Rust**: @@ -130,7 +130,7 @@ When sending a CCIP message, you must select the appropriate `extra_args` struct - `SVMExtraArgsV1`: For Solana and other SVM-based destinations - `EVMExtraArgsV2`: For Ethereum and other EVM-based destinations -For the full parameter specification, refer to the [CCIP API Reference](/ccip/api-reference/svm/v1.6.0/messages#extra-args). +For the full parameter specification, refer to the [CCIP API Reference](/ccip/api-reference/svm/v0.1.1/messages#extra-args). ### Setting `compute_units` (SVM destinations) diff --git a/src/content/ccip/concepts/cross-chain-token/svm/architecture.mdx b/src/content/ccip/concepts/cross-chain-token/svm/architecture.mdx index d13cb8349b3..cc29817f708 100644 --- a/src/content/ccip/concepts/cross-chain-token/svm/architecture.mdx +++ b/src/content/ccip/concepts/cross-chain-token/svm/architecture.mdx @@ -4,13 +4,12 @@ date: Last Modified title: "Cross-Chain Token Standard - Architecture (SVM)" metadata: description: "Understand the CCIP CCT architecture on SVM chains like Solana. Learn how Router, OffRamp, Token, and Token Pool programs interact for cross-chain transfers." + excerpt: "CCIP architecture, SVM, Solana, Router, OffRamp, TokenAdminRegistry, token pools, cross-chain transfers, PDAs, Address Lookup Table, BurnMint, LockRelease, token administrator, CPI, Associated Token Accounts, program interactions, token pool authorization, SPL tokens, Token-2022" --- import { Aside, ClickToZoom } from "@components" import CcipCommon from "@features/ccip/CcipCommon.astro" - - The Cross-Chain Token (CCT) architecture offers a streamlined, self-service approach to enabling cross-chain operations to any token. The CCT standard is token logic agnostic, meaning token developers can deploy pre-audited token pool contracts to turn any SPL-compatible token into a CCT or deploy their own custom token pool contracts for bespoke token use cases. Importantly, CCTs do not require token developers to inherit any CCIP-specific code within their token's smart contract. The CCT standard leverages the Chainlink Cross-Chain Interoperability Protocol (CCIP) for cross-chain transfers and allows token developers to configure, manage, and transfer tokens across multiple blockchains. @@ -33,67 +32,125 @@ The architecture diagrams below provide an overview of how CCT fits within the C The CCIP architecture for SVM-based blockchains (e.g., Solana) is described on this page, where we focus specifically on cross-chain token management. +## Architecture + +This document explains the four key components of CCIP's Cross-Chain Token architecture on SVM: + +1. **Token**: SPL token requirements and registration for CCIP integration +1. **Token Pool**: Self-contained programs that execute cross-chain token operations +1. **Router**: Central coordinator for token administration and outbound transfers +1. **OffRamp**: Handler for inbound cross-chain token reception and release + +Each component builds on the previous, forming a secure, integrated system for cross-chain token transfers. The sections below are organized in dependency order - understanding each component provides the foundation for understanding how they work together in the complete architecture. + +## Token + +In the Cross-Chain Token (CCT) architecture, the token is an SPL Mint managed by either the standard SPL Token program or Token-2022 (Token Extensions). To enable cross-chain transfers, every token requires: + +1. **Registration**: Establishes a [token administrator](/ccip/concepts/cross-chain-token/overview#token-administrator) role and creates the TokenAdminRegistry [PDA](https://solana.com/docs/core/pda) that governs CCIP integration +1. **Pool-Specific Requirements**: Token requirements vary by chosen pool type: + - **BurnMint pools**: Must support `mint_to` and `burn` instructions; mint authority must be transferable to the pool + - **LockRelease pools**: Must support `transfer_checked` instruction; no mint authority requirements +1. **Compatibility**: Must support standard token interfaces including [Associated Token Accounts](https://spl.solana.com/associated-token-account) and provide decimal precision + +For detailed compatibility requirements and pool type selection guidance, see [Tokens documentation](/ccip/concepts/cross-chain-token/svm/tokens). For the complete registration process and administrator role management, see [Registration & Administration](/ccip/concepts/cross-chain-token/svm/registration-administration). + +## Token Pool + +A Token Pool is a self-contained program responsible for executing cross-chain token transfers for a specific token. Each token must have exactly one pool per blockchain, deployed using one of three approaches: self-serve mode (recommended), self-deployed standard pools, or custom pools. + + + +**Cross-Chain Token Operations:** + +- **Source Chain Operations** (called by Router during `ccip_send`): + + - **BurnMint pools**: Transfer tokens from sender's [ATA](https://spl.solana.com/associated-token-account) to pool's ATA, then burn from pool's ATA + - **LockRelease pools**: Lock tokens by transferring from sender's ATA to pool's [ATA](https://spl.solana.com/associated-token-account) + +- **Destination Chain Operations** (called by OffRamp during `execute`): + - **BurnMint pools**: Mint tokens directly to receiver's [ATA](https://spl.solana.com/associated-token-account) + - **LockRelease pools**: Release tokens by transferring from pool's [ATA](https://spl.solana.com/associated-token-account) to receiver's ATA + +For comprehensive implementation details, deployment approaches, and technical requirements, see [Token Pools documentation](/ccip/concepts/cross-chain-token/svm/token-pools). + ## Router The CCIP Router program is central to cross-chain token management. It has two flows: 1. **Token Administration** - - **TokenAdminRegistry (one PDA per mint):** Stores the designated CCIP token administrator public key for a specific token mint (distinct from the SPL token's own mint authority) and references the token's pool address lookup table (ALT). - - **Token Pool Address Lookup Table:** A Solana address lookup table that precisely defines the set of account addresses (including pool configuration PDAs, pool signer PDAs, and other required accounts) that are authorized for cross-chain operations with this token. + - **TokenAdminRegistry (one [PDA](https://solana.com/docs/core/pda) per mint):** Stores the designated CCIP [token administrator](/ccip/concepts/cross-chain-token/overview#token-administrator) public key for a specific token mint (distinct from the SPL token's own mint authority) and references the token's pool [address lookup table](https://docs.solana.com/developing/lookup-tables) (ALT). The PDA is derived using seeds `[seed::TOKEN_ADMIN_REGISTRY, mint.key().as_ref()]`. This registry is created during token registration (see [Token section](#token)) and governs all subsequent CCIP operations for that token. + - **Token Pool Address Lookup Table:** A Solana [address lookup table](https://docs.solana.com/developing/lookup-tables) that precisely defines the set of account addresses (including pool configuration [PDAs](https://solana.com/docs/core/pda), pool signer PDAs, and other required accounts) that are authorized for cross-chain operations with this token. For the complete list of required accounts and their exact order, see the [`set_pool` ALT requirements](/ccip/api-reference/svm/v0.1.1/router#address-lookup-table-requirements). - **Administrator Methods:** The token administrator can register or update cross-chain support for their mint through a sequence of instructions: - 1. `owner_propose_administrator`: Initiated by the mint authority to designate a token administrator. - 1. `accept_admin_role_token_admin_registry`: Confirmation by the proposed administrator to accept the role. - 1. `set_pool`: Links the token to a specific token pool configuration via an address lookup table. - - **Pool configuration:** The TokenAdminRegistry maps each mint to exactly one token pool configuration. This ensures that during cross-chain transfers, only the authorized token pool implementation can interact with the token. + + 1. [`owner_propose_administrator`](/ccip/api-reference/svm/v0.1.1/router#owner_propose_administrator): Initiated by the mint authority to designate a token administrator. + 1. [`accept_admin_role_token_admin_registry`](/ccip/api-reference/svm/v0.1.1/router#accept_admin_role_token_admin_registry): Confirmation by the proposed administrator to accept the role. + 1. [`set_pool`](/ccip/api-reference/svm/v0.1.1/router#set_pool): Links the token to a specific token pool configuration via an address lookup table, including writable account indexes for proper permission management. + + For detailed step-by-step procedures, sequence diagrams, and complete registration workflows, see [Registration & Administration](/ccip/concepts/cross-chain-token/svm/registration-administration). + + - **Pool configuration:** The TokenAdminRegistry maps each mint to exactly one token pool configuration through the ALT. This ensures that during cross-chain transfers, only the authorized token pool implementation can interact with the token. + - **Security Architecture:** The one-to-one mapping between tokens and pools provides critical security guarantees: + - **Single Authorized Pool:** Each token mint can only have one authorized pool configuration, preventing unauthorized token handling + - **Atomic Pool Updates:** Changing pool configurations requires updating the entire ALT reference, ensuring consistent state + - **Access Control:** Only the registry administrator can modify pool assignments, maintaining strict governance 1. **Lock or Burn Flow (when sending tokens cross-chain)** - - `ccip_send` entrypoint: When a CCIP sender initiates a cross-chain token transfer, they invoke the `ccip_send` instruction on the Router, providing the token mint, amount, destination chain, receiver address, and other transaction parameters. - - **Validation Against Registry:** The sender must provide the token pool account addresses as part of the transaction. The Router validates these accounts by checking them against the addresses stored in the address lookup table (ALT) referenced by the mint's TokenAdminRegistry PDA. - - **CPI to `lock_or_burn_tokens`:** After validation, the Router executes a CPI call to the token pool's `lock_or_burn_tokens` instruction, passing the appropriate context for the token pool to either lock tokens in its Associated Token Account (ATA) or burn them from circulation, depending on the pool implementation. + - [`ccip_send`](/ccip/api-reference/svm/v0.1.1/router#ccip_send) entrypoint: When a CCIP sender initiates a cross-chain token transfer, they invoke the [`ccip_send`](/ccip/api-reference/svm/v0.1.1/router#ccip_send) instruction on the Router, providing the token mint, amount, destination chain, receiver address, and other transaction parameters. + - **Multi-step Validation:** The Router performs comprehensive validation: + - Verifies the destination chain is not cursed (via RMN Remote CPI) + - Checks sender authorization against allow-list if enabled + - Validates token amounts are non-zero + - Ensures proper account relationships and permissions + - **Registry Validation:** The sender must provide the token pool account addresses as part of the transaction. The Router validates these accounts by checking them against the addresses stored in the address lookup table (ALT) referenced by the mint's TokenAdminRegistry PDA, including proper writable permissions. + - **Fee Processing:** Before token interaction, the Router handles fee collection either in native SOL (with wrapping to WSOL) or supported fee SPL tokens through the fee quoter program. + - **[CPI](https://docs.solana.com/developing/programming-model/calling-between-programs) to [`lock_or_burn_tokens`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#lock_or_burn_tokens):** After validation, the Router executes a CPI call to the token pool's [`lock_or_burn_tokens`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#lock_or_burn_tokens) instruction, passing the appropriate context including nonce information and destination chain details for the token pool to either lock tokens in its [Associated Token Account](https://spl.solana.com/associated-token-account) (ATA) or burn them from circulation, depending on the pool implementation (see [Token Pool section](#token-pool) for operation details). ## OffRamp -1. **Verification and Token Pool Validation** +The CCIP OffRamp program handles cross-chain token reception and release on the destination chain. This section focuses specifically on the **execute phase**. For the complete OffRamp functionality including commit phase and general message processing, see [OffRamp Components](/ccip/concepts/architecture/onchain/svm/components#offramp). - On the destination blockchain, the OffRamp program receives validated CCIP Messages containing information about which tokens to transfer, the intended receiver, and the source chain details. Before finalizing the transfer, the OffRamp performs a series of validations: +During the execute phase, when processing messages containing token transfers, the OffRamp performs comprehensive token-specific validations and operations. - - It checks the TokenAdminRegistry PDA (owned by the Router) to confirm that the provided token pool accounts are the authorized ones for that token mint. - - It validates that the address lookup table and TokenAdminRegistry PDAs match the mint's registry record to ensure interaction with the correct token pool program. - - It verifies its own authorization to call the token pool by checking a special PDA, which is derived from the `allowed_offramp` seed, source chain selector, and offramp program ID. This PDA must exist and be owned by the Router, preventing unauthorized offramps from minting or releasing tokens. +1. **Token Pool Authorization Validation** -1. **Direct CPI to `release_or_mint_tokens`** + Before releasing or minting tokens, the OffRamp validates its authorization to interact with token pools: - Once all validations are successful, the OffRamp makes a CPI call to the token pool program, involving the `release_or_mint_tokens` instruction. - For this CPI, the Offramp uses a special PDA signer derived using the `external_token_pools_signer` seed, which the token pool recognizes as an authorized caller. + - **Router Authorization Check**: Verifies a special [PDA](https://solana.com/docs/core/pda) exists, derived using seeds `[seed::ALLOWED_OFFRAMP, source_chain_selector.to_le_bytes().as_ref(), offramp.key().as_ref()]` with the Router as the program ID. This PDA must be owned by the Router, ensuring only authorized OffRamps can trigger token operations. + - **TokenAdminRegistry Validation**: Checks the TokenAdminRegistry [PDA](https://solana.com/docs/core/pda) (owned by the Router) to confirm the provided token pool accounts match the authorized configuration for the token mint. + - **[Address Lookup Table](https://docs.solana.com/developing/lookup-tables) Verification**: Validates that the address lookup table and TokenAdminRegistry PDAs correspond to the mint's registry record, ensuring interaction with the correct token pool program. -## Token +1. **Token Pool Operations** -On Solana, the token to be transferred across blockchains is an SPL Mint managed by one of the standard Solana token programs, either the original SPL Token or the newer Token-2022. -To learn more , read the [Tokens compatibility requirements](/ccip/concepts/cross-chain-token/svm/tokens#compatibility). + Once authorization is confirmed, the OffRamp executes token operations: -## Token Pool + - **[CPI](https://docs.solana.com/developing/programming-model/calling-between-programs) to [`release_or_mint_tokens`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#release_or_mint_tokens)**: Makes a cross-program invocation to the token pool's [`release_or_mint_tokens`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#release_or_mint_tokens) instruction, passing the validated cross-chain token transfer details. + - **Authorization Signer**: Uses the `external_token_pools_signer` [PDA](https://solana.com/docs/core/pda) as the CPI signer, derived using seeds `[seed::EXTERNAL_TOKEN_POOLS_SIGNER, pool_program.key().as_ref()]` with the OffRamp as the program ID. Token pools recognize this as an authorized caller from the OffRamp. + - **Token Balance Verification**: Validates that the recipient's [Associated Token Account](https://spl.solana.com/associated-token-account) receives the correct amount of tokens as specified by the pool's response. -A Token Pool is a self-contained program responsible for executing cross-chain token transfers for a specific token. +1. **Cross-Chain Token Operations** - + The OffRamp handles different token pool types based on their configuration: + + - **BurnMint token pools**: Mint new tokens directly to the recipient's [ATA](https://spl.solana.com/associated-token-account) + - **LockRelease token pools**: Transfer (release) tokens from the pool's [ATA](https://spl.solana.com/associated-token-account) to the recipient's ATA + +The OffRamp ensures secure token operations by leveraging the same TokenAdminRegistry and address lookup table system established by the Router (see [Token section](#token)), maintaining the one-to-one mapping between tokens and their authorized pools while providing the necessary authorization for cross-chain token reception. + +## Component Integration -**How Token Pools Work** +The four components work together to enable secure cross-chain transfers: -- Separate Token Pools Per Blockchain - - You deploy a corresponding pool program for each blockchain that interacts with your token, then configure remote chains information to enable cross-chain transfers. -- Token Pool Operations - - When acting as a source chain pool (called by the Router in `ccip_send`): - - BurnMint token pool: Transfers tokens from the sender's ATA to the pool's ATA, then burns them from the pool's ATA. - - LockRelease token pool: Locks tokens by transferring them from the sender ATA to the pool's ATA. - - When acting as a destination chain pool (called by the OffRamp): - - BurnMint token pool: Mints tokens to a receiver's ATA. - - LockRelease token pool: Transfers (releases) tokens from the pool's ATA to the receiver's ATA. +1. **Token Registration**: Creates the TokenAdminRegistry [PDA](https://solana.com/docs/core/pda) that authorizes all subsequent operations and links to the designated token pool +1. **Token Pool Deployment**: Provides the execution logic for transfers, with the specific pool type (BurnMint or LockRelease) determined by the token's requirements and operational preferences +1. **Router Coordination**: Manages token administration through the TokenAdminRegistry and validates outbound transfers by ensuring proper authorization against the pool's [Address Lookup Table](https://docs.solana.com/developing/lookup-tables) +1. **OffRamp Execution**: Validates authorization against the same TokenAdminRegistry system and executes inbound transfers through [CPI](https://docs.solana.com/developing/programming-model/calling-between-programs) calls to the authorized token pool -For an in-depth overview of token pool programs, see the [Token Pools](/ccip/concepts/cross-chain-token/svm/token-pools) page. +This architecture ensures that every cross-chain token operation is governed by the initial registration decision, maintaining security and consistency across the entire transfer lifecycle. The one-to-one mapping between tokens and pools, established during registration and enforced by all components, provides the foundation for secure cross-chain token transfers. diff --git a/src/content/ccip/concepts/cross-chain-token/svm/index.mdx b/src/content/ccip/concepts/cross-chain-token/svm/index.mdx index 927c3eacc6c..b91896bf624 100644 --- a/src/content/ccip/concepts/cross-chain-token/svm/index.mdx +++ b/src/content/ccip/concepts/cross-chain-token/svm/index.mdx @@ -16,5 +16,6 @@ This section provides detailed guidance for integrating tokens with Chainlink CC - **[Architecture](/ccip/concepts/cross-chain-token/svm/architecture)**: Understand the specific architecture for CCTs on SVM chains. - **[Tokens](/ccip/concepts/cross-chain-token/svm/tokens)**: Learn about the requirements and compatibility for your SPL tokens. - **[Token Pools](/ccip/concepts/cross-chain-token/svm/token-pools)**: Explore the different types of token pool programs and how to use them. +- **[Integration Guide](/ccip/concepts/cross-chain-token/svm/integration-guide)**: Determine your integration path based on mint authority control and deployment preferences. Includes decision tree and touch points with Chainlink governance. - **[Registration and Administration](/ccip/concepts/cross-chain-token/svm/registration-administration)**: Details on registering your token with CCIP and managing administrative roles on SVM. - **[Upgradability](/ccip/concepts/cross-chain-token/svm/upgradability)**: Information on upgrading token pool programs. diff --git a/src/content/ccip/concepts/cross-chain-token/svm/integration-guide.mdx b/src/content/ccip/concepts/cross-chain-token/svm/integration-guide.mdx new file mode 100644 index 00000000000..0168f204530 --- /dev/null +++ b/src/content/ccip/concepts/cross-chain-token/svm/integration-guide.mdx @@ -0,0 +1,221 @@ +--- +section: ccip +date: Last Modified +title: "Cross-Chain Token Standard - Integration Guide (SVM)" +metadata: + description: "Step-by-step integration guide for CCIP Cross-Chain Tokens on SVM chains like Solana. Determine your integration path based on mint authority control, choose deployment approaches, and understand when self-service vs Chainlink assistance is required." + excerpt: "CCIP integration guide, SVM, Solana, mint authority, self-service, Chainlink assistance, deployment approaches, token registration, pool initialization, SPL token multisig, governance multisig, contact form, decision tree, integration path" +--- + +import { Aside, ClickToZoom } from "@components" +import CcipCommon from "@features/ccip/CcipCommon.astro" + +This integration guide helps you determine the optimal path for integrating your SPL token with Chainlink CCIP on SVM-based blockchains like Solana. Follow the decision tree below to understand your specific requirements, deployment options, and when you can use self-service versus when you need Chainlink assistance. + + + +## Prerequisites + +Before starting integration, ensure you meet these requirements: + +- **Token Compatibility**: Your token must meet [compatibility requirements](/ccip/concepts/cross-chain-token/svm/tokens#compatibility) +- **Decimal Planning**: Plan [decimal configuration](/ccip/concepts/cross-chain-token/svm/tokens#decimal-planning) across all target blockchains +- **Pool Type Selection**: Choose the appropriate token pool type for your use case: + + - **[BurnMint Pools](/ccip/concepts/cross-chain-token/svm/token-pools#burnmint-token-pool)**: Burn tokens on source, mint on destination. Requires transferring mint authority to pool. Best for tokens designed to have variable supply across chains. + + - **[LockRelease Pools](/ccip/concepts/cross-chain-token/svm/token-pools#lockrelease-token-pool)**: Lock tokens on source, release on destination. No mint authority transfer required. Requires liquidity management. Best for retaining mint authority control or capped-supply tokens. + + For detailed comparisons and technical requirements, see [Token Handling Mechanisms](/ccip/concepts/cross-chain-token/svm/token-pools#token-handling-mechanisms). + +## Integration Overview + +CCIP Cross-Chain Token (CCT) integration involves two key phases: + +1. **Token Registration**: Establishing a CCIP token administrator role +1. **Token Pool Deployment**: Setting up the pool program that handles cross-chain operations + +Your path through these phases depends on your **mint authority control** and chosen **[deployment approach](/ccip/concepts/cross-chain-token/svm/token-pools#deployment-approaches)**. + +## Decision Flow Diagram + +The following diagram visualizes the complete decision process based on your mint authority control: + + + +## Mint Authority Assessment + +The first critical decision point is understanding your mint authority control, as this determines your available options throughout the integration process. + +**Why mint authority control matters for token registration:** The Router's [`owner_propose_administrator`](/ccip/api-reference/svm/v0.1.1/router#owner_propose_administrator) instruction can only be called by the actual mint authority holder. The Router verifies onchain that the signer account matches the token's `mint_authority` field. If you cannot sign this instruction as the mint authority, the Router cannot verify your authorization onchain, requiring manual governance assistance. + +**You have direct control when:** + +- You hold the mint authority private key directly +- You control a governance multisig that holds the mint authority (non-SPL token multisig) +- You can execute mint authority operations through your governance process + +**You do NOT have direct control when:** + +- Mint authority is set to `None` (supply capped) +- Mint authority is held by an SPL token multisig +- Mint authority is controlled by another party you cannot coordinate with +- You have lost access to the mint authority private key + + + +## Integration Paths + +Based on your mint authority control, follow the appropriate integration path: + +### Path A: Full Self-Service (Mint Authority Controlled) + +**When to use:** You have direct control over the mint authority + +**Registration Process:** + +- **Self-service registration**: Use [`owner_propose_administrator`](/ccip/api-reference/svm/v0.1.1/router#owner_propose_administrator) and [`accept_admin_role_token_admin_registry`](/ccip/api-reference/svm/v0.1.1/router#accept_admin_role_token_admin_registry) instructions (propose + accept) +- **Immediate control**: Complete registration without external assistance +- **Administrator flexibility**: Choose any address as the CCIP token administrator + +**Pool Deployment Options:** + +1. **[Self-Serve Mode](/ccip/concepts/cross-chain-token/svm/token-pools#approach-1-self-serve-mode-recommended) (Recommended)** + + - Use Chainlink-deployed standard pool programs + - Initialize your pool using [`initialize`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#initialize) instruction + - Automatic governance-controlled upgrades + - Lowest operational overhead + +2. **[Self-Deployed Standard Pools](/ccip/concepts/cross-chain-token/svm/token-pools#approach-2-self-deployed-standard-pools)** + + - Deploy standard pool programs yourself + - Control upgrade authority and timing + - Initialize your own pools + +3. **[Custom Token Pools](/ccip/concepts/cross-chain-token/svm/token-pools#approach-3-custom-token-pools)** + - Build custom pool logic for specialized requirements + - Full control over implementation and upgrades + +### Path B: Assisted Registration + Self-Serve Pools (Mint Authority Not Controlled) + +**When to use:** You want to use self-serve mode pools, but you cannot call [`owner_propose_administrator`](/ccip/api-reference/svm/v0.1.1/router#owner_propose_administrator) as the mint authority + +**Registration Process:** + +- **Manual registration required**: Submit [registration request](https://chain.link/ccip-contact?v=Tokens:%20Token%20admin%20registration) +- **CCIP governance assistance**: Router upgrade authority will propose the administrator using [`ccip_admin_propose_administrator`](/ccip/api-reference/svm/v0.1.1/router#ccip_admin_propose_administrator) +- **Choose administrator**: You specify who should be the CCIP token administrator + +**Pool Deployment:** + +- **Assisted pool initialization**: Submit [registration request](https://chain.link/ccip-contact?v=Tokens:%20Token%20admin%20registration) to have the pool program upgrade authority initialize your pool +- **Self-serve mode benefits**: Once initialized, you become the pool owner with full configuration control +- **Governance-controlled upgrades**: Benefit from automatic security updates and features + +### Path C: Full Manual Process (Custom or Self-Deployed) + +**When to use:** You cannot call [`owner_propose_administrator`](/ccip/api-reference/svm/v0.1.1/router#owner_propose_administrator) as the mint authority and want self-deployed or custom pools + +**Registration Process:** + +- Same manual registration process as Path B + +**Pool Deployment:** + +- **Deploy your own programs**: Full control over pool program deployment +- **Control upgrade authority**: Manage your own upgrade process +- **Initialize independently**: Use your upgrade authority to initialize pools + + + +## Implementation Steps + +Once you've determined your path, follow these implementation steps: + +### Step 1: Complete Registration + +- **Self-service path**: Follow [self-service registration](/ccip/concepts/cross-chain-token/svm/registration-administration#self-service-registration-flow) +- **Assisted path**: Submit [registration request](https://chain.link/ccip-contact?v=Tokens:%20Token%20admin%20registration) + +### Step 2: Deploy and Initialize Token Pool + +Choose your deployment approach: + +- **Self-serve mode**: Initialize pool from existing Chainlink-deployed programs + + - **If you can sign as mint authority**: Use the [`initialize`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#initialize) instruction directly + - **If you cannot sign as mint authority** (mint authority is `None`, held by SPL token multisig, or controlled by another party): Submit [registration request](https://chain.link/ccip-contact?v=Tokens:%20Token%20admin%20registration) for assisted initialization + +- **Self-deployed**: Deploy standard pool programs yourself, then initialize pool from your deployed program + +- **Custom**: Implement and deploy custom pool following [technical requirements](/ccip/concepts/cross-chain-token/svm/token-pools#custom-token-pools), then initialize pool from your deployed program + +### Step 3: Create Associated Token Account + +- Create the [Associated Token Account (ATA)](https://www.solana-program.com/docs/associated-token-account) for the Pool Signer PDA +- **Required**: Pool operations cannot begin without this ATA +- The ATA will hold tokens for LockRelease pools or serve as the burn account for BurnMint pools + +### Step 4: Transfer Mint Authority (BurnMint Pools Only) + +Choose one of two approaches: + +- **Direct Transfer**: Transfer `mint_authority` directly to the Pool Signer PDA (simple, pool-only minting) +- **Multisig Setup (Recommended)**: Create an M-of-N [SPL token multisig](https://spl.solana.com/token#multisig-usage) with Pool Signer PDA appearing at least M times as a signer (flexible, multiple authorized minters) + +See [Mint Authority Management](/ccip/concepts/cross-chain-token/svm/token-pools#mint-authority-management) for detailed configuration options. + +### Step 5: Create Address Lookup Table (ALT) + +- Create an ALT containing all required accounts for your pool operations +- Must include required accounts in specific order as detailed in the [`set_pool` API reference](/ccip/api-reference/svm/v0.1.1/router#address-lookup-table-requirements) +- See the complete [ALT requirements table](/ccip/api-reference/svm/v0.1.1/router#address-lookup-table-requirements) for exact account order and derivations + +### Step 6: Link Pool to Token Registry + +- Call [`set_pool`](/ccip/api-reference/svm/v0.1.1/router#set_pool) instruction on the Router +- Links your pool's ALT to your token in the TokenAdminRegistry +- Enables CCIP to route cross-chain transfers to your pool + +### Step 7: Configure Pool Settings + +- Complete [remote chain configuration](/ccip/concepts/cross-chain-token/svm/registration-administration#remote-chain-configuration) +- Set up [rate limits and security settings](/ccip/concepts/cross-chain-token/svm/registration-administration#rate-limits-and-security) +- **For LockRelease pools**: Configure [liquidity management](/ccip/concepts/cross-chain-token/svm/registration-administration#liquidity-management-lockrelease-pools-only) + +## Next Steps + +After determining your integration path: + +1. **Review Detailed Documentation**: + + - [Architecture](/ccip/concepts/cross-chain-token/svm/architecture): Understand component interactions + - [Tokens](/ccip/concepts/cross-chain-token/svm/tokens): Token requirements and compatibility + - [Token Pools](/ccip/concepts/cross-chain-token/svm/token-pools): Pool implementation details + - [Registration & Administration](/ccip/concepts/cross-chain-token/svm/registration-administration): Complete registration and configuration procedures + +1. **For Assisted Paths**: Submit your [registration request](https://chain.link/ccip-contact?v=Tokens:%20Token%20admin%20registration) with detailed information about your token and requirements + +1. **For Self-Service Paths**: Begin with token registration following the appropriate workflow for your chosen deployment approach diff --git a/src/content/ccip/concepts/cross-chain-token/svm/registration-administration.mdx b/src/content/ccip/concepts/cross-chain-token/svm/registration-administration.mdx index 71c45ec623d..845344a4229 100644 --- a/src/content/ccip/concepts/cross-chain-token/svm/registration-administration.mdx +++ b/src/content/ccip/concepts/cross-chain-token/svm/registration-administration.mdx @@ -3,52 +3,108 @@ section: ccip date: Last Modified title: "Cross-Chain Token Standard - Registration & Administration (SVM)" metadata: - description: "Register and administer SPL tokens for CCIP on SVM chains. Learn the two-step process, role transfers, setting token pools, and configuring pool parameters." + description: "Complete guide to registering and administering SPL tokens for CCIP on SVM chains like Solana. Covers token administrator roles, self-service registration with mint authority, Router vs Pool operations, remote chain configuration, rate limiting, allowlists, and liquidity management for cross-chain token transfers." + excerpt: "CCIP, SPL tokens, SVM, Solana, token administrator, registration, self-service, mint authority, Router program, Token Pool, TokenAdminRegistry, PDA, cross-chain transfers, administrator roles, pool configuration, remote chains, rate limiting, allowlists, liquidity management, rebalancer, Associated Token Accounts, Address Lookup Tables, auto-derivation, owner_propose_administrator, set_pool, init_chain_remote_config, provide_liquidity, withdraw_liquidity" --- -import { ClickToZoom } from "@components" +import { Aside, ClickToZoom } from "@components" import CcipCommon from "@features/ccip/CcipCommon.astro" - +When token administrators want to register their SPL token for Cross‐Chain Token (CCT) operations, they interact with both the Router program and Token Pool programs. This guide covers both token registration/administration (Router side) and token pool configuration (Pool side). -When token administrators want to register their SPL token for Cross‐Chain Token (CCT) operations, they interact with the Router program. +## Token Registration & Administration (Router Side) -Two key steps ensure a secure assignment of the administrator role: +This section covers all operations performed through the Router program to manage token administrator roles and basic token configuration. -1. The intended administrator is proposed (i.e., placed in a pending state). -1. That pending administrator must explicitly _accept_ the role. +### Router Access Control for Token Administration -## Self-Service Registration Flow +Understanding who can call which Router instructions is critical for secure token administration. This table shows the authorization model for all token admin registry instructions: -If your SPL token supports an automatic way to determine an admin using onchain verifiable data (e.g., you hold the mint authority), you can complete self-registration in a permissionless manner by calling the Router's `owner_propose_administrator` instruction: +| Instruction | Mint Authority | Router Upgrade Authority | Current Token Admin | Pending Token Admin | +| ---------------------------------------------------------------------------------------------------------------------------- | :------------: | :----------------------: | :-----------------: | :-----------------: | +| [`owner_propose_administrator`](/ccip/api-reference/svm/v0.1.1/router#owner_propose_administrator) | ✅ | ❌ | ❌ | ❌ | +| [`owner_override_pending_administrator`](/ccip/api-reference/svm/v0.1.1/router#owner_override_pending_administrator) | ✅ | ❌ | ❌ | ❌ | +| [`ccip_admin_propose_administrator`](/ccip/api-reference/svm/v0.1.1/router#ccip_admin_propose_administrator) | ❌ | ✅ | ❌ | ❌ | +| [`accept_admin_role_token_admin_registry`](/ccip/api-reference/svm/v0.1.1/router#accept_admin_role_token_admin_registry) | ❌ | ❌ | ❌ | ✅ | +| [`transfer_admin_role_token_admin_registry`](/ccip/api-reference/svm/v0.1.1/router#transfer_admin_role_token_admin_registry) | ❌ | ❌ | ✅ | ❌ | +| [`set_pool`](/ccip/api-reference/svm/v0.1.1/router#set_pool) | ❌ | ❌ | ✅ | ❌ | + +**Notes:** + +- **Mint Authority**: The SPL token's `mint_authority` holder +- **Router Upgrade Authority**: The Router program's upgrade authority +- **Current Token Admin**: The active CCIP [token administrator](/ccip/concepts/cross-chain-token/overview#token-administrator) +- **Pending Token Admin**: [Token administrator](/ccip/concepts/cross-chain-token/overview#token-administrator) proposed but not yet accepted + +**Focus on Self-Service Registration:** The following sections focus on the **self-service registration flow** where you control your token's mint authority. While the Router also supports `ccip_admin_propose_administrator` for cases where mint authority is not accessible, we detail the self-service approach as it's the primary registration method for most token developers. + +### Self-Service Registration Flow + +If your SPL token supports an automatic way to determine an admin using onchain verifiable data (e.g., you hold the mint authority), you can complete self-registration in a permissionless manner by calling the Router's [`owner_propose_administrator`](/ccip/api-reference/svm/v0.1.1/router#owner_propose_administrator) instruction: + +1. **Admin Initiates Registration:** The token admin calls the Router's [`owner_propose_administrator`](/ccip/api-reference/svm/v0.1.1/router#owner_propose_administrator) instruction, passing in the mint and the proposed administrator's public key. This instruction initializes a `TokenAdminRegistry` PDA for this mint. -1. **Admin Initiates Registration:** The token admin calls the Router's `owner_propose_administrator` instruction, passing in the mint and the proposed administrator's public key. This instruction initializes a `TokenAdminRegistry` PDA for this mint. 1. **Determine Administrator:** The Router ensures that the caller is the SPL token's mint authority, confirming they have the right to set a CCIP admin. -1. **Propose Administrator:** The Router sets the proposed administrator as the pending administrator. The token admin is not fully recognized yet; they remain `pending`. The `TokenAdminRegistry` now stores this user as `pendingAdmin`. The next step is to accept the role. -## Non-Self-Service Registration Flow +1. **Propose Administrator:** The Router sets the proposed administrator as the pending administrator. The token admin is not fully recognized yet; they remain `pending`. The `TokenAdminRegistry` now stores this user as `pending_administrator`. The next step is to accept the role. -For token programs that do not have a standard way to identify an administrator using onchain verifiable data (e.g., no direct mint authority check), the token developer can manually initiate the registration by submitting a request [here](https://chain.link/ccip-contact?v=Tokens:%20Token%20admin%20registration). +**Self-Service Registration Requirements:** -## Interacting with the Registry +- **Caller Authorization**: Only the SPL token's `mint_authority` can call [`owner_propose_administrator`](/ccip/api-reference/svm/v0.1.1/router#owner_propose_administrator) +- **Registry State**: TokenAdminRegistry PDA must not already exist for this mint +- **Result**: Creates new TokenAdminRegistry PDA with proposed administrator in pending state -### Proposing the Administrator +### Non-Self-Service Registration Flow + + + +For token programs that do not have a standard way to identify an administrator using onchain verifiable data (e.g., no direct mint authority check), the token developer can manually initiate the registration by submitting a request above. + +### Administrator Role Management + +#### Proposing the Administrator The following sequence diagram illustrates the process of proposing the administrator. -### Accepting the Administrator Role +#### Overriding Pending Administrator + +If you need to change the pending administrator before they accept the role, you can use the [`owner_override_pending_administrator`](/ccip/api-reference/svm/v0.1.1/router#owner_override_pending_administrator) instruction. This is useful when you initially proposed the wrong administrator or need to update the pending administrator for other reasons. + +1. **Override Pending Administrator:** The mint authority calls the Router's [`owner_override_pending_administrator`](/ccip/api-reference/svm/v0.1.1/router#owner_override_pending_administrator) instruction, passing in the mint and the new proposed administrator's public key. + +1. **Validate Authority:** The Router ensures that the caller is the SPL token's mint authority and that no administrator has been accepted yet (the `administrator` field must be zero). + +1. **Update Pending Administrator:** The Router replaces the existing `pending_administrator` with the new proposed administrator. The previous pending administrator can no longer accept the role. + +**Override Requirements:** + +- **Caller Authorization**: Only the SPL token's `mint_authority` can call [`owner_override_pending_administrator`](/ccip/api-reference/svm/v0.1.1/router#owner_override_pending_administrator) +- **Registry State**: TokenAdminRegistry PDA must exist but have no accepted administrator yet (`administrator` field is zero) +- **Result**: Updates the `pending_administrator` field with the new proposed administrator + + + +#### Accepting the Administrator Role Once the administrator has been proposed and is pending, they must accept the role to complete the registration process. This step finalizes the administrator's assignment. -1. **Pending Administrator Calls `accept_admin_role_token_admin_registry`** +1. **Pending Administrator Calls [`accept_admin_role_token_admin_registry`](/ccip/api-reference/svm/v0.1.1/router#accept_admin_role_token_admin_registry)** - The pending admin invokes `accept_admin_role_token_admin_registry(mint)` on the Router program, specifying the mint for which they were proposed. + The pending admin invokes [`accept_admin_role_token_admin_registry()`](/ccip/api-reference/svm/v0.1.1/router#accept_admin_role_token_admin_registry) on the Router program, specifying the mint account in the transaction context. 1. **Finalize Registration** - The Router checks that the caller's public key matches the `pending_administrator` field in the `TokenAdminRegistry` PDA. @@ -57,38 +113,38 @@ Once the administrator has been proposed and is pending, they must accept the ro Below is the sequence diagram illustrating how the pending administrator interacts with the Router program to complete registration. -### Transfer Administrator Role +#### Transfer Administrator Role -The `transfer_admin_role_token_admin_registry` instruction allows the current token administrator to transfer their role to a new administrator. This transfer process is secure and involves two steps, requiring the new admin to accept it explicitly before finalization. +The [`transfer_admin_role_token_admin_registry`](/ccip/api-reference/svm/v0.1.1/router#transfer_admin_role_token_admin_registry) instruction allows the current token administrator to transfer their role to a new administrator. This transfer process is secure and involves two steps, requiring the new admin to accept it explicitly before finalization. 1. **Initiate Role Transfer** - - The current admin calls `transfer_admin_role_token_admin_registry(mint, newAdmin)` on the Router, passing the SPL token mint and the new administrator's public key. - - The Router checks that the caller is the token's existing administrator. If so, it sets `pending_administrator = newAdmin` in the `TokenAdminRegistry` (PDA). + - The current admin calls [`transfer_admin_role_token_admin_registry(new_admin)`](/ccip/api-reference/svm/v0.1.1/router#transfer_admin_role_token_admin_registry) on the Router, passing the new administrator's public key. + - The Router checks that the caller is the token's existing administrator. If so, it sets `pending_administrator = new_admin` in the `TokenAdminRegistry` (PDA). 1. **Pending Administrator** - The registry is now pending. The existing admin will still be active until the new admin accepts. 1. **Accept the Role** - - The new administrator must call `accept_admin_role_token_admin_registry(mint)` to finalize the transfer. + - The new administrator must call [`accept_admin_role_token_admin_registry()`](/ccip/api-reference/svm/v0.1.1/router#accept_admin_role_token_admin_registry) to finalize the transfer. - If `authority.key()` matches `pending_administrator`, the Router updates `administrator = pending_administrator`. Otherwise, it will fail. - Once accepted, the new administrator can set or modify the token pool. Below is a sequence diagram showing how the transfer is requested, followed by how the new admin must accept to complete the handover. ### Setting the Token Pool -On SVM-based blockchains (e.g., Solana), the `set_pool` instruction enables a token administrator to map a given mint to the pool lookup table that defines how that token is handled in cross-chain transfers. This instruction modifies the `TokenAdminRegistry` PDA so the Route program knows which token pool accounts can lock or burn tokens on the source chain (and release or mint them on the destination). +On SVM-based blockchains (e.g., Solana), the [`set_pool`](/ccip/api-reference/svm/v0.1.1/router#set_pool) instruction enables a token administrator to map a given mint to the pool lookup table that defines how that token is handled in cross-chain transfers. This instruction modifies the `TokenAdminRegistry` PDA so the Route program knows which token pool accounts can lock or burn tokens on the source chain (and release or mint them on the destination). -1. **Set Token Pool:** The current administrator calls the `set_pool` instruction on the Router program, passing in: +1. **Set Token Pool:** The current administrator calls the [`set_pool`](/ccip/api-reference/svm/v0.1.1/router#set_pool) instruction on the Router program, passing in: - The token mint (for which we are configuring cross-chain transfers). - The `pool_lookuptable` account (the Address Lookup Table containing the mandatory PDAs and program addresses for that token pool). - A list of "writable indexes" indicating which lookup table entries should be marked as writable during cross-chain transfers. These indexes specify positions in the ALT that require write permission for successful transaction execution. @@ -97,63 +153,134 @@ On SVM-based blockchains (e.g., Solana), the `set_pool` instruction enables a to - Resets the old permission bits, then enables the specified "writable indexes." - This ensures the new token pool has the correct set of PDAs with the correct writable permissions. 1. **Validate or Delist:** - - If the new `pool_lookuptable` is not the zero address, the Router checks that this lookup table has at least the minimal set of addresses required for cross-chain transfers. This includes the token mint, pool program, token program, pool configuration PDA, and any other mandatory accounts specified by the pool implementation. If valid, the token becomes enabled for cross-chain transfers. + - If the new `pool_lookuptable` is not the zero address, the Router checks that this lookup table has at least the minimal set of addresses required for cross-chain transfers. For the complete list of required accounts and their exact order, see the [`set_pool` ALT requirements](/ccip/api-reference/svm/v0.1.1/router#address-lookup-table-requirements). If valid, the token becomes enabled for cross-chain transfers. - If the `pool_lookuptable` is the zero address, the token is effectively delisted from CCIP, meaning no new cross-chain transfers can occur. -The sequence diagram below explains how the `set_pool` instruction updates the `TokenAdminRegistry` PDA and either enables or delists the token for cross-chain transfers. +The sequence diagram below explains how the [`set_pool`](/ccip/api-reference/svm/v0.1.1/router#set_pool) instruction updates the `TokenAdminRegistry` PDA and either enables or delists the token for cross-chain transfers. -### Configuring the Token Pool +## Token Pool Configuration (Pool Side) + +Once you have registered your token and set the token pool via the Router, you need to configure the specific pool parameters. These operations are performed directly on the Token Pool programs, not the Router. + + + +### Pool Initialization -The configuration of token pools includes adding new blockchains, setting remote pool addresses, and applying rate limits for cross-chain transfers. The following instructions are used for configuring token pools: +Before any other configuration can occur, you must initialize your token pool: + +1. **Initialize Token Pool** + + - **Instruction:** [`initialize`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#initialize) + - **Use Case:** Create the pool state PDA for your specific mint. This is the first mandatory step that must be completed before any other pool configuration operations. + - **Authorization:** Program upgrade authority can always initialize pools. When self-serve is enabled (`self_served_allowed: true`), the token's mint authority can also initialize pools. + - **Requirements:** Pool owner must create the [Associated Token Account (ATA)](https://www.solana-program.com/docs/associated-token-account) for the Pool Signer PDA before pool operations can begin. + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#initialize) to learn more. + +### Remote Chain Configuration + +Configure your token pool for specific destination blockchains: 1. **Initialize a Remote Configuration** - - **Instruction:** `init_chain_remote_config` + - **Instruction:** [`init_chain_remote_config`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#init_chain_remote_config) - **Use Case:** Create a new onchain account (PDA derived from the chain selector and token pool program ID) holding configuration details for a specific remote blockchain (e.g., remote token address). - - Read the [API reference](/ccip/api-reference/svm) to learn more. + - **Authorization:** Pool Owner only + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#init_chain_remote_config) to learn more. 1. **Edit an Existing Remote Configuration** - - **Instruction:** `edit_chain_remote_config` + - **Instruction:** [`edit_chain_remote_config`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#edit_chain_remote_config) - **Use Case:** Update the entire stored configuration for a remote chain (`RemoteConfig`), including the remote token address and decimals. - - Read the [API reference](/ccip/api-reference/svm) to learn more. + - **Authorization:** Pool Owner only + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#edit_chain_remote_config) to learn more. 1. **Add Remote Pool Address** - - **Instruction:** `append_remote_pool_addresses` - - **Use Case:** Register one or more remote pool addresses for the same remote chain. This can happen when you deploy a new pool version on that blockchain but keep the old address functional until all in-flight messages are processed. Note: To remove a remote pool address, call `edit_chain_remote_config` with a new configuration without that address. - - Read the [API reference](/ccip/api-reference/svm) to learn more. + - **Instruction:** [`append_remote_pool_addresses`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#append_remote_pool_addresses) + - **Use Case:** Register one or more remote pool addresses for the same remote chain. This can happen when you deploy a new pool version on that blockchain but keep the old address functional until all in-flight messages are processed. + - **Authorization:** Pool Owner only + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#append_remote_pool_addresses) to learn more. -1. **Configure Rate Limits** +1. **Remove Remote Pool Address** - - **Instruction:** `set_chain_rate_limit` - - **Use Case:** Apply or modify the remote blockchain's inbound/outbound rate-limit configuration. This uses a token bucket algorithm in which you can configure the capacity (maximum tokens) and rate (tokens per second refill rate) for both inbound and outbound transfers. - - Read the [API reference](/ccip/api-reference/svm) to learn more. + - **Instruction:** [`edit_chain_remote_config`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#edit_chain_remote_config) + - **Use Case:** Remove one or more remote pool addresses from an existing remote chain configuration. Call this instruction with a new `RemoteConfig` that excludes the addresses you want to remove. + - **Authorization:** Pool Owner only + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#edit_chain_remote_config) to learn more. 1. **Remove Chain Config** - - **Instruction:** `delete_chain_config` + - **Instruction:** [`delete_chain_config`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#delete_chain_config) - **Use Case:** Remove the remote blockchain configuration PDA to stop supporting it permanently. - - Read the [API reference](/ccip/api-reference/svm) to learn more. + - **Authorization:** Pool Owner only + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#delete_chain_config) to learn more. -1. **Liquidity Management (Lock/Release only)** +### Rate Limits and Security - - **Instruction** - - `set_rebalancer`: Configure which public key is authorized to add (via `provide_liquidity`) or withdraw liquidity (via `withdraw_liquidity`) from the pool. - - `set_can_accept_liquidity`: Enable or disable whether the pool can accept incoming liquidity via the `provide_liquidity` instruction. - - **Use Case:** Lock/Release token pools require liquidity management to ensure sufficient tokens are available for releases. These settings control which wallet or multisig is authorized to withdraw or add liquidity to the pool. - - Read the [API reference](/ccip/api-reference/svm) to learn more. +Configure transfer limits and access controls for your token pool: + +1. **Configure Rate Limits** + + - **Instruction:** [`set_chain_rate_limit`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#set_chain_rate_limit) + - **Use Case:** Apply or modify the remote blockchain's inbound/outbound rate-limit configuration. This uses a token bucket algorithm in which you can configure the capacity (maximum tokens) and rate (tokens per second refill rate) for both inbound and outbound transfers. + - **Authorization:** Pool Owner only + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#set_chain_rate_limit) to learn more. 1. **Optional Allowlist** - - **Instruction** - - `configure_allow_list`: Set `enabled = true` or `false` and optionally add new addresses. When the allowlist is enabled, only addresses that appear on it can initiate cross‐chain transfers. - - `remove_from_allow_list`: Remove specific addresses from the existing list. - - **Use case:** You can add or remove addresses if the pool has an allowlist. This provides an additional layer of access control for who can initiate cross-chain token transfers. - - Read the [API reference](/ccip/api-reference/svm) to learn more. + - **Instructions:** [`configure_allow_list`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#configure_allow_list), [`remove_from_allow_list`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#remove_from_allow_list) + - **Use case:** You can add or remove addresses if the pool has an allowlist. When the allowlist is enabled, only addresses that appear on it can initiate cross‐chain transfers. This provides an additional layer of access control for who can initiate cross-chain token transfers. + - **Authorization:** Pool Owner only + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#configure_allow_list) to learn more. + +For detailed authorization requirements, see the access control tables for [BurnMint pools](/ccip/concepts/cross-chain-token/svm/token-pools#access-control) and [LockRelease pools](/ccip/concepts/cross-chain-token/svm/token-pools#access-control-1). + +### Liquidity Management (Lock/Release Pools Only) + +Configure liquidity providers and settings for Lock/Release token pools: + +#### Liquidity Configuration + +1. **Set Rebalancer** + + - **Instruction:** [`set_rebalancer`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#set_rebalancer) + - **Use Case:** Configure which public key is authorized to add or withdraw liquidity from the pool. + - **Authorization:** Pool Owner only + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#set_rebalancer) to learn more. + +1. **Configure Liquidity Acceptance** + + - **Instruction:** [`set_can_accept_liquidity`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#set_can_accept_liquidity) + - **Use Case:** Enable or disable whether the pool can accept incoming liquidity via the [`provide_liquidity`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#provide_liquidity) instruction. + - **Authorization:** Pool Owner only + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#set_can_accept_liquidity) to learn more. + +#### Liquidity Operations + +1. **Provide Liquidity** + + - **Instruction:** [`provide_liquidity`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#provide_liquidity) + - **Use Case:** Add tokens to the pool's reserves to enable cross-chain releases. The rebalancer transfers tokens from their account to the pool's Associated Token Account. + - **Authorization:** Rebalancer only + - **Requirements:** Pool must have `can_accept_liquidity` enabled + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#provide_liquidity) to learn more. + +1. **Withdraw Liquidity** + + - **Instruction:** [`withdraw_liquidity`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#withdraw_liquidity) + - **Use Case:** Remove tokens from the pool's reserves. Can be used to transfer liquidity between pools by setting the destination as another pool's rebalancer. + - **Authorization:** Rebalancer only + - **Requirements:** Pool must have `can_accept_liquidity` enabled + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#withdraw_liquidity) to learn more. + +**Note:** Lock/Release token pools require active liquidity management to ensure sufficient tokens are available for releases. Insufficient liquidity will cause cross-chain transfer failures. For complete authorization details, see the [LockRelease Access Control table](/ccip/concepts/cross-chain-token/svm/token-pools#access-control-1). diff --git a/src/content/ccip/concepts/cross-chain-token/svm/token-pools.mdx b/src/content/ccip/concepts/cross-chain-token/svm/token-pools.mdx index 25935bc3eac..73394956726 100644 --- a/src/content/ccip/concepts/cross-chain-token/svm/token-pools.mdx +++ b/src/content/ccip/concepts/cross-chain-token/svm/token-pools.mdx @@ -3,202 +3,655 @@ section: ccip date: Last Modified title: "Cross-Chain Token Standard - Token Pools (SVM)" metadata: - description: "Learn about CCIP Token Pools for SVM chains like Solana. Covers requirements (instructions, PDAs, decimals), standard pools, and custom pool use cases." + description: "Complete guide to CCIP Token Pools for SVM chains like Solana. Covers deployment approaches (self-serve, self-deployed, custom), decimal compatibility decisions, standard pool implementation (BurnMint, LockRelease), and custom pool development requirements." + excerpt: "Token pools, SVM, Solana, deployment approaches, self-serve mode, BurnMint, LockRelease, decimal compatibility, decimal precision, mint authority, liquidity management, PDAs, custom pools, Token-2022, SPL tokens, cross-chain transfers, CCIP Router, rate limiting, instructions" --- -import { Aside } from "@components" +import { Aside, ClickToZoom } from "@components" import CcipCommon from "@features/ccip/CcipCommon.astro" - +On SVM-based blockchains (e.g., Solana), a [token pool](/ccip/concepts/cross-chain-token/overview#token-pool) program mediates the cross-chain transfer of [cross-chain tokens](/ccip/concepts/cross-chain-token/overview) by coordinating with the SPL Token Program. This guide describes all the requirements that your token pools must meet. -On SVM-based blockchains (e.g., Solana), a token pool program mediates the cross-chain transfer of Cross-Chain Tokens (CCTs) by coordinating with the SPL Token Program. This guide describes all the requirements that your token pools must meet. +For architectural context and how token pools fit into the complete CCIP system, see [Architecture Overview](/ccip/concepts/cross-chain-token/svm/architecture). For token-specific requirements and pool type selection guidance, see [Tokens documentation](/ccip/concepts/cross-chain-token/svm/tokens). -## Common Requirements +## Deployment Approaches -All token pools, whether standard or custom, must adhere to the following guidelines: +Before diving into the technical details, it's important to understand your three deployment options. Each approach offers different levels of control and responsibility based on your operational preferences and infrastructure requirements. -### Mandatory Instructions +### Approach 1: Self-Serve Mode (Recommended) -When CCIP interacts with your token pools, it expects the presence of the following functions: +**What it is:** Chainlink Labs deploys and maintains the standard token pool programs (BurnMint and LockRelease) on Solana Devnet and Mainnet. You simply initialize your token pool from these existing deployed programs. -1. For locking or burning tokens: +**Key Benefits:** - - `lock_or_burn_tokens(ctx: Context, lock_or_burn: LockOrBurnInV1,) -> Result`: This locks or burns tokens on the source blockchain. - - Read the [API reference](/ccip/api-reference/svm) to learn more about the parameters. +- No need to build, audit, or deploy pool programs yourself +- Automatic access to upgrades and security fixes +- Fastest time to deployment +- Lower operational overhead -1. For releasing or minting tokens: +**Who should use this:** [Token developers](/ccip/concepts/cross-chain-token/overview#token-developer) that want to integrate with CCIP quickly without managing infrastructure. - - `release_or_mint_tokens(ctx: Context, release_or_mint: ReleaseOrMintInV1,) -> Result`: This releases or mints tokens on the destination blockchain. - - Read the [API reference](/ccip/api-reference/svm) to learn more about the parameters. +**How it works:** -### Seeds and PDAs +1. **Program Admin** (Chainlink's upgrade authority) deploys the program and initializes the Global Config PDA with: + - `self_served_allowed: true` (enables user self-service) + - Default router address for the network + - Default RMN remote address for security +1. **Users** can initialize pools for their tokens by calling the [`initialize`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#initialize) instruction, provided they control the token's mint authority +1. New pools automatically inherit the default router and RMN addresses from the Global Config PDA -Reuse the base-token-pool Seeds and PDAs: +### Approach 2: Self-Deployed Standard Pools -1. Your token pool program should use the same seeds ([`ccip_tokenpool_config`](https://github.com/smartcontractkit/chainlink-ccip/blob/4c416d75ac2f5178bdb2c77527eb96822c999a92/chains/solana/contracts/programs/base-token-pool/src/common.rs#L13), [`ccip_tokenpool_chainconfig`](https://github.com/smartcontractkit/chainlink-ccip/blob/4c416d75ac2f5178bdb2c77527eb96822c999a92/chains/solana/contracts/programs/base-token-pool/src/common.rs#L12), and [`ccip_tokenpool_signer`](https://github.com/smartcontractkit/chainlink-ccip/blob/contracts-ccip-release/1.6.0/chains/solana/contracts/programs/base-token-pool/src/common.rs#L14)) so that the CCIP Router can correctly derive your program's program-derived addresses (PDAs). The built-in instructions in the CCIP Router rely on these well-known seeds to locate your pool's onchain configuration and signer accounts. +**What it is:** You build and deploy the standard Chainlink token pool programs yourself, giving you control over the upgrade authority. - +**Key Benefits:** -1. Refer to the standard implementation of [BurnMint](https://github.com/smartcontractkit/chainlink-ccip/tree/contracts-ccip-release/1.6.0/chains/solana/contracts/programs/burnmint-token-pool) or [LockRelease](https://github.com/smartcontractkit/chainlink-ccip/tree/contracts-ccip-release/1.6.0/chains/solana/contracts/programs/lockrelease-token-pool) token pools for more information. +- Full control over when to apply upgrades +- Can customize deployment timing and parameters +- Maintain upgrade authority for your pools +- Use proven, audited standard implementations -### Mint Authority for BurnMint Token Pools +**Who should use this:** Projects that need control over upgrade timing or have specific governance requirements. -On Solana, the `mint_authority` for an SPL token is stored as a single `COption` in the Mint account. This means only one address can be set as the minter at any given time. It is possible to configure the mint authority (using [mechanisms](/ccip/concepts/cross-chain-token/svm/tokens#mint-authority-for-burnmint) such as a multisig solution) so that you retain governance control even after it is reassigned to a BurnMint token pool program. +**How it works:** You compile and deploy the Chainlink-provided [BurnMint](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs/burnmint-token-pool) or [LockRelease](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs/lockrelease-token-pool) programs to your chosen address, retaining upgrade authority. -### Token Decimal Handling +### Approach 3: Custom Token Pools -Transferring tokens cross-chain when the token has different decimal configurations on source and destination can introduce rounding errors or unexpected balance changes if not appropriately handled. Below, we demonstrate a concrete scenario illustrating how these errors manifest and how you can mitigate them in your token pools. +**What it is:** You build your own token pool program with custom logic while ensuring CCIP compatibility. -#### Example of Precision Loss +**Key Benefits:** -Consider a token developer who deployed their token on two blockchains with different decimal configurations and without any proper decimals conversation in the token pools: +- Complete customization for unique token mechanics +- Support for specialized features (rebasing, fee-on-transfer, etc.) +- Full control over program logic -- Blockchain A: Token with 12 decimals -- Blockchain B: Token with 6 decimals +**Who should use this:** Projects with unique token mechanics that standard pools cannot accommodate. -| Transfer Path | Example | Explanation | Impact | -| -------------- | ------------------------------------------------------------------- | ----------------------- | ------------------------------- | -| A → B (12 → 6) | - Send 1 from A (= 10^12 base units)
- Receive on B: 1,000,000 | 10^12 / 10^6= 1,000,000 | Gain of 999,999 (1,000,000 -1) | -| B → A (6 → 12) | - Send 1 from B (= 10^6 base units)
- Receive on A: 0.000001 | 10^6 / 10^12= 0.000001 | Loss of 0.999999 (1 - 0.000001) | +**Requirements:** Must implement all [technical requirements](#technical-requirements) and follow the specifications detailed in the [Custom Token Pools](#custom-token-pools) section. Pay special attention to [decimal compatibility considerations](#decimal-compatibility-considerations) as custom pools require manual decimal conversion implementation. -Without proper decimal conversion, the user's final balance can differ dramatically from their intended transfer amount. +## Token Handling Mechanisms -#### How to Handle Token Decimals +Before implementing token pools, you need to choose the appropriate [token handling mechanism](/ccip/concepts/cross-chain-token/overview#token-handling-mechanisms) for your cross-chain token transfers. This strategic decision determines which combination of token pools you'll deploy on source and destination blockchains. -All standard token pools (BurnMint, LockRelease) in the base token pool library automatically call `to_svm_token_amount` during the `release_or_mint_tokens` flow. This instruction: +The table below summarizes the different token handling mechanisms and the [recommended token pools](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs) to deploy for each scenario, ensuring a seamless token transfer process. -1. Reads the incoming amount. -1. Converts it from the source token decimals (incoming) to the local token decimals. -1. Returns a u64 or an error if the conversion exceeds u64::Max (maximum token supply on SVM-based blockchains). +| Token Handling Mechanism | Source Blockchain Token Pool Type | Destination Blockchain Token Pool Type | How it Works | +| ------------------------ | --------------------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Burn & Mint | BurnMint | BurnMint | - Standard burn and mint mechanism for CCT transfers. | +| Lock & Mint | LockRelease | BurnMint | - The source blockchain is the issuing blockchain.
- The LockRelease token pool must be deployed on the issuing blockchain. | +| Burn & Unlock | BurnMint | LockRelease | - The destination blockchain is the issuing blockchain.
- The BurnMint token pool burns tokens on the source blockchain, and the LockRelease token pool unlocks tokens on the issuing blockchain. | +| Lock & Unlock | LockRelease | LockRelease | - Tokens are locked on the source blockchain and unlocked on the destination blockchain.
- Can result in fragmented liquidity and requires careful management of liquidity across multiple blockchains to avoid stuck token transfers due to insufficient liquidity locked in the token pool on the destination blockchain. | -If you build a custom token pool, be sure to use [`to_svm_token_amount`](https://github.com/smartcontractkit/chainlink-ccip/blob/contracts-ccip-release/1.6.0/chains/solana/contracts/programs/base-token-pool/src/common.rs#L536) from the base token pool library to handle decimal differences correctly. +## Decimal Compatibility Considerations -It is important to note that CCTs with different decimal precision can impact the total number of tokens in circulation. Tokens locked/burned on the source chain might result in a smaller number of tokens minted/released on the destination chain due to decimal rounding. +Before implementing token pools, it's critical to understand how decimal differences across blockchains can impact your cross-chain token transfers. This section provides strategic guidance for making informed decisions about token deployment and decimal configuration. For initial decimal planning considerations when deploying your token, see [Decimal Planning](/ccip/concepts/cross-chain-token/svm/tokens#decimal-planning). - +### The Decimal Challenge -**Understanding Token Decimals** +When deploying a token across multiple blockchains, [token developers](/ccip/concepts/cross-chain-token/overview#token-developer) can configure different decimal places for each blockchain. However, this flexibility comes with important trade-offs: -When deploying a token, token developers can configure different decimal places for each blockchain. For example: +**Example Configuration:** -- **On Ethereum**: The developer sets 18 decimals (0.123456789123456789) -- **On Solana**: The developer sets 9 decimals (0.123456789) +- **Ethereum**: 18 decimals (0.123456789123456789) +- **Solana**: 9 decimals (0.123456789) -When transferring tokens between these blockchains, CCIP handles decimal conversion automatically, but must round numbers to match the destination's configured precision. +**What Happens During Transfers:** +When transferring between blockchains with different decimal precision, CCIP automatically handles conversion but **must round numbers** to match the destination's configured precision. -**Impact Scenarios** +### Impact on Token Supply -Consider a token developer who deployed their token across three blockchains with different decimal configurations: +Different decimal configurations can affect your token's total supply across chains: -- **Blockchain A**: High precision (18 decimals) -- **Blockchain B**: Low precision (9 decimals) -- **Blockchain C**: High precision (18 decimals) +| Transfer Direction | Result | Supply Impact | +| ------------------------ | --------------------------------------------------------------- | --------------------------------------------------------------- | +| **High → Low Precision** | Precision loss due to rounding (e.g., 18 decimals → 9 decimals) | **Permanent loss**: Tokens burned/locked exceed tokens released | +| **Low → High Precision** | No precision loss (e.g., 9 decimals → 18 decimals) | **No impact**: Perfect conversion possible | +| **Equal Precision** | No precision loss (e.g., 18 decimals → 18 decimals) | **No impact**: Perfect 1:1 transfers | -| Scenario | Transfer Path | Example | Impact | -| ---------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -| **High to Low Precision ❌** | A → B | • **Send from A**: 1.123456789123456789
• **Receive on B**: 1.123456789
**Lost**: 0.000000000123456789 | • **BurnMint**: Tokens permanently burned on Blockchain A
• **LockRelease**: Tokens locked in token pool on Blockchain A | -| **Low to High Precision ✅** | B → A | • **Send from B**: 1.123456789
• **Receive on A**: 1.123456789000000000 | • No precision loss | -| **Equal Precision ✅** | A → C | • **Send from A**: 1.123456789123456789
• **Receive on C**: 1.123456789123456789 | • No precision loss | +**Critical Considerations:** -#### Recommended Practices +- **BurnMint Pools**: Lost precision results in **permanently burned tokens** on the source chain +- **LockRelease Pools**: Lost precision results in **tokens permanently locked** in the source pool +- Small amounts are most affected by rounding; large transfers typically see minimal percentage impact - +### Strategic Recommendations + +**Primary Recommendation:** +Deploy tokens with the **same number of decimals across all blockchains** whenever possible. This completely eliminates precision loss during cross-chain transfers. + +**When Different Decimals Are Necessary:** + +- Only use different decimals when required by blockchain limitations +- Clearly communicate rounding risks to users in your UI +- Consider implementing transfer warnings for high-to-low precision transfers +- Plan for locked/burned token accumulation in your tokenomics + +**Development Considerations:** + +- Verify decimal configurations on both source and destination before going live +- Test small-amount transfers to understand rounding behavior +- Consider implementing minimum transfer amounts to minimize relative precision loss + +**Standard token pools** (BurnMint, LockRelease) handle decimal conversion automatically - no additional implementation required. + +**Custom token pools** must implement decimal conversion manually - see [Decimal Implementation Requirements](#decimal-implementation-requirements) for technical details. -- Deploy tokens with the same number of decimals across all blockchains whenever possible. - - This prevents loss of precision during cross-chain transfers. - - Different decimals should only be used when required by blockchain limitations (e.g., non-EVM chains with decimal constraints). -- Verify decimal configurations on both source and destination blockchains before transfers. -- Consider implementing UI warnings for transfers that might be affected by rounding. -- When using high-to-low precision transfers, be aware that: - - In BurnMint pools, lost precision results in permanently burned tokens. - - In LockRelease pools, lost precision results in tokens accumulating in the source pool. +## Standard Token Pools: An Overview -## Standard Token Pools +Chainlink provides two standard token pool types that implement the token handling mechanisms described above. Each pool type implements specific logic for how tokens are managed during cross-chain transfers. -Depending on your use case (i.e., token handling mechanism), you must deploy the appropriate token pool type for each blockchain you want to support. Chainlink provides a set of [token pool programs](https://github.com/smartcontractkit/chainlink-ccip/tree/contracts-ccip-release/1.6.0/chains/solana/contracts/programs) that you can use to deploy your token pools in minutes. These token pool programs are fully audited and ready for deployment on your blockchains, but should be validated that they meet your use case requirements. Each program inherits the same underlying [`base-token-pool`](https://github.com/smartcontractkit/chainlink-ccip/tree/contracts-ccip-release/1.6.0/chains/solana/contracts/programs/base-token-pool), which provides shared data structures, rate-limiting logic, and other core functionality. +### SVM Program Architecture Overview -### Base Token Pool +On SVM-based blockchains like Solana, applications consist of **programs** (executable code) and **accounts** (data storage). Programs are stateless and store their data in separate accounts. -The base-token-pool library serves as the foundation for SVM-based token pools. It provides: +**Program-Derived Addresses (PDAs)** are special accounts with addresses [deterministically derived](https://solana.com/docs/core/pda) from seeds and a program ID. PDAs have no private keys, allowing programs to "sign" for them. This enables secure, predictable account management. -- **Core Data Structures** - - `BaseConfig` stores information such as the token's mint, the router program ID, and other essentials. - - `BaseChain` and `RemoteConfig` track cross-chain configuration data, including remote token pool, token addresses, and rate-limit settings. -- **Rate Limiter** - - A token bucket implementation that throttles outbound or inbound token transfers. -- **Allowlist (optional)** - - An optional sender validation that restricts which addresses can initiate cross-chain transfers. Token administrators can enable/disable the allowlist with `configure_allow_list` instruction and add authorized senders to it, or remove addresses with the `remove_from_allow_list` instruction. -- **Shared Instruction Definitions** - - Common instructions like `transfer_ownership`, `accept_ownership`, `init_chain_remote_config`, and others. -- **Events and Errors** - - Reusable Solana events (e.g., `Burned`, `Minted`, `Locked`, `Released`) and error definitions (e.g., `InvalidToken`, `RateLimitReached`). +### CCIP Token Pool Architecture -You typically do not deploy the `base-token-pool` by itself. Instead, you use one of the standard programs—`BurnMint` or `LockRelease`—that extend this library with specialized token-transfer logic. +Both BurnMint and LockRelease token pool programs use PDAs to organize data into two categories: + +- **Global PDAs**: Shared configuration for all pools deployed from this program +- **Pool-Specific PDAs**: Individual configuration for each token's pool + +Each token has its own independent pool (one pool per mint), with pool-specific PDAs derived using the mint address as a seed. + +### Program-Derived Addresses (PDAs) + +**Global Configuration:** + +- **Global Config PDA** (`seeds: ["config"]`): Program-wide settings including `self_served_allowed`, default router, and RMN remote addresses + +**Pool-Specific Configuration (per mint):** + +- **Pool State PDA** (`seeds: ["ccip_tokenpool_config", mint]`): Token-specific pool configuration, ownership, and operational settings +- **Pool Signer PDA** (`seeds: ["ccip_tokenpool_signer", mint]`): Signing authority for token operations (burns, mints, transfers) +- **Chain Config PDAs** (`seeds: ["ccip_tokenpool_chainconfig", chain_selector, mint]`): Per-destination chain configuration including rate limits and remote pool addresses + +The detailed sections below will help you understand the specific requirements and implementation details for each pool type. ### BurnMint Token Pool -The [`burnmint-token-pool`](https://github.com/smartcontractkit/chainlink-ccip/tree/contracts-ccip-release/1.6.0/chains/solana/contracts/programs/burnmint-token-pool) implements a program that: + + +The BurnMint token pool provides burn and mint operations for cross-chain token transfers: + +#### How It Works + +**Outbound token transfer (when the SVM chain is the source chain):** + +- User transfers tokens to the pool's Associated Token Account (ATA) +- Pool program burns the tokens using the standard SPL burn instruction +- Tokens are permanently removed from circulation on the source chain + +**Inbound token transfer (when the SVM chain is the destination chain):** + +- Pool program mints new tokens using the SPL `mint_to` instruction +- New tokens are created in the user's associated token account (ATA) +- Pool program must control the `mint_authority` for the token + +#### BurnMint Pool Specifics + +The BurnMint token pool specializes in burn and mint operations, requiring specific mint authority management for minting operations. + +#### Mint Authority Management + +**Mint Authority Control:** + +The mint authority follows this lifecycle for BurnMint pools: + +**Required First: Pool Initialization** + +- You must control the token's `mint_authority` to initialize the pool +- The [`initialize`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#initialize) instruction requires the mint authority as the signer +- **The pool automatically sets the initializer as the pool owner during initialization** +- Pool owner must create the [Associated Token Account (ATA)](https://www.solana-program.com/docs/associated-token-account) for the Pool Signer PDA before pool operations can begin + + + +**Ongoing: Pool Management** + +- As the pool owner, you can configure CCIP settings throughout the pool's lifetime: + - Set up chain configurations for new remote chains + - Configure or update rate limits for existing chains + - Manage allowlists and other pool settings + - Add or remove remote pool addresses + - **Transfer pool ownership to any address using [`transfer_ownership`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#transfer_ownership)** + +**When Ready: Mint Authority Transfer** + +- Transfer the `mint_authority` when you're ready to enable the pool for minting operations +- This enables the pool to mint tokens on inbound flows when the SVM chain is the destination +- Choose one of two transfer mechanisms (multisig approach strongly recommended for production): + +**Option 1: Direct Transfer (Simple)** + +**Configuration:** + +- Transfer the `mint_authority` directly to the Pool Signer PDA + +**Best suited for:** + +- Development environments +- Simple production deployments where the token exclusively integrates with CCIP +- Scenarios with a single trusted actor interacting with the token + +**Limitations:** + +- Only the token pool can mint tokens +- Reduced flexibility for future integrations + +**Option 2: Multisig Configuration (Recommended for Production)** + +**Configuration:** + +- Set up an M-of-N [SPL token multisig account](https://spl.solana.com/token#multisig-usage) as the mint authority +- Include the Pool Signer PDA as a required signer **exactly M times** (where M is your threshold) +- Include additional signers under your exclusive control as needed + +**SPL Token Multisig Requirements:** + +- **Threshold (M)**: Any value from 1 to N (your choice based on security needs) +- **Total Signers (N)**: At least 2 signers total +- **Pool Signer Repetition**: The Pool Signer PDA must appear **at least M times** in the signer list (typically exactly M times for optimal configuration) +- **Additional Signers**: Remaining (N-M) signer slots for your governance control + +**Valid Configuration Examples:** + +| Threshold (M) | Total Signers (N) | Pool Signer PDA Occurrences | Your Signers | +| ------------- | ----------------- | --------------------------- | ------------ | +| 1 | 3 | 1 | 2 | +| 2 | 4 | 2 | 2 | +| 2 | 5 | 2 | 3 | +| 3 | 6 | 3 | 3 | + +**Key benefits:** + +- Enables multiple authorized parties to mint tokens +- Maintains governance control through other multisig signers +- Provides extensibility for future integrations +- Enhanced security through distributed control +- Flexible threshold configuration for different security requirements + +**Technical Requirements:** + +- Must use [SPL token multisig](https://spl.solana.com/token#multisignatures) - other multisig implementations are not supported +- The Pool Signer PDA must be included at least M times as a multisig signer +- Pool must be able to mint tokens for cross-chain transfers without requiring additional manual signatures + +**Why Pool Signer Must Appear At Least M Times:** + +This design ensures the pool can always mint tokens for cross-chain transfers without requiring your manual intervention, while still maintaining your governance control: + +- **Autonomous Operation**: Pool operations always have sufficient signatures (≥M occurrences of Pool Signer) +- **Governance Control**: Your additional signers can still initiate mint operations independent of the pool (≤N-M pool signer occurrences ensures ≥M governance signer slots remain) +- **Flexible Security**: You choose the threshold (M) based on your security requirements, constrained by M ≤ N/2 +- **Optimal Configuration**: Most deployments use exactly M pool signer occurrences for optimal balance + +**Multisig Configuration Validation:** + +The system validates your multisig configuration with these rules: + +- `total_signers >= 2` (must have at least 2 signers) +- `threshold >= 1` (must require at least 1 signature) +- `threshold <= total_signers` (can't require more signatures than available signers) +- `pool_signer_occurrences >= threshold` (Pool Signer PDA must appear at least M times for autonomous operation) +- `pool_signer_occurrences <= (total_signers - threshold)` (Pool Signer PDA cannot occupy all governance signer slots) + +**Constraint Implications:** + +- **Minimum Pool Signer Occurrences**: M times (enables autonomous pool operation) +- **Maximum Pool Signer Occurrences**: N-M times (preserves governance control capability) +- **Threshold Limit**: M ≤ N/2 (ensures both pool autonomy and governance control are possible) + +**Common Misconceptions:** + +To ensure proper implementation, avoid these common misconceptions about SPL token multisig configurations: + +**Incorrect**: "Only 1-of-N multisig is supported" +**Correct**: "Any M-of-N multisig is supported with proper Pool Signer repetition" + +**Incorrect**: "Pool Signer appears once in the multisig" +**Correct**: "Pool Signer appears at least M times (typically exactly M times) in the multisig" + +**Incorrect**: "Pool can operate with any multisig configuration" +**Correct**: "Pool Signer must appear ≥M and ≤(N-M) times to ensure both autonomous operation and governance control capability" + +**Incorrect**: "Any threshold M is valid for any total signers N" +**Correct**: "Threshold M must satisfy M ≤ N/2 to allow both pool autonomy and governance control" + +After this transfer, the pool can mint tokens when the SVM chain is the destination chain for cross-chain transfers. + + + +#### Access Control + +Understanding who can call which instructions is critical for secure pool operation and proper integration. This table shows the authorization model for all BurnMint token pool instructions, helping you understand the security boundaries and operational responsibilities. + +| Instruction Category | Instruction | Program Upgrade Authority | Pool Owner | Router Authority | +| -------------------- | -------------------------------------------------------------------------------------------------------------------------------- | :-----------------------: | :--------: | :--------------: | +| **Global Config** | [`init_global_config`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#init_global_config) | ✅ | ❌ | ❌ | +| | [`update_self_served_allowed`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#update_self_served_allowed) | ✅ | ❌ | ❌ | +| | [`update_default_router`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#update_default_router) | ✅ | ❌ | ❌ | +| | [`update_default_rmn`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#update_default_rmn) | ✅ | ❌ | ❌ | +| **Pool Lifecycle** | [`initialize`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#initialize) | ✅ OR Mint Authority | ❌ | ❌ | +| **Ownership** | [`transfer_ownership`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#transfer_ownership) | ❌ | ✅ | ❌ | +| | [`accept_ownership`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#accept_ownership) | ❌ | ✅\*\* | ❌ | +| **Security** | [`transfer_mint_authority_to_multisig`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#transfer_mint_authority_to_multisig) | ✅ | ❌ | ❌ | +| | [`configure_allow_list`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#configure_allow_list) | ❌ | ✅ | ❌ | +| | [`remove_from_allow_list`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#remove_from_allow_list) | ❌ | ✅ | ❌ | +| **Chain Config** | [`init_chain_remote_config`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#init_chain_remote_config) | ❌ | ✅ | ❌ | +| | [`edit_chain_remote_config`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#edit_chain_remote_config) | ❌ | ✅ | ❌ | +| | [`append_remote_pool_addresses`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#append_remote_pool_addresses) | ❌ | ✅ | ❌ | +| | [`set_chain_rate_limit`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#set_chain_rate_limit) | ❌ | ✅ | ❌ | +| | [`delete_chain_config`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#delete_chain_config) | ❌ | ✅ | ❌ | +| **Cross-Chain** | [`lock_or_burn_tokens`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#lock_or_burn_tokens) | ❌ | ❌ | ✅ | +| | [`release_or_mint_tokens`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#release_or_mint_tokens) | ❌ | ❌ | ✅ | + +**Notes:** + +- \* **accept_ownership**: Must be the `proposed_owner` from `transfer_ownership` +- **Critical**: Pool Signer PDA MUST have mint capability (direct or via multisig) for minting operations +- **Critical**: Pool owner must create the [Associated Token Account (ATA)](https://www.solana-program.com/docs/associated-token-account) for the Pool Signer PDA before pool operations can begin -1. **Burns tokens**: - - When users initiate a cross-chain transfer from an SVM-based blockchain, they transfer tokens into the pool's Associated Token Account (ATA). - - The pool program then calls the standard SPL burn instruction, removing those tokens from circulation. -1. **Mints tokens**: - - On the destination blockchain, the pool program must hold the `mint_authority` (Read the [Mint Authority for BurnMint](/ccip/concepts/cross-chain-token/svm/tokens#mint-authority-for-burnmint) section for more information). - - It invokes the SPL `mint_to` instruction via CPI, creating new tokens for the user's ATA. +#### When to Use -For many cross-chain use cases—especially when transferring a token from an SVM-based blockchain to another blockchain—BurnMint is the most straightforward approach if your token supply is meant to expand (mint) or contract (burn) on different blockchains. +**Key Characteristics:** -**When to Use:** +- Requires mint authority control for initialization, then transfer to pool for operations +- Total supply can vary across chains during transfers +- No liquidity management needed +- Suitable for tokens designed to expand/contract supply -- You can configure the `mint_authority`. -- Use it as part of the Burn and Mint or Lock and Mint/Burn and Unlock token handling mechanisms. Read the [Token Handling Mechanism section](/ccip/concepts/cross-chain-token/svm/tokens#token-handling-mechanisms) for more information. +**Choose BurnMint When:** + +- You control the `mint_authority` for your token (required for initialization) +- You are willing to transfer mint authority to the pool after CCIP registration +- Your token is designed to have variable supply across chains +- You want to avoid liquidity management complexity +- Your token participates in [Burn and Mint](/ccip/concepts/cross-chain-token/overview#burn-and-mint) or [Lock and Mint/Burn and Unlock](/ccip/concepts/cross-chain-token/overview#lock-and-mint) token handling mechanisms + +For detailed mint authority configuration options, see [Mint Authority Management](#mint-authority-management). ### LockRelease Token Pool -The [`lockrelease-token-pool`](https://github.com/smartcontractkit/chainlink-ccip/tree/contracts-ccip-release/1.6.0/chains/solana/contracts/programs/lockrelease-token-pool) token pool implements a program that: + + +The LockRelease token pool implements a lock-and-release strategy for cross-chain token transfers: + +#### How It Works + +**Outbound token transfer (when the SVM chain is the source chain):** + +- User transfers tokens to the pool's Associated Token Account (ATA) +- Pool program "locks" tokens by holding them in its account +- Tokens remain in circulation but are held by the pool as escrow +- No tokens are destroyed - total supply remains constant + +**Inbound token transfer (when the SVM chain is the destination chain):** + +- Pool program transfers tokens from its ATA to the user's ATA +- Pool must have sufficient token balance (liquidity) to fulfill transfers +- No minting occurs - only transfers of existing tokens from the pool's reserves + +#### LockRelease Pool Specifics + +The LockRelease token pool specializes in lock and release operations, requiring liquidity management rather than mint authority control. Unlike BurnMint pools, LockRelease pools: + +- **Do not require mint authority transfer** - the original mint authority remains unchanged +- **Rely on token reserves** - manage liquidity through the pool's token holdings +- **Use rebalancer role** - designated address manages liquidity operations + +#### Liquidity Management + +**Pool Initialization:** + +- Program upgrade authority can always initialize pools +- When self-serve is enabled (`self_served_allowed: true`), the token's mint authority can also initialize pools +- **The pool automatically sets the initializer as the pool owner during initialization** +- Pool is configured with liquidity acceptance settings during initialization +- Pool owner must create the [Associated Token Account (ATA)](https://www.solana-program.com/docs/associated-token-account) for the Pool Signer PDA before pool operations can begin + + + +**Ongoing Liquidity Operations:** + +- **Rebalancer Role**: Designated address that can provide or withdraw pool liquidity +- **Liquidity Acceptance**: Configurable setting (`can_accept_liquidity`) controls whether the pool accepts new liquidity +- **Liquidity Operations**: + - `provide_liquidity`: Rebalancer adds tokens to pool reserves + - `withdraw_liquidity`: Rebalancer removes tokens from pool reserves (can transfer to other pools) + +**Liquidity Requirements:** + +- Pool must maintain sufficient token balance to fulfill cross-chain transfers +- Insufficient liquidity will cause transfer failures +- Rebalancer responsible for maintaining adequate liquidity across all supported chains -1. **Locks Tokens**: +#### Access Control - - Users send tokens to the pool's ATA. - - The pool program "locks" these tokens (i.e., holds them in its account). +Understanding who can call which instructions is critical for secure pool operation and proper integration. This table shows the authorization model for all LockRelease token pool instructions, helping you understand the security boundaries and operational responsibilities. -1. **Releases Tokens**: +| Instruction Category | Instruction | Program Upgrade Authority | Pool Owner | Router Authority | Rebalancer | +| -------------------- | --------------------------------------------------------------------------------------------------------------------- | :-----------------------: | :--------: | :--------------: | :--------: | +| **Global Config** | [`init_global_config`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#init_global_config) | ✅ | ❌ | ❌ | ❌ | +| | [`update_self_served_allowed`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#update_self_served_allowed) | ✅ | ❌ | ❌ | ❌ | +| | [`update_default_router`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#update_default_router) | ✅ | ❌ | ❌ | ❌ | +| | [`update_default_rmn`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#update_default_rmn) | ✅ | ❌ | ❌ | ❌ | +| **Pool Lifecycle** | [`initialize`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#initialize) | ✅ OR Mint Authority | ❌ | ❌ | ❌ | +| **Ownership** | [`transfer_ownership`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#transfer_ownership) | ❌ | ✅ | ❌ | ❌ | +| | [`accept_ownership`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#accept_ownership) | ❌ | ✅\*\* | ❌ | ❌ | +| **Security** | [`configure_allow_list`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#configure_allow_list) | ❌ | ✅ | ❌ | ❌ | +| | [`remove_from_allow_list`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#remove_from_allow_list) | ❌ | ✅ | ❌ | ❌ | +| **Liquidity Mgmt** | [`set_rebalancer`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#set_rebalancer) | ❌ | ✅ | ❌ | ❌ | +| | [`set_can_accept_liquidity`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#set_can_accept_liquidity) | ❌ | ✅ | ❌ | ❌ | +| | [`provide_liquidity`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#provide_liquidity) | ❌ | ❌ | ❌ | ✅ | +| | [`withdraw_liquidity`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#withdraw_liquidity) | ❌ | ❌ | ❌ | ✅ | +| **Chain Config** | [`init_chain_remote_config`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#init_chain_remote_config) | ❌ | ✅ | ❌ | ❌ | +| | [`edit_chain_remote_config`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#edit_chain_remote_config) | ❌ | ✅ | ❌ | ❌ | +| | [`append_remote_pool_addresses`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#append_remote_pool_addresses) | ❌ | ✅ | ❌ | ❌ | +| | [`set_chain_rate_limit`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#set_chain_rate_limit) | ❌ | ✅ | ❌ | ❌ | +| | [`delete_chain_config`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#delete_chain_config) | ❌ | ✅ | ❌ | ❌ | +| **Cross-Chain** | [`lock_or_burn_tokens`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#lock_or_burn_tokens) | ❌ | ❌ | ✅ | ❌ | +| | [`release_or_mint_tokens`](/ccip/api-reference/svm/v0.1.1/lock-release-token-pool#release_or_mint_tokens) | ❌ | ❌ | ✅ | ❌ | - - The pool program transfers tokens from its ATA to the user's ATA, effectively "unlocking" them on the destination side. +**Notes:** -In this scenario, **no mint authority** is needed. +- \* **accept_ownership**: Must be the `proposed_owner` from `transfer_ownership` +- **Critical**: Pool owner must create the [Associated Token Account (ATA)](https://www.solana-program.com/docs/associated-token-account) for the Pool Signer PDA before pool operations can begin -The Lock & Release token pool includes additional functionality for managing liquidity: +#### When to Use -- **Rebalancer Role**: A designed public key that can move tokens in and out of the pool. -- **Liquidity Acceptance**: Controls whether the pool can receive additional liquidity. -- **Liquidity Operations**: Functions to add or withdraw liquidity from the pool. +**Key Characteristics:** -**When to Use:** +- Program upgrade authority can always initialize pools; mint authority can self-initialize when accessible +- No mint authority required for ongoing operations (unlike BurnMint) +- Fixed total supply per chain - tokens are only transferred, never created or destroyed +- Requires active liquidity management and funding +- Suitable for tokens where you want to retain mint authority control OR where mint authority is no longer accessible -- Your token's mint authority is disabled or inaccessible. -- You want a fixed total supply on the blockchain where the token pool is deployed. -- Use it as part of the Lock and Mint/Burn and Unlock or Lock and Unlock token handling mechanisms. Read the [Token Handling Mechanism section](/ccip/concepts/cross-chain-token/svm/tokens#token-handling-mechanisms) for more information. +**Choose LockRelease When:** + +- You want to retain control of the token's mint authority (not transfer it to the pool) +- Your token's mint authority is disabled/revoked (e.g., to cap token supply) or otherwise inaccessible +- You prefer not to delegate minting capabilities to the token pool +- You want to maintain fixed total supply on each blockchain +- You can manage liquidity requirements and rebalancing across chains +- You have operational capacity to monitor and maintain pool liquidity levels +- Your token participates in [Lock and Mint/Burn and Unlock](/ccip/concepts/cross-chain-token/overview#burn-and-unlock) or [Lock and Unlock](/ccip/concepts/cross-chain-token/overview#lock-and-unlock) token handling mechanisms + +Both pool types are built on the shared [`base-token-pool`](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs/base-token-pool) foundation, which provides common functionality including [rate limiting](/ccip/concepts/cross-chain-token/overview#token-pool-rate-limits), allowlists, cross-chain configuration, and event handling. + +## Next Steps: Pool Configuration + +After deploying your token pool using any of the approaches above, you'll need to configure it for cross-chain operations. This includes: + +- Setting up remote chain configurations +- Configuring rate limits for cross-chain transfers +- Managing allowlists and access controls +- Setting up liquidity management (for LockRelease pools) + +For detailed instructions on configuring your token pool parameters, see [Token Pool Configuration](/ccip/concepts/cross-chain-token/svm/registration-administration#token-pool-configuration-pool-side). ## Custom Token Pools -If the standard BurnMint and LockRelease token pool programs don't meet your requirements, you can create a custom token pool program that is compatible with CCIP. This typically involves integrating the `base-token-pool` library for core functionality (ownership, rate-limiting, cross-chain instructions) and extending it with your custom logic (e.g., handling rebasing tokens). +If the standard BurnMint and LockRelease token pool programs don't meet your requirements, you can create a custom token pool program that is compatible with CCIP. This advanced approach gives you complete control over token handling logic while maintaining CCIP compatibility. + +### When to Build Custom Token Pools + +**Consider building a custom token pool when:** + +- **Complex Token Mechanics**: Your token has unique behavior like rebasing, fee-on-transfer, or complex reward mechanisms +- **Specialized Business Logic**: You need custom validation, compliance checks, or integration with other protocols +- **Governance Requirements**: You need custom access control patterns + +**Standard pools are sufficient for:** + +- Basic SPL tokens with standard mint/burn/transfer functionality +- Tokens that don't require custom logic during cross-chain transfers +- SPL tokens and Token-2022 tokens + +### Technical Requirements + +All custom token pools must implement the following requirements to be CCIP-compatible: + +#### Required Program-Derived Addresses (PDAs) + +Your custom token pool **must** use these exact PDA seeds so the CCIP Router can correctly derive and interact with your pool accounts: + +**Required PDAs and Their Seeds:** + +1. **Global Config PDA** + + - Seeds: `["config"]` + - Purpose: Program-wide settings including `self_served_allowed`, default router, and RMN addresses + - Used by: Program admin for deployment configuration + +1. **Pool State PDA** + + - Seeds: `["ccip_tokenpool_config", mint_address]` + - Purpose: Token-specific pool configuration, ownership, and operational settings + - Used by: Pool management and cross-chain operations + +1. **Pool Signer PDA** + + - Seeds: `["ccip_tokenpool_signer", mint_address]` + - Purpose: Signing authority for token operations (burns, mints, transfers) + - Used by: Token transfer operations and mint authority control + +1. **Chain Config PDAs** + - Seeds: `["ccip_tokenpool_chainconfig", chain_selector, mint_address]` + - Purpose: Per-destination chain configuration including rate limits and remote pool addresses + - Used by: Cross-chain transfer validation and routing + + + +#### Mandatory Instructions + +When CCIP interacts with your custom token pools, it expects the presence of the following functions with exact signatures: + +1. **For source chain operations (locking or burning tokens):** + + - [`lock_or_burn_tokens(ctx: Context, lock_or_burn: LockOrBurnInV1,) -> Result`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#lock_or_burn_tokens) + - This function handles token operations when your chain is the source of a cross-chain transfer + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/base-token-pool#lockorburnoutv1) to learn more about the parameters + +1. **For destination chain operations (releasing or minting tokens):** + + - [`release_or_mint_tokens(ctx: Context, release_or_mint: ReleaseOrMintInV1,) -> Result`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#release_or_mint_tokens) + - This function handles token operations when your chain is the destination of a cross-chain transfer + - Read the [API reference](/ccip/api-reference/svm/v0.1.1/base-token-pool#releaseormintinv1) to learn more about the parameters + +#### Integration with Base Token Pool + +All custom token pools should integrate the [`base-token-pool`](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs/base-token-pool) library for core functionality: + +- **Ownership management**: Pool ownership and proposed ownership transfers +- **Rate limiting**: Inbound and outbound rate limit controls per destination chain +- **Cross-chain configuration**: Remote pool addresses and chain-specific settings +- **Access control**: Allowlists and permission management +- **Event handling**: Standardized event emissions for monitoring +- **Decimal conversion**: Use `to_svm_token_amount` for proper decimal handling between chains + +#### Decimal Implementation Requirements + +All custom token pools **must** implement proper decimal conversion to handle tokens with different decimal configurations across blockchains. For strategic guidance on decimal compatibility decisions, see [Decimal Compatibility Considerations](#decimal-compatibility-considerations). + +**Required Implementation:** + +All standard token pools (BurnMint, LockRelease) automatically call [`to_svm_token_amount`](/ccip/api-reference/svm/v0.1.1/base-token-pool#to_svm_token_amount) during the [`release_or_mint_tokens`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#release_or_mint_tokens) flow. If you build a custom token pool, you **must** use [`to_svm_token_amount`](/ccip/api-reference/svm/v0.1.1/base-token-pool#to_svm_token_amount) from the base token pool library. + +**How [`to_svm_token_amount`](/ccip/api-reference/svm/v0.1.1/base-token-pool#to_svm_token_amount) Works:** + +1. Reads the incoming amount from the source chain +1. Converts it from the source token decimals to the local token decimals +1. Returns a u64 amount or an error if the conversion exceeds u64::Max (maximum token supply on SVM-based blockchains) + + + +### Implementation Examples + +#### Example 1: Rebasing Token Pool + +**Use Case**: Rebasing tokens adjust their supply periodically based on external parameters (e.g., price, yield). These tokens require custom logic to handle rebasing events during cross-chain transfers. + +**Implementation Approach**: + +- **Source Blockchain**: Instead of burning or locking a specific amount of tokens, track "underlying shares" that represent proportional ownership. In [`lock_or_burn_tokens`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#lock_or_burn_tokens), convert the user's tokens into an internal share count and store that in [`LockOrBurnOutV1.dest_pool_data`](/ccip/api-reference/svm/v0.1.1/base-token-pool#lockorburnoutv1) for the destination token pool. + +- **Destination Blockchain**: In [`release_or_mint_tokens`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#release_or_mint_tokens), parse the share count from [`ReleaseOrMintInV1.source_pool_data`](/ccip/api-reference/svm/v0.1.1/base-token-pool#releaseormintinv1) and convert those shares back into the current token amount based on the latest rebase. If your token supply has been rebased upward/downward since the transfer initiated, recalculate the final amount before minting or transferring to the user's ATA. + +#### Example 2: Fee-on-Transfer Token Pool + +**Use Case**: Tokens that deduct fees during transfers need custom logic to ensure cross-chain transfer amounts are accurate. + +**Implementation Approach**: + +- **Source Blockchain**: In [`lock_or_burn_tokens`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#lock_or_burn_tokens), calculate the net amount after fees and ensure the correct amount is locked/burned. Store the original intended amount in `dest_pool_data`. + +- **Destination Blockchain**: In [`release_or_mint_tokens`](/ccip/api-reference/svm/v0.1.1/burn-mint-token-pool#release_or_mint_tokens), use the original intended amount from `source_pool_data` to mint/release the correct amount, accounting for any destination-side fees. + +### Development Resources + +**Implementation References:** + +- [BurnMint Token Pool](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs/burnmint-token-pool) - Standard burn/mint implementation +- [LockRelease Token Pool](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs/lockrelease-token-pool) - Standard lock/release implementation +- [Base Token Pool Library](https://github.com/smartcontractkit/chainlink-ccip/tree/v0.1.1-solana/chains/solana/contracts/programs/base-token-pool) - Shared functionality foundation -Below is an example of a token rebasing use case that requires building your own custom token pool: +**Testing and Validation:** -- **Use Case**: - - Rebasing tokens are a unique type of token that adjusts their supply in response to specific parameters (e.g., price or yield distribution). These tokens require custom logic to handle rebasing events during cross-chain transfers. -- **Solution**: - - **Source Blockchain**: Instead of burning or locking a specific amount of tokens, you might track "underlying shares" that map to a rebase or a fee adjustment. In `lock_or_burn_tokens`, convert the user's tokens into an internal share count and store that in `LockOrBurnOutV1.dest_pool_data` for the destination token pool. - - **Destination Blockchain**: In `release_or_mint_tokens`, parse the share count from `ReleaseOrMintInV1.source_pool_data` and then convert those shares back into the appropriate number of tokens. If your token supply has been rebased upward/downward, recalculate before minting or transferring to the user's ATA. +- Test with CCIP Router integration to ensure proper PDA derivation +- Validate decimal conversion handling for cross-chain transfers +- Ensure rate limiting and access control functions work correctly +- Test both source and destination chain operations thoroughly diff --git a/src/content/ccip/concepts/cross-chain-token/svm/tokens.mdx b/src/content/ccip/concepts/cross-chain-token/svm/tokens.mdx index c4b2417c4fd..48a0fe574ad 100644 --- a/src/content/ccip/concepts/cross-chain-token/svm/tokens.mdx +++ b/src/content/ccip/concepts/cross-chain-token/svm/tokens.mdx @@ -3,189 +3,110 @@ section: ccip date: Last Modified title: "Cross-Chain Token Standard - Tokens (SVM)" metadata: - description: "Learn CCIP integration requirements for SPL tokens on SVM chains. Covers compatibility (SPL Token, Token-2022), registration (mint authority), and transfer functions." + description: "Essential guide for integrating SPL tokens with CCIP on SVM chains like Solana. Covers token compatibility requirements, decimal considerations, registration using mint authority, pool type selection (BurnMint vs LockRelease), and Token-2022 support." + excerpt: "CCIP, SPL tokens, SVM, Solana, Token-2022, mint authority, token administrator, registration, self-registration, BurnMint, LockRelease, pool selection, token pools, cross-chain transfers, compatibility, associated token accounts, decimals, token programs" --- import { Aside } from "@components" import CcipCommon from "@features/ccip/CcipCommon.astro" - +This document provides essential guidance for integrating tokens with Chainlink CCIP on SVM-based blockchains, such as Solana, using the Cross-Chain Token (CCT) standard. It covers token compatibility requirements, decimal planning considerations, registration processes, and strategic guidance for selecting the right token pool type for your use case. -This document provides comprehensive guidance for integrating tokens with Chainlink CCIP on SVM-based blockchains, such as Solana, using the Cross-Chain Token (CCT) standard. It outlines the compatibility requirements, registration processes, and transfer functions essential for ensuring that tokens operate seamlessly with CCIP. + ## Compatibility Before implementing CCIP support for your token, it's crucial to understand the compatibility requirements. These requirements ensure proper functionality of your token within the CCIP ecosystem. -### Basic Compatibility Requirements - -1. **Supported Token Programs**: Only tokens managed by either the standard SPL Token program or the Token-2022 (Token Extensions) program are compatible with CCIP. -1. **Interface Requirements**: For all tokens, especially those using Token-2022 extensions, ensure: - - **Associated Token Accounts (ATA)**: The token program must support creation and use of ATAs - - **Decimals**: The token must provide decimal precision via `mint.decimals` - - **Program Identification**: The token program must be correctly referenced through `mint.to_account_info().owner` +### Mandatory Compatibility Requirements -### Token Pool Compatibility +All tokens must meet these requirements for CCIP compatibility: -When using standard CCIP Token Pool Program templates, your token must be compatible with one of the following token pool types: +1. **Supported Token Programs**: Must use either the standard SPL Token program or Token-2022 (Token Extensions) program +1. **Interface Requirements**: Must support standard token interfaces: + - **Associated Token Accounts (ATA)**: Required for all CCIP operations + - **Decimals**: Must provide decimal precision via `mint.decimals` + - **Program Identification**: Must be correctly referenced through `mint.to_account_info().owner` -#### BurnMint Token Pool +### Decimal Planning -For token pools that burn tokens during outbound transfers (via OnRamp) and mint tokens during inbound transfers (via OffRamp): +When deploying your token across multiple blockchains, **decimal configuration is a critical strategic decision** that affects cross-chain transfer behavior and token supply management: -- The token's mint authority must be delegateable -- The token program must support the `mint_to` instruction -- The token program must support the `burn` instruction +**Key Decision:** Deploy your token with the **same number of decimals across all blockchains** whenever possible. This eliminates precision loss during cross-chain transfers. -#### LockRelease Token Pool +**Impact on Token Pools:** -For token pools that lock tokens during outbound transfers and release them during inbound transfers: +- **Different decimals**: Can result in precision loss and permanently locked/burned tokens +- **Same decimals**: Enable perfect 1:1 cross-chain transfers -- The token program must support the `transfer_checked` instruction +For comprehensive guidance on decimal compatibility impacts, strategic recommendations, and technical implementation requirements, see [Decimal Compatibility Considerations](/ccip/concepts/cross-chain-token/svm/token-pools#decimal-compatibility-considerations). -### Custom Token Pool Implementation - -Token developers can alternatively implement their own custom Token Pool Programs to support additional Token-2022 extensions not supported by the standard token pools. Custom implementations must adhere to CCIP's interface specifications while allowing developers to control which instructions are called when handling tokens. +### Token Requirements by Pool Type -## Registration Functions +Your token's requirements depend on which token pool type you'll deploy, determined by your chosen [token handling mechanism](/ccip/concepts/cross-chain-token/svm/token-pools#token-handling-mechanisms). Refer to the token handling mechanisms table to understand which pool type you need for your SVM chain deployment. -To enable a CCT in CCIP, ensure you can assign or confirm the token administrator. On SVM-based blockchains (e.g., Solana), this typically means having control over the `mint_authority` of the token's Mint account. The CCIP Router program uses this authority to verify that you can set a "token administrator" in its onchain registry. +#### BurnMint Pool -### Self-Registration +**Token Requirements:** -To self-register your CCT under CCIP, you use the `owner_propose_administrator` instruction provided by the CCIP Router. It works as follows: +- Must support `mint_to` and `burn` instructions +- **Mint authority** must be transferable (directly to pool signer PDA or via SPL Token Multisig). See [BurnMint Pool mint authority configuration](/ccip/concepts/cross-chain-token/svm/token-pools#mint-authority-management) for detailed multisig requirements -- **Mint Authority**: Only the signer holding the private key for the token's `mint_authority` can initiate the request. -- **Pending Administrator**: This instruction creates (or updates) a Token Admin Registry account and sets a pending administrator. -- **Accept Role**: The newly proposed administrator then calls `accept_admin_role_token_admin_registry` to complete the process. +#### LockRelease Pool -Once the registration is complete, the CCIP Router recognizes your token and lets its administrator configure a token pool (burnMint or lockRelease). +**Token Requirements:** -### Edge Cases +- Must support `transfer_checked` instruction +- **No mint authority requirements** (pool operates through transfers only) -If the token's `mint_authority` is no longer accessible—for example, if it was intentionally set to `None` to cap the total supply—and therefore token ownership cannot be verified using onchain data, a manual registration process can be performed on your behalf. This approach ensures that tokens remain eligible for CCIP integration even if their original `mint_authority` is permanently unavailable, while avoiding fragmentation and helping token developers remain in control of their CCTs. - - - -## Mint Authority for BurnMint +### Custom Token Pool Implementation -BurnMint token pools must hold the mint authority, which is required to mint tokens. On SVM-based blockchains, only a _single public key_ can serve as the mint authority. There are two approaches for managing mint authority, with the multisig approach being strongly recommended for production environments. +Token developers can alternatively implement their own custom Token Pool Programs to support additional Token-2022 extensions not supported by the standard token pools. Custom implementations must adhere to CCIP's interface specifications while allowing developers to control which instructions are called when handling tokens. -### Advanced Setup: Multisig as Mint Authority (Recommended for Production) +For technical requirements and implementation guidance for custom pools, see [Custom Token Pools](/ccip/concepts/cross-chain-token/svm/token-pools#custom-token-pools). -For production environments and complex use cases, implementing a multisig solution as the mint authority provides greater flexibility and security. +## Registration -#### Configuration details +To enable your token for CCIP cross-chain transfers, you must register it and establish a token administrator role. This process ensures secure assignment of administrative control over your token's CCIP integration. -- Implement a 1-of-N multisig where any authorized signer can initiate minting operations -- Include the token pool's Program Derived Address (PDA) as one of the authorized signers -- Ensure other signers remain under the exclusive control of the token owner +### Registration Requirements -#### Key benefits +- **Self-Registration**: If you control the token's `mint_authority`, you can complete registration automatically +- **Manual Registration**: If `mint_authority` is not accessible (e.g., set to `None` to cap supply), manual registration is available -- Enables multiple minters to interact with the token via a shared mint authority -- Provides centralized control for the token owner -- Maintains extensibility for future integrations +### Registration Process -#### Implementation Process for Multisig Setup +The registration follows a secure two-step process: -1. Initialize the token with a temporary mint authority -1. Deploy the BurnMint token pool program -1. Configure the Token Pool Signer PDA within the Token Pool Program -1. Register the token in the Token Admin Registry - - Set your desired account as the proposed administrator - - Verify the token's `mint_authority` matches the transaction signer -1. Establish the multisig - - Create a 1-of-N multisig configuration - - Include the Token Pool signer PDA as one of the authorized signers -1. Configure the administrator in the on-chain router registry -1. Set the multisig account as the token's `mint_authority` +1. **Propose Administrator**: Designate who will administer your token's CCIP integration +1. **Accept Role**: The proposed administrator must explicitly accept the role to complete registration -### Default Setup: Token Pool as Direct Mint Authority - -This configuration assigns the token pool's Program Derived Address (PDA) directly as the token's mint authority. - -#### Best suited for - -- Development environments -- Simple production deployments where the token exclusively integrates with CCIP -- Scenarios with a single trusted actor interacting with the token - -#### Implementation - -- The `mint_authority` of the token is directly set to the token pool signer PDA -- Simplifies deployment and initial configuration - -#### Limitations - -- Only the token pool can mint tokens -- Changes to mint authority may be constrained by the token pool program's capabilities - -## Token Handling Mechanisms - -To facilitate cross-chain token transfers, you need to choose the appropriate [token handling mechanism](/ccip/concepts/cross-chain-token/overview#token-handling-mechanisms) and deploy the correct combination of token pools for the source and destination blockchains. The table below summarizes the different token handling mechanisms and the [recommended token pools](https://github.com/smartcontractkit/chainlink-ccip/tree/contracts-ccip-release/1.6.0/chains/solana/contracts/programs) to deploy for each scenario, ensuring a seamless token transfer process. - -| Token Handling Mechanism | Source Blockchain Token Pool Type | Destination Blockchain Token Pool Type | How it Works | -| ------------------------ | --------------------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Burn & Mint | BurnMint | BurnMint | - Standard burn and mint mechanism for CCT transfers. | -| Lock & Mint | LockRelease | BurnMint | - The source blockchain is the issuing blockchain.
- The LockRelease token pool must be deployed on the issuing blockchain. | -| Burn & Unlock | BurnMint | LockRelease | - The destination blockchain is the issuing blockchain.
- The BurnMint token pool burns tokens on the source blockchain, and the LockRelease token pool unlocks tokens on the issuing blockchain. | -| Lock & Unlock | LockRelease | LockRelease | - Tokens are locked on the source blockchain and unlocked on the destination blockchain.
- Can result in fragmented liquidity and requires careful management of liquidity across multiple blockchains to avoid stuck token transfers due to insufficient liquidity locked in the token pool on the destination blockchain. | - -Below are the core requirements for SPL tokens to integrate with CCIP transfer operations. Depending on the token handling mechanism, you may use a BurnMint token pool on both blockchains or combine a LockRelease token pool on one chain with a BurnMint token pool on the other. - -### Burn and Mint Requirements - -In this token handling mechanism, the same token pool type (BurnMint) is used on both source and destination blockchains, so these requirements are similar for both blockchains. - -1. **Set the Token Pool as Mint Authority** - - - The token pool program must hold the mint authority to enable minting tokens. - - For further details on mint authority configurations, refer to the [Mint Authority for BurnMint](#mint-authority-for-burnmint) section. - -1. **Burning Tokens** - - - Solana's SPL Token Program has no separate "burn" permission. Instead, the token pool program must own the token account that holds the tokens to be burned. - - Users typically transfer their tokens to the token pool's associated token account (ATA), which the pool program controls. Once the tokens reside in that ATA, the pool program can execute burn as needed. - - Because the pool program does not automatically create this ATA, the token administrator must ensure it is initialized beforehand. This one-time setup guarantees that tokens can be safely sent to the token pool ATA. - -1. **Minting Tokens** - - Once the pool program is the mint authority, it can invoke `mint_to` via a CPI (cross-program invocation) into the SPL Token Program. - - This allows the program to call the token program to mint the corresponding tokens. - -### Lock and Mint Requirements - -Locking tokens is ideal for tokens that no longer have an accessible `mint_authority`. If the `mint_authority` has been disabled, you can still enable cross-chain functionality by locking tokens on the source blockchain and minting them on the destination blockchain. +For comprehensive guidance including detailed instructions, sequence diagrams, and administrator role management, see [Registration & Administration](/ccip/concepts/cross-chain-token/svm/registration-administration). -#### Lock and Mint +## Next Steps -1. **Source Blockchain: LockRelease token pool** +Once your token meets the compatibility requirements, you need to complete two key steps to enable cross-chain transfers: - - The token pool program has an Associated Token Account (ATA) where users send their tokens. - - Tokens received in this ATA are locked in escrow, meaning no `mint_authority` is required. - - The token administrator must create the token pool's ATA in advance to receive locked tokens. +### Register Your Token -1. **Destination Blockchain: BurnMint token pool** - - The BurnMint token pool holds the `mint_authority` on the destination blockchain. - - For further details on mint authority configurations, refer to the [Mint Authority for BurnMint](#mint-authority-for-burnmint) section. +Complete the token registration process to establish administrative control over your token's CCIP integration. -#### Burn and Unlock +For detailed instructions, sequence diagrams, and administrator role management, see [Registration & Administration](/ccip/concepts/cross-chain-token/svm/registration-administration). -1. **Source blockchain: BurnMint token pool** +### Deploy and Configure Token Pool - - Users send tokens to the token pool's ATA on the source blockchain. - - The token pool program then calls the SPL `burn` instruction on that account. +After registration, deploy and configure a token pool to enable cross-chain transfer operations. -1. **Destination blockchain: LockRelease token pool** - - On the destination blockchain, the token pool program holds locked tokens in an ATA. - - The token pool program transfers tokens from its ATA to the receiver's ATA. +For comprehensive implementation guidance including deployment approaches (self-serve, self-deployed, custom), detailed architecture requirements, and step-by-step configuration instructions, see [Token Pools documentation](/ccip/concepts/cross-chain-token/svm/token-pools). diff --git a/src/content/ccip/concepts/cross-chain-token/svm/upgradability.mdx b/src/content/ccip/concepts/cross-chain-token/svm/upgradability.mdx index 6cbb9548879..6c55c21725c 100644 --- a/src/content/ccip/concepts/cross-chain-token/svm/upgradability.mdx +++ b/src/content/ccip/concepts/cross-chain-token/svm/upgradability.mdx @@ -3,55 +3,148 @@ section: ccip date: Last Modified title: "Cross-Chain Token Standard - Upgradability (SVM)" metadata: - description: "Learn about upgrading CCIP token pools on SVM chains like Solana. Covers in-place upgrades, preserving mint authority, user workflow, and best practices." + description: "Learn about CCIP token pool upgrades on SVM chains like Solana. Covers the three deployment approaches: self-serve mode with governance-controlled updates (similar to SPL Token programs), self-deployed pools with user-controlled upgrades, and custom pool upgrade management." + excerpt: "CCIP, token pool upgrades, SVM, Solana, deployment approaches, self-serve mode, governance, multisig, timelock, node operators, SPL Token programs, self-deployed pools, custom pools, upgrade authority, in-place upgrades, mint authority, program ID, governance process, ManyChainMultiSig, MCMS, upgrade management" --- import { Aside } from "@components" import CcipCommon from "@features/ccip/CcipCommon.astro" - +Token pool upgradability on SVM-based blockchains (e.g., Solana) depends entirely on which [deployment approach](/ccip/concepts/cross-chain-token/svm/token-pools#deployment-approaches) you choose. Your upgrade responsibilities and capabilities vary significantly based on whether you use self-serve mode, deploy standard pools yourself, or build custom pools. -On SVM-based blockchains (e.g., Solana), token pools can be upgraded in place by token developers to preserve both the mint authority (for Burn and Mint pools) and the transaction workflow (for any token pool). Rather than deploying a brand-new program ID each time you change pool logic, you can push new code to the existing ID and maintain stability for all users referencing that pool. +## Upgrade Approaches by Deployment Type -## In-Place Upgrades +Your upgrade experience depends entirely on which deployment approach you chose when setting up your token pool: -1. **Retain Mint Authority (Burn and Mint Pools):** SPL tokens have a single `mint_authority`. When you delegate this authority to a Burn and Mint token pool program, that program holds the exclusive rights to mint tokens. As detailed in the [Mint Authority for BurnMint](/ccip/concepts/cross-chain-token/svm/tokens#mint-authority-for-burnmint) section of the Tokens page, while it is possible to deploy a new pool program and reassign the mint authority, doing so involves extra overhead. In-place upgrades allow you to: +### Approach 1: Self-Serve Mode (Recommended - No Action Required) + +**How it works:** + +This approach follows the same pattern as **SPL Token programs** on Solana: you create and manage your own token pools (like creating your own mints), but the underlying token pool programs are maintained by the program authority through established governance processes. + +**What it means for upgrades:** + +- **Governance-controlled upgrades**: The standard BurnMint and LockRelease programs are upgraded through CCIP's [governance process](/ccip/concepts/architecture/onchain/svm/upgradability) involving multisig approvals, timelock reviews, and node operator oversight +- **Seamless updates**: Security fixes and feature updates are deployed through the governance process without breaking your pool configuration or mint authority +- **No action required**: You don't manage program upgrades, similar to how you don't upgrade the SPL Token program when using standard Solana tokens +- **Preserved functionality**: Updates happen at the program level while your individual pool state and configuration remain intact + +**Your responsibilities:** + +- **None** - program upgrades are handled through CCIP governance +- Monitor CCIP announcements for new features or breaking changes +- Test your integration after major protocol updates + +**Benefits:** + +- Always up-to-date with latest security patches through proven governance +- No operational overhead for program upgrade management +- Professional maintenance through decentralized governance +- Immediate access to new CCIP features + + + +### Approach 2: Self-Deployed Standard Pools (User-Controlled Upgrades) + +**What it means for upgrades:** + +- **You control the upgrade authority** for your deployed standard pool programs +- **Manual upgrades**: You decide when to apply updates from the Chainlink repository +- **Full control**: You can customize timing, test extensively, and coordinate with your governance + +**Your responsibilities:** + +- Monitor Chainlink repository for new releases +- Test upgrades in development environments +- Execute upgrade transactions using Solana CLI or Anchor tooling +- Coordinate upgrades with your governance/operational processes + +### Approach 3: Custom Token Pools (User-Controlled Upgrades) + +**What it means for upgrades:** + +- **You control the upgrade authority** for your custom pool program +- **Custom development**: You develop your own upgrades and improvements +- **Complete responsibility**: All upgrade planning, development, and execution is your responsibility + +**Your responsibilities:** + +- Develop custom upgrade code +- Ensure CCIP compatibility after upgrades +- Test thoroughly with CCIP Router integration +- Execute upgrade transactions +- Monitor for breaking changes in CCIP protocol updates + +## In-Place Upgrades (Approaches 2 & 3 Only) + + + +When you control the upgrade authority, in-place upgrades provide significant benefits: + +### Benefits of In-Place Upgrades + +1. **Retain Mint Authority (Burn and Mint Pools):** SPL tokens have a single `mint_authority`. When you delegate this authority to a Burn and Mint token pool program, that program holds the exclusive rights to mint tokens. As detailed in the [Mint Authority Management](/ccip/concepts/cross-chain-token/svm/token-pools#mint-authority-management) section, in-place upgrades allow you to: - **Maintain Control:** Upgrade the pool code without reassigning the mint authority, which avoids the complexity of modifying the multisig membership or reconfiguring authorities. - **Reduce Overhead:** Avoid manual reassignments, such as adding a new pool to the multisig and removing the old one, thereby simplifying maintenance and reducing the risk of errors. -1. **Preserve User Workflow (All Pools):** On SVM-based blockchains, instructions require specifying all involved accounts, including the token pool program ID. If you redeploy your pool to a new Program ID, users and integrators must update their transaction code to reference it. In-place upgrades keep the original ID so that existing references and account parameters remain valid. +2. **Preserve User Workflow (All Pools):** On SVM-based blockchains, instructions require specifying all involved accounts, including the token pool program ID. If you redeploy your pool to a new Program ID, users and integrators must update their transaction code to reference it. In-place upgrades keep the original ID so that existing references and account parameters remain valid. -## Recommended Practices +## Best Practices for User-Controlled Upgrades -