{"id":21850507,"url":"https://github.com/circlefin/solana-cctp-contracts","last_synced_at":"2025-04-14T15:02:25.686Z","repository":{"id":228683925,"uuid":"767763967","full_name":"circlefin/solana-cctp-contracts","owner":"circlefin","description":"Official repository for Solana smart contracts used by the Cross-Chain Transfer Protocol","archived":false,"fork":false,"pushed_at":"2025-01-14T18:24:39.000Z","size":25405,"stargazers_count":16,"open_issues_count":5,"forks_count":21,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-28T03:51:09.390Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/circlefin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-03-05T21:23:45.000Z","updated_at":"2025-03-22T04:34:14.000Z","dependencies_parsed_at":"2024-12-06T21:23:03.636Z","dependency_job_id":"6bbff61c-2f12-47f5-8ad6-3d9d31795a42","html_url":"https://github.com/circlefin/solana-cctp-contracts","commit_stats":null,"previous_names":["circlefin/solana-cctp-contracts"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/circlefin%2Fsolana-cctp-contracts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/circlefin%2Fsolana-cctp-contracts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/circlefin%2Fsolana-cctp-contracts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/circlefin%2Fsolana-cctp-contracts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/circlefin","download_url":"https://codeload.github.com/circlefin/solana-cctp-contracts/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248903706,"owners_count":21180828,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-28T00:17:53.782Z","updated_at":"2025-04-14T15:02:20.673Z","avatar_url":"https://github.com/circlefin.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cross-Chain Transfer Protocol (CCTP) on Solana\n\n## Contents\n\n- [Introduction](#introduction)\n- [Deployments](#deployments)\n- [Contract Design](#contract-design)\n- [TokenMessenger Module](#tokenmessenger-module)\n- [MessageTransmitter Module](#messagetransmitter-module)\n- [TokenMinter Module](#tokenminter-module)\n- [Permissions](#permissions)\n- [Deployment guide](#deployment-guide)\n\n## Introduction\n\n[Cross-Chain Transfer Protocol (CCTP)](https://circle.com/cctp) is a permissionless on-chain utility that facilitates USDC transfers securely between blockchains networks via native burning and minting. Circle created it to improve capital efficiency and minimize trust requirements when using USDC across blockchain networks. CCTP enables developers to build multi-chain applications that provide secure, 1:1 transfers of USDC across blockchains for their users.\n\n## Developer Documentation\n\nTo learn more about how to integrate with CCTP, please see our developer documentation [here](https://developers.circle.com/stablecoins/docs/cctp-getting-started).\n\n## Deployments\n\n| Devnet               |                                              |\n| -------------------- | -------------------------------------------- |\n| MessageTransmitter   | CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd |\n| TokenMessengerMinter | CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3 |\n\n| Mainnet              |       |\n| -------------------- | ----- |\n| MessageTransmitter   | CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd |\n| TokenMessengerMinter | CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3 |\n\n### Program Verification\n\nMainnet on-chain progams can be verified with the following steps:\n\n```sh\n# Checkout deployed commit\ngit checkout 4e8f1d7bd4c95c3e1f4cb8ba2118897b7163c7c4\n# Build a verifiable build \nanchor build --verifiable\n# Verify MessageTransmitter\nanchor verify --program-name message_transmitter --provider.cluster mainnet --skip-build CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd\n# Verify TokenMessengerMinter\nanchor verify --program-name token_messenger_minter --provider.cluster mainnet --skip-build CCTPiPYPc6AsJuwueEnWgSgucamXDZwBd53dQ11YiKX3\n```\n\n## Contract Design\n\nSolana offers a different smart contract model to traditional EVM-based blockchains. In traditional EVM-based chains, contract code/logic and state are combined into a single contract deployed on-chain. With Solana, a smart contract is read-only or stateless and contains just program logic. This creates a logical separation of state (accounts) and contract logic (programs). This model allows for a single generic Solana program to operate across various accounts without requiring additional deployments. This is the crucial difference between Solana and EVM-based smart contracts.\n\nCCTP protocol on EVM chains consists of three contracts:\n\n- **MessageTransmitter**: Generic message passing. Sends all messages on the source chain, and receives all messages on the destination chain.\n- **TokenMessenger**: Entrypoint for cross-chain token transfer. Routes messages to burn a token on source chain, and mint it on destination chain.\n- **TokenMinter**: Responsible for minting and burning tokens. Contains chain-specific settings used by minters and burners.\n\nOn Solana, the CCTP protocol implementation is split into two programs: MessageTransmitter and TokenMessengerMinter. Where TokenMessengerMinter encapsulates the functionality of both TokenMessenger and TokenMinter contracts. To ensure alignment with EVM contracts' logic and state and to facilitate future upgrades and maintenance, the code and state of Solana programs reflect the EVM counterparts as closely as possible.\n\nSolana CCTP programs are written in Rust and leverage the Anchor framework that makes it easier and more efficient for developers to create, deploy, and manage smart contracts on the Solana blockchain. Along with the program, an IDL (Interface Description Language) can be generated and deployed on-chain making it much easier for developers to interact with the CCTP program. See [Deployment guide](#deployment-guide) for more details.\n\nEach CCTP program instruction emits one or more events upon execution. Depending on the purpose of instruction, events are emitted via Anchor's CPI events functionality or by creating new stand-alone accounts where such events are stored. Stand-alone account addresses are randomly generated on a client and passed to the program. The program initializes the account, writes the event, and sets itself as the owner. Replace instructions don't update previously created event accounts but create new ones. This is done to make it easier for the client to generate a replace instruction because it doesn't need to look up the original account address. At this time, only `MessageSent` events are emitted via stand-alone accounts.\n\nBackend services can observe new account-based events by introspecting instructions and extracting event account addresses. Once the event has been processed, the account could be deleted and rent SOL reclaimed with `reclaimEventAccount` instruction. Rent SOL can only be returned to the original rent payer.\n\n## MessageTransmitter Module\n\n### **Instructions**\n\n---\n\n`initialize`\n\nInitialize MessageTransmitter. This operation needs to be performed prior to using any other instructions. During the initialization, authorities are set to the upgrade authority.\n\n| Parameter          |   Type   | Description                            |\n| ------------------ | :------: | -------------------------------------- |\n| localDomain        |   u32    | Solana domain id                       |\n| attester           | [u8; 20] | Attester to enable                     |\n| maxMessageBodySize |   u64    | Maximum size of message body, in bytes |\n| version            |   u32    | Message Format version                 |\n\n`transferOwnership`\n\nChange the authority of MessageTransmitter.\n\n| Parameter |  Type  | Description   |\n| --------- | :----: | ------------- |\n| newOwner  | Pubkey | New authority |\n\n`acceptOwnership`\n\nServes as a safety net after the authority has been changed. If an address has been inputted incorrectly, the former authority can rectify this by invoking the `transferOwnership` instruction once more.\n\n| Parameter | Type | Description |\n| --------- | :--: | ----------- |\n| N/A       |      |             |\n\n`updatePauser`\n\nChange the pauser of MessageTransmitter.\n\n| Parameter |  Type  | Description |\n| --------- | :----: | ----------- |\n| newPauser | Pubkey | New pauser  |\n\n`updateAttesterManager`\n\nChange the AttesterManager of MessageTransmitter.\n\n| Parameter          |  Type  | Description   |\n| ------------------ | :----: | ------------- |\n| newAttesterManager | Pubkey | New authority |\n\n---\n\n`receiveMessage`\n\nReceive a message. Messages with a given nonce can only be broadcast successfully once for a pair of domains. The message body of a valid message is passed to the specified recipient for further processing.\n\n| Parameter   |   Type   | Description                   |\n| ----------- | :------: | ----------------------------- |\n| message     | Vec\\\u003cu8\u003e | Message bytes                 |\n| attestation | Vec\\\u003cu8\u003e | Signed attestation of message |\n\n`sendMessage`\n\nSend a message to the destination domain and recipient. Emits a MessageSent event which will be attested by Circle’s attestation service.\n\n| Parameter         |   Type   | Description                                             |\n| ----------------- | :------: | ------------------------------------------------------- |\n| destinationDomain |   u32    | Destination domain identifier                           |\n| recipient         |  Pubkey  | Address to handle message body on destination domain    |\n| messageBody       | Vec\\\u003cu8\u003e | Application-specific message to be handled by recipient |\n\n`sendMessageWithCaller`\n\nSend a message to the destination domain and recipient, for a specified destinationCaller on the destination domain. Emits a MessageSent event which will be attested by Circle’s attestation service.\n\n| Parameter         |   Type   | Description                                             |\n| ----------------- | :------: | ------------------------------------------------------- |\n| destinationDomain |   u32    | Destination domain identifier                           |\n| recipient         |  Pubkey  | Address to handle message body on destination domain    |\n| messageBody       | Vec\\\u003cu8\u003e | Application-specific message to be handled by recipient |\n| destinationCaller |  Pubkey  | Caller on the destination domain                        |\n\n`replaceMessage`\n\nReplace a message with a new message body and/or destination caller.\n\n| Parameter            |   Type   | Description                                                                          |\n| -------------------- | :------: | ------------------------------------------------------------------------------------ |\n| originalMessage      | Vec\\\u003cu8\u003e | Original message to replace                                                          |\n| originalAttestation  | Vec\\\u003cu8\u003e | Attestation of originalMessage                                                       |\n| newMessageBody       | Vec\\\u003cu8\u003e | New message body of replaced message                                                 |\n| newDestinationCaller |  Pubkey  | The new destination caller, which may be the same as the original destination caller |\n\n`setSignatureThreshold`\n\nSet the threshold of signatures required to attest to a message.\n\n| Parameter             | Type | Description             |\n| --------------------- | :--: | ----------------------- |\n| newSignatureThreshold | u32  | New signature threshold |\n\n`enableAttester`\n\nEnable an attester.\n\n| Parameter   |   Type   | Description        |\n| ----------- | :------: | ------------------ |\n| newAttester | [u8; 20] | Attester to enable |\n\n`disableAttester`\n\nDisable an attester.\n\n| Parameter |   Type   | Description         |\n| --------- | :------: | ------------------- |\n| attester  | [u8; 20] | Attester to disable |\n\n`setMaxMessageBodySize`\n\nSet the max message body size.\n\n| Parameter             | Type | Description             |\n| --------------------- | :--: | ----------------------- |\n| newMaxMessageBodySize | u64  | New signature threshold |\n\n`pause`\n\nPause MessageTransmitter.\n\n| Parameter | Type | Description |\n| --------- | :--: | ----------- |\n| None      |      |             |\n\n`unpause`\n\nResume MessageTransmitter.\n\n| Parameter | Type | Description |\n| --------- | :--: | ----------- |\n| None      |      |             |\n\n`reclaimEventAccount`\n\nDeletes the event account and reclaims rent SOL to the original rent payer. This instruction requires a valid attestation to be executed.\n\n| Parameter   |   Type   | Description                |\n| ----------- | :------: | -------------------------- |\n| attestation | Vec\\\u003cu8\u003e | Attestation of the message |\n\n`getNoncePDA`\n\nView-only helper instruction to look-up `usedNonces` account for `receiveMessage` and `isNonceUsed` instructions.\n\n| Parameter    | Type | Description       |\n| ------------ | :--: | ----------------- |\n| nonce        | u64  | Message nonce     |\n| sourceDomain | u32  | Domain identifier |\n\n`isNonceUsed`\n\nView-only helper instruction that returns true if the nonce is already used, i.e. the message is received on the destination chain.\n\n| Parameter | Type | Description   |\n| --------- | :--: | ------------- |\n| nonce     | u64  | Message nonce |\n\n### **State**\n\n---\n\n`MessageTransmitter`\n\nStores MessageTransmitter configuration and next available nonce.\n\n| Field              |     Type     | Description                                             |\n| ------------------ | :----------: | ------------------------------------------------------- |\n| owner              |    Pubkey    | Main authority of the program                           |\n| pendingOwner       |    Pubkey    | New authority that needs to be accepted                 |\n| attesterManager    |    Pubkey    | Attester Manager of the program                         |\n| pauser             |    Pubkey    | Pause / unpause authority                               |\n| paused             |     bool     | Specifies whether MessageTransmitter is paused          |\n| localDomain        |     u32      | Solana domain id                                        |\n| version            |     u32      | Message Format version                                  |\n| signatureThreshold |     u32      | Threshold of signatures required to attest to a message |\n| enabledAttesters   | Vec\\\u003cPubkey\u003e | Enabled attesters (message signers)                     |\n| maxMessageBodySize |     u64      | Maximum size of message body, in bytes                  |\n| nextAvailableNonce |     u64      | Next available nonce from this source domain            |\n\n`UsedNonces`\n\nOn-chain account that stores used nonces.\n\n| Field        |    Type     | Description                           |\n| ------------ | :---------: | ------------------------------------- |\n| remoteDomain |     u32     | Remote domain id                      |\n| firstNonce   |     u64     | First nonce in the usedNonces array   |\n| usedNonces   | [bool; 500] | Flags indicating if the nonce is used |\n\n### **Events**\n\n---\n\n`OwnershipTransferStarted`\n\n| Field         |  Type  | Description    |\n| ------------- | :----: | -------------- |\n| previousOwner | Pubkey | Previous owner |\n| newOwner      | Pubkey | New owner      |\n\n`OwnershipTransferred`\n\n| Field         |  Type  | Description    |\n| ------------- | :----: | -------------- |\n| previousOwner | Pubkey | Previous owner |\n| newOwner      | Pubkey | New owner      |\n\n`PauserChanged`\n\n| Field      |  Type  | Description |\n| ---------- | :----: | ----------- |\n| newAddress | Pubkey | New pauser  |\n\n`AttesterManagerUpdated`\n\n| Field                   |  Type  | Description              |\n| ----------------------- | :----: | ------------------------ |\n| previousAttesterManager | Pubkey | Previous AttesterManager |\n| newAttesterManager      | Pubkey | New AttesterManager      |\n\n`MessageSent`\n\nEmitted when a new message is dispatched.\n\n| Field      |   Type   | Description          |\n| ---------- | :------: | -------------------- |\n| rent_payer |  Pubkey  | Account rent payer   |\n| message    | Vec\\\u003cu8\u003e | Raw bytes of message |\n\n`MessageReceived`\n\nEmitted when a new message is received.\n\n| Field        |   Type   | Description                                                 |\n| ------------ | :------: | ----------------------------------------------------------- |\n| caller       |  Pubkey  | Authorized caller of receiveMessage() on destination domain |\n| sourceDomain |   u32    | The source domain this message originated from              |\n| nonce        |   u64    | Unique message nonce                                        |\n| sender       |  Pubkey  | The sender of this message                                  |\n| messageBody  | Vec\\\u003cu8\u003e | Raw bytes of message                                        |\n\n`SignatureThresholdUpdated`\n\nEmitted when threshold number of attestations (m in m/n multisig) is updated.\n\n| Field                 | Type | Description             |\n| --------------------- | :--: | ----------------------- |\n| oldSignatureThreshold | u32  | Old signature threshold |\n| newSignatureThreshold | u32  | New signature threshold |\n\n`AttesterEnabled`\n\nEmitted when an attester is enabled.\n\n| Field    |   Type   | Description            |\n| -------- | :------: | ---------------------- |\n| attester | [u8; 20] | Newly enabled attester |\n\n`AttesterDisabled`\n\nEmitted when an attester is disabled.\n\n| Field    |   Type   | Description             |\n| -------- | :------: | ----------------------- |\n| attester | [u8; 20] | Newly disabled attester |\n\n`MaxMessageBodySizeUpdated`\n\nEmitted when max message body size is updated.\n\n| Field                 | Type | Description                             |\n| --------------------- | :--: | --------------------------------------- |\n| newMaxMessageBodySize | u64  | New maximum message body size, in bytes |\n\n`Pause`\n\nEmitted when MessageTransmitter is paused.\n\n| Field | Type | Description |\n| ----- | :--: | ----------- |\n| None  |      |             |\n\n`Unpause`\n\nEmitted when MessageTransmitter is resumed.\n\n| Field | Type | Description |\n| ----- | :--: | ----------- |\n| None  |      |             |\n\n## TokenMessenger Module\n\n### **Instructions**\n\n---\n\n`initialize`\n\nInitialize TokenMessenger. This operation needs to be performed prior to using any other instructions. During the initialization, authorities are set to the upgrade authority.\n\n| Parameter          |  Type  | Description                    |\n| ------------------ | :----: | ------------------------------ |\n| tokenController    | Pubkey | Token controller address       |\n| messageTransmitter | Pubkey | Local Message Transmitter      |\n| messageBodyVersion |  u32   | Version of message body format |\n\n`transferOwnership`\n\nChange the authority of TokenMessenger.\n\n| Parameter |  Type  | Description   |\n| --------- | :----: | ------------- |\n| newOwner  | Pubkey | New authority |\n\n`acceptOwnership`\n\nServes as a safety net after the authority has been changed. If an address has been inputted incorrectly, the former authority can rectify this by invoking the `transferOwnership` instruction once more.\n\n| Parameter | Type | Description |\n| --------- | :--: | ----------- |\n| N/A       |      |             |\n\n`depositForBurn`\n\nDeposit and burn tokens from sender to be minted on destination domain. Minted tokens will be transferred to mintRecipient.\n\n| Parameter         |  Type  | Description                                     |\n| ----------------- | :----: | ----------------------------------------------- |\n| amount            |  u64   | Amount of tokens to deposit and burn            |\n| destinationDomain |  u32   | Destination domain identifier                   |\n| mintRecipient     | Pubkey | Address of mint recipient on destination domain |\n\n`depositForBurnWithCaller`\n\nDeposit and burn tokens from sender to be minted on destination domain. Minted tokens will be transferred to mintRecipient.\n\n| Parameter         |  Type  | Description                                     |\n| ----------------- | :----: | ----------------------------------------------- |\n| amount            |  u64   | Amount of tokens to deposit and burn            |\n| destinationDomain |  u32   | Destination domain identifier                   |\n| mintRecipient     | Pubkey | Address of mint recipient on destination domain |\n| destinationCaller | Pubkey | Caller on the destination domain                |\n\n`replaceDepositForBurn`\n\nReplace a BurnMessage to change the mint recipient and/or destination caller. Allows the sender of a previous BurnMessage (created by depositForBurn) to send a new BurnMessage to replace the original. The new BurnMessage will reuse the amount and burn token of the original, without requiring a new deposit.\n\nThis is useful in cases where the user specified an incorrect address and has no way to safely mint the previously burned tokens.\n\n| Parameter            |   Type   | Description                                     |\n| -------------------- | :------: | ----------------------------------------------- |\n| originalMessage      | Vec\\\u003cu8\u003e | Original message to replace                     |\n| originalAttestation  | Vec\\\u003cu8\u003e | Attestation of originalMessage                  |\n| newMintRecipient     |  Pubkey  | Address of mint recipient on destination domain |\n| newDestinationCaller |  Pubkey  | Caller on the destination domain                |\n\n`handleReceiveMessage`\n\nHandle an incoming message received by the local MessageTransmitter, and take the appropriate action. For a burn message, mint the associated token to the requested recipient on the local domain.\n\n| Parameter    |   Type   | Description                                       |\n| ------------ | :------: | ------------------------------------------------- |\n| remoteDomain |   u32    | The domain where the message originated from      |\n| sender       |  Pubkey  | The sender of the message (remote TokenMessenger) |\n| messageBody  | Vec\\\u003cu8\u003e | The message body bytes                            |\n\n`addRemoteTokenMessenger`\n\nAdd the TokenMessenger for a remote domain.\n\n| Parameter      |  Type  | Description                      |\n| -------------- | :----: | -------------------------------- |\n| domain         |  u32   | Domain of remote TokenMessenger  |\n| tokenMessenger | Pubkey | Address of remote TokenMessenger |\n\n`removeRemoteTokenMessenger`\n\nRemove the TokenMessenger for a remote domain.\n\n| Parameter | Type | Description |\n| --------- | :--: | ----------- |\n| N/A       |      |             |\n\n### **State**\n\n---\n\n`TokenMessenger`\n\nStores TokenMessenger configuration.\n\n| Field                   |  Type  | Description                                                                                     |\n| ----------------------- | :----: | ----------------------------------------------------------------------------------------------- |\n| owner                   | Pubkey | Main authority of the program                                                                   |\n| pendingOwner            | Pubkey | New authority that needs to be accepted                                                         |\n| localMessageTransmitter | Pubkey | Local Message Transmitter responsible for sending and receiving messages to/from remote domains |\n| messageBodyVersion      |  u32   | Version of message body format                                                                  |\n\n`RemoteTokenMessenger`\n\nStores information about TokenMessenger on remote domain.\n\n| Field          |  Type  | Description                           |\n| -------------- | :----: | ------------------------------------- |\n| domain         |  u32   | Domain of remote TokenMessenger       |\n| tokenMessenger | Pubkey | Valid TokenMessenger on remote domain |\n\n### **Events**\n\n---\n\n`OwnershipTransferStarted`\n\n| Field         |  Type  | Description    |\n| ------------- | :----: | -------------- |\n| previousOwner | Pubkey | Previous owner |\n| newOwner      | Pubkey | New owner      |\n\n`OwnershipTransferred`\n\n| Field         |  Type  | Description    |\n| ------------- | :----: | -------------- |\n| previousOwner | Pubkey | Previous owner |\n| newOwner      | Pubkey | New owner      |\n\n`DepositForBurn`\n\nEmitted when a DepositForBurn message is sent.\n\n| Field                     |  Type  | Description                                                 |\n| ------------------------- | :----: | ----------------------------------------------------------- |\n| nonce                     |  u64   | Unique nonce reserved by message                            |\n| burnToken                 | Pubkey | Mint address of token burnt on Solana                       |\n| amount                    |  u64   | Deposit amount                                              |\n| depositor                 | Pubkey | Address where deposit is transferred from                   |\n| mintRecipient             | Pubkey | Address receiving minted tokens on destination domain       |\n| destinationDomain         |  u32   | Destination domain                                          |\n| destinationTokenMessenger | Pubkey | Address of TokenMessenger on destination domain             |\n| destinationCaller         | Pubkey | Authorized caller of receiveMessage() on destination domain |\n\n`MintAndWithdraw`\n\nEmitted when tokens are minted.\n\n| Field         |  Type  | Description                        |\n| ------------- | :----: | ---------------------------------- |\n| mintRecipient | Pubkey | Recipient address of minted tokens |\n| amount        |  u64   | Amount of minted tokens            |\n| mintToken     | Pubkey | Mint address of minted token       |\n\n`RemoteTokenMessengerAdded`\n\nEmitted when a remote TokenMessenger is added.\n\n| Field          |  Type  | Description                      |\n| -------------- | :----: | -------------------------------- |\n| domain         |  u32   | Domain of remote TokenMessenger  |\n| tokenMessenger | Pubkey | Address of remote TokenMessenger |\n\n`RemoteTokenMessengerRemoved`\n\nEmitted when a remote TokenMessenger is removed.\n\n| Field          |  Type  | Description                      |\n| -------------- | :----: | -------------------------------- |\n| domain         |  u32   | Domain of remote TokenMessenger  |\n| tokenMessenger | Pubkey | Address of remote TokenMessenger |\n\n## TokenMinter Module\n\n### **Instructions**\n\n---\n\n`setTokenController`\n\nChange the token controller address.\n\n| Parameter          |  Type  | Description          |\n| ------------------ | :----: | -------------------- |\n| newTokenController | Pubkey | New token controller |\n\n`updatePauser`\n\nChange the pauser address.\n\n| Parameter |  Type  | Description |\n| --------- | :----: | ----------- |\n| newPauser | Pubkey | New pauser  |\n\n`setMaxBurnAmountPerMessage`\n\nSet the maximum burn amount per message.\n\n| Parameter           | Type | Description                     |\n| ------------------- | ---- | ------------------------------- |\n| burnLimitPerMessage | u64  | Maximum burn amount per message |\n\n`addLocalToken`\n\nAdd a new local token.\n\n| Parameter | Type | Description |\n| --------- | :--: | ----------- |\n| N/A       |      |             |\n\n`removeLocalToken`\n\nRemove local token.\n\n| Parameter | Type | Description |\n| --------- | :--: | ----------- |\n| N/A       |      |             |\n\n`linkTokenPair`\n\nLink supported pair of local and remote tokens.\n\n| Parameter    |  Type  | Description          |\n| ------------ | :----: | -------------------- |\n| remoteDomain |  u32   | Remote domain        |\n| remoteToken  | Pubkey | Remote token address |\n| localToken   | Pubkey | Local token address  |\n\n`unlinkTokenPair`\n\nUnlink a pair of local and remote tokens.\n\n| Parameter | Type | Description |\n| --------- | :--: | ----------- |\n| N/A       |      |             |\n\n`pause`\n\nPause TokenMinter.\n\n| Parameter | Type | Description |\n| --------- | :--: | ----------- |\n| None      |      |             |\n\n`unpause`\n\nResume TokenMinter.\n\n| Parameter | Type | Description |\n| --------- | :--: | ----------- |\n| None      |      |             |\n\n`burnTokenCustody`\n\nBurn tokens in the custody. If the specified amount is greater than the current balance, then the entire balance is burned, i.e., no error is returned in such case.\n\n| Parameter | Type | Description              |\n| --------- | :--: | ------------------------ |\n| amount    | u64  | Amount of tokens to burn |\n\n### **State**\n\n---\n\n`TokenMinter`\n\nStores TokenMinter configuration and records stats.\n\n| Field           |  Type  | Description                                                             |\n| --------------- | :----: | ----------------------------------------------------------------------- |\n| tokenController | Pubkey | Authority to manage token address mappings, and per-message burn limits |\n| pauser          | Pubkey | Pause / unpause authority                                               |\n| paused          |  bool  | Specifies whether the TokenMinter is paused                             |\n\n`TokenPair`\n\nSupported mintable tokens on remote domains, mapped to their corresponding local token.\n\n| Field        |  Type  | Description              |\n| ------------ | :----: | ------------------------ |\n| remoteDomain |  u32   | Remote domain            |\n| remoteToken  | Pubkey | Remote token address     |\n| localToken   | Pubkey | Local token mint address |\n\n`LocalToken`\n\nSupported tokens on the local domain.\n\n| Field               |  Type  | Description                        |\n| ------------------- | :----: | ---------------------------------- |\n| custody             | Pubkey | Custody token account              |\n| mint                | Pubkey | Token mint address                 |\n| burnLimitPerMessage |  u64   | Maximum burn amount per message    |\n| messagesSent        |  u64   | Total number of messages sent      |\n| messagesReceived    |  u64   | Total number of messages received  |\n| amountSent          |  u64   | Amount of tokens sent (burned)     |\n| amountReceived      |  u64   | Amount of tokens received (minted) |\n\n### **Events**\n\n---\n\n`SetTokenController`\n\n| Field           |  Type  | Description          |\n| --------------- | :----: | -------------------- |\n| tokenController | Pubkey | New token controller |\n\n`PauserChanged`\n\n| Field      |  Type  | Description |\n| ---------- | :----: | ----------- |\n| newAddress | Pubkey | New pauser  |\n\n`Mint`\n\nEmitted when a mint request is processed.\n\n| Field  | Type | Description   |\n| ------ | :--: | ------------- |\n| amount | u64  | Minted amount |\n\n`Burn`\n\nEmitted when a burn request is processed.\n\n| Field  | Type | Description   |\n| ------ | :--: | ------------- |\n| amount | u64  | Burned amount |\n\n`SetBurnLimitPerMessage`\n\nEmitted when a burn limit per message is set.\n\n| Field               |  Type  | Description                |\n| ------------------- | :----: | -------------------------- |\n| token               | Pubkey | Token mint address         |\n| burnLimitPerMessage |  u64   | New burn limit per message |\n\n`LocalTokenAdded`\n\nEmitted when a new local token is added.\n\n| Field   |  Type  | Description           |\n| ------- | :----: | --------------------- |\n| custody | Pubkey | Custody token account |\n| mint    | Pubkey | Token mint address    |\n\n`LocalTokenRemoved`\n\nEmitted when a local token is removed.\n\n| Field   |  Type  | Description           |\n| ------- | :----: | --------------------- |\n| custody | Pubkey | Custody token account |\n| mint    | Pubkey | Token mint address    |\n\n`TokenPairLinked`\n\nEmitted when a token pair is linked.\n\n| Field        |  Type  | Description              |\n| ------------ | :----: | ------------------------ |\n| localToken   | Pubkey | Local token mint address |\n| remoteDomain |  u32   | Remote domain            |\n| remoteToken  | Pubkey | Remote token address     |\n\n`TokenPairUnlinked`\n\nEmitted when a token pair is linked.\n\n| Field        |  Type  | Description              |\n| ------------ | :----: | ------------------------ |\n| localToken   | Pubkey | Local token mint address |\n| remoteDomain |  u32   | Remote domain            |\n| remoteToken  | Pubkey | Remote token address     |\n\n`Pause`\n\nEmitted when TokenMinter is paused.\n\n| Field | Type | Description |\n| ----- | :--: | ----------- |\n| None  |      |             |\n\n`Unpause`\n\nEmitted when TokenMinter is resumed.\n\n| Field | Type | Description |\n| ----- | :--: | ----------- |\n| None  |      |             |\n\n## Permissions\n\nThe following table shows the permissions for calling each instruction:\n\n| module             | instruction                | permissionless | pauser | attester manager | token controller | owner | upgrade authority | program (e.g. TokenMessenger) | MessageTransmitter |\n| ------------------ | -------------------------- | :------------: | :----: | :--------------: | :--------------: | :---: | :---------------: | :---------------------------: | :----------------: |\n| MessageTransmitter | initialize                 |                |        |                  |                  |       |         x         |                               |                    |\n| MessageTransmitter | transferOwnership          |                |        |                  |                  |   x   |                   |                               |                    |\n| MessageTransmitter | acceptOwnership            |                |        |                  |                  |   x   |                   |                               |                    |\n| MessageTransmitter | updatePauser               |                |        |                  |                  |   x   |                   |                               |                    |\n| MessageTransmitter | updateAttesterManager      |                |        |                  |                  |   x   |                   |                               |                    |\n| MessageTransmitter | receiveMessage             |       x        |        |                  |                  |       |                   |                               |                    |\n| MessageTransmitter | sendMessage                |                |        |                  |                  |       |                   |               x               |                    |\n| MessageTransmitter | sendMessageWithCaller      |                |        |                  |                  |       |                   |               x               |                    |\n| MessageTransmitter | replaceMessage             |                |        |                  |                  |       |                   |               x               |                    |\n| MessageTransmitter | setSignatureThreshold      |                |        |        x         |                  |       |                   |                               |                    |\n| MessageTransmitter | enableAttester             |                |        |        x         |                  |       |                   |                               |                    |\n| MessageTransmitter | disableAttester            |                |        |        x         |                  |       |                   |                               |                    |\n| MessageTransmitter | setMaxMessageBodySize      |                |        |                  |                  |   x   |                   |                               |                    |\n| MessageTransmitter | pause                      |                |   x    |                  |                  |       |                   |                               |                    |\n| MessageTransmitter | unpause                    |                |   x    |                  |                  |       |                   |                               |                    |\n| TokenMessenger     | initialize                 |                |        |                  |                  |       |         x         |                               |                    |\n| TokenMessenger     | transferOwnership          |                |        |                  |                  |   x   |                   |                               |                    |\n| TokenMessenger     | acceptOwnership            |                |        |                  |                  |   x   |                   |                               |                    |\n| TokenMessenger     | depositForBurn             |       x        |        |                  |                  |       |                   |                               |                    |\n| TokenMessenger     | depositForBurnWithCaller   |       x        |        |                  |                  |       |                   |                               |                    |\n| TokenMessenger     | replaceDepositForBurn      |       x        |        |                  |                  |       |                   |                               |                    |\n| TokenMessenger     | handleReceiveMessage       |                |        |                  |                  |       |                   |                               |         x          |\n| TokenMessenger     | addRemoteTokenMessenger    |                |        |                  |                  |   x   |                   |                               |                    |\n| TokenMessenger     | removeRemoteTokenMessenger |                |        |                  |                  |   x   |                   |                               |                    |\n| TokenMinter        | setTokenController         |                |        |                  |                  |   x   |                   |                               |                    |\n| TokenMinter        | updatePauser               |                |        |                  |                  |   x   |                   |                               |                    |\n| TokenMinter        | setMaxBurnAmountPerMessage |                |        |                  |        x         |       |                   |                               |                    |\n| TokenMinter        | addLocalToken              |                |        |                  |        x         |       |                   |                               |                    |\n| TokenMinter        | removeLocalToken           |                |        |                  |        x         |       |                   |                               |                    |\n| TokenMinter        | linkTokenPair              |                |        |                  |        x         |       |                   |                               |                    |\n| TokenMinter        | unlinkTokenPair            |                |        |                  |        x         |       |                   |                               |                    |\n| TokenMinter        | pause                      |                |   x    |                  |                  |       |                   |                               |                    |\n| TokenMinter        | unpause                    |                |   x    |                  |                  |       |                   |                               |                    |\n\n## Deployment guide\n\n### Setup Environment\n\n1. Clone the repository from \u003chttps://github.com/circlefin/solana-cctp-contracts\u003e.\n2. Install the latest Solana tools from \u003chttps://docs.solana.com/cli/install-solana-cli-tools\u003e. If you already have Solana tools, run `solana-install update` to get the latest compatible version.\n3. Install the latest Rust stable from \u003chttps://rustup.rs/\u003e. If you already have Rust, run `rustup update` to get the latest version.\n4. Install the latest Anchor framework from \u003chttps://www.anchor-lang.com/docs/installation\u003e. If you already have Anchor, run `avm update` to get the latest version.\n\nRustfmt is used to format the code. It requires `nightly` features to be activated:\n\n5. Install `nightly` rust toolchain. \u003chttps://rust-lang.github.io/rustup/installation/index.html#installing-nightly\u003e\n6. Execute `git config core.hooksPath .githooks` to activate pre-commit hooks.\n\n#### [Optional] Vscode setup\n\n1. Install `rust-analyzer` extension\n2. If formatting doesn't work, make sure that `rust-analyzer.rustfmt.extraArgs` is set to `+nightly`\n\n### Build\n\nFirst, generate new keys for the program addresses with `solana-keygen new -o \u003cPROG_ID_JSON\u003e`. Then, replace the existing program IDs with the newly generated addresses in `Anchor.toml`, `programs/message-transmitter/src/lib.rs`, and `programs/token-messenger-minter/src/lib.rs`.\n\nAlso, ensure the path to your wallet in `Anchor.toml` is correct. Alternatively, when running Anchor deploy or test commands, you can specify your wallet with `--provider.wallet` argument. The wallet's pubkey will be set as an upgrade authority upon initial deployment of the program. It is strongly recommended to use multisig upgrade authority when deploying to the mainnet.\n\nTo build the program run `anchor build` command from the root `solana-cctp-contracts` directory:\n\n```sh\ncd solana-cctp-contracts\nanchor build\n```\n\n#### Cargo Dependencies\n\nTo ensure with certainty that packages are not changed unexpectedly as well as to enable reproducible,\nverifiable builds, all Cargo dependencies are vendored locally in the [vendor](/vendor/) directory and\nenabled via the [.cargo/config.toml](.cargo/config.toml) file.\n\n### Test\n\nUnit tests are executed with the `cargo test` command:\n\n```sh\ncargo test -- --nocapture\n```\n\nIntegration tests can be started as follows:\n\n```sh\nnpm install\nanchor test -- --features test\n```\n\nBy default, integration tests are executed on a local validator, so it won't cost you any SOL.\n\n### Deploy\n\nTo deploy the program to the devnet and upload the IDL use the following commands:\n\n```sh\nanchor deploy --provider.cluster devnet --program-name message_transmitter --program-keypair \u003cPROG_ID_JSON\u003e\nanchor deploy --provider.cluster devnet --program-name token_messenger_minter --program-keypair \u003cPROG_ID_JSON\u003e\nanchor idl init --provider.cluster devnet --filepath ./target/idl/message_transmitter.json \u003cPROGRAM ID\u003e\nanchor idl init --provider.cluster devnet --filepath ./target/idl/token_messenger_minter.json \u003cPROGRAM ID\u003e\n```\n\n### Initialize\n\nBefore the first use of the CCTP programs they must be initialized with the [MessageTransmitter#initialize](#messagetransmitter-module) and [TokenMessenger#initialize](#tokenmessenger-module) instructions.\n\n---\n\nLicense: [LICENSE](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcirclefin%2Fsolana-cctp-contracts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcirclefin%2Fsolana-cctp-contracts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcirclefin%2Fsolana-cctp-contracts/lists"}