diff --git a/README.md b/README.md index 8e411d90..545a965a 100644 --- a/README.md +++ b/README.md @@ -40,10 +40,10 @@ SOLANA_RPC_URL=https://your-solana-devnet-rpc-url ### Requirements -- [NodeJS 12](https://nodejs.org/en/download/) or higher +- [Node.js v20+](https://nodejs.org/en/download/) (v23.11.0 recommended) - [Rust](https://www.rust-lang.org/tools/install) - we recommend rustc version 1.87 and above - [Solana CLI](https://docs.solanalabs.com/cli/install) - we recommend v0.31.1 -- [Anchor](https://book.anchor-lang.com/getting_started/installation.html) - re recommend v2.1.21 and above. +- [Anchor](https://book.anchor-lang.com/getting_started/installation.html) - we recommend v2.1.21 and above. - A C compiler such as the one included in [GCC](https://gcc.gnu.org/install/). ### Building and Deploying the Consumer Program @@ -92,7 +92,7 @@ Next, build the program: anchor build ``` -The build process generates a keypair for your CCIP Receiver Solana program (not to be confused with your wallet keypair we generated earlier). Before you deploy the `ccip_basic_receiver` Solana program, you must update it's public key in this line in the `./programs/ccip-basic-receiver/src/lib.rs` file: +Before you deploy the `chainlink_solana_demo` program, you must update its public key in `./programs/chainlink_solana_demo/src/lib.rs`: ``` declare_id!("####GEg__SOME__KEY__HERE__F2TsL#####"); @@ -108,7 +108,7 @@ anchor keys sync ``` -After this command, check the file `./programs/ccip-basic-receiver/src/lib.rs` again. The line will be updated and show a new program account, for eg: +After this command, check `./programs/chainlink_solana_demo/src/lib.rs` again. The `declare_id!` line will be updated with your program address, for example: ``` declare_id!("JC16qi56dgcLoaTVe4BvnCoDL6FhH5NtahA7jmWZFdqm"); @@ -126,9 +126,9 @@ anchor build anchor deploy --provider.cluster devnet ``` -Once you have successfully deployed the program, the terminal output will specify the program ID of the program. Make sure you're looking for the Program ID of the `ccip-basic-receiver` program (and not any other program that also got deployed). +Once you have successfully deployed the program, the terminal output will specify the program ID. Make sure you're looking for the Program ID of the `chainlink_solana_demo` program. -The Program ID for your `ccip-basic-receiver` program must match the value you inserted into the `./programs/ccip-basic-receiver/src/lib.rs` file. +The Program ID must match the value in `./programs/chainlink_solana_demo/src/lib.rs`. 🚨 The `declare_id!` and your deployed program ID should be the same. If they're different, it could indicate: @@ -277,21 +277,25 @@ You will be asked to provide anchor environment variables. See `.env.example` fo ## Cross-Chain Interoperability Protocol (CCIP) -This repository also includes comprehensive scripts and libraries for **Chainlink CCIP**, enabling cross-chain communication between Solana and EVM-compatible blockchains. +This repository also includes scripts and libraries for **Chainlink CCIP**, enabling cross-chain communication between Solana and EVM-compatible blockchains. ### CCIP Features - **Token Transfers**: Send tokens from EVM chains to Solana and vice versa -- **Arbitrary Messaging**: Send custom data between chains +- **Arbitrary Messaging**: Send custom data between chains - **Multi-Chain Support**: Works with Ethereum, Base, Optimism, BSC, Arbitrum, and more -- **Token Pool Management**: Configure burn-mint token pools for cross-chain transfers -- **Admin Registry**: Manage token administration across multiple chains +- **CCIP Receivers**: Deploy and manage programs that receive cross-chain messages + +> **Cross-chain token (CCT) pool setup** (burn-mint pools, admin registry, ALT management) lives in [ccip-solana-bs58-generator](https://github.com/smartcontractkit/ccip-solana-bs58-generator), not this repo. ### Quick Start with CCIP #### Send Tokens from Ethereum to Solana ```bash +# Estimate fees (read-only, no private key required) +yarn evm:check-fee + # Get test tokens yarn evm:token:drip @@ -302,9 +306,6 @@ yarn evm:transfer --token 0x779877A7B0D9E8603169DdbD7836e478b4624789 --amount 10 #### Send Tokens from Solana to Ethereum ```bash -# Create and configure a token -yarn svm:token:create --name "MyToken" --symbol "MTK" - # Delegate authority for CCIP transfers yarn svm:token:delegate diff --git a/ccip-lib/svm/README.md b/ccip-lib/svm/README.md index fa1a1eab..339cec18 100644 --- a/ccip-lib/svm/README.md +++ b/ccip-lib/svm/README.md @@ -2,6 +2,8 @@ A TypeScript SDK for interacting with the Chainlink CCIP protocol on Solana. +> **Note:** Token pool setup, admin registry, and ALT management for cross-chain tokens (CCT) were removed from this repo. Use [ccip-solana-bs58-generator](https://github.com/smartcontractkit/ccip-solana-bs58-generator) for those workflows. This SDK still supports CCIP messaging, fee calculation, token transfers, and receiver operations. + ## Installation This SDK is part of the CCIP library and is not published as a standalone npm package. To use it: @@ -24,7 +26,7 @@ import { CCIPClient } from "../path/to/ccip-lib/svm"; - Anchor-generated bindings for all CCIP accounts and instructions - Flexible configuration management with dependency injection - Structured logging throughout the SDK -- Token pool management (burn-mint pools) for cross-chain token transfers +- Router client for cross-chain messaging and token transfers ## Architecture @@ -32,15 +34,10 @@ The SDK follows a modular architecture with clear separation of concerns: ### Core Components -- **CCIPClient**: Main entry point for SDK functionality (fee calculation, message sending, token pool access) +- **CCIPClient**: Main entry point for SDK functionality (fee calculation and message sending) - **CCIPAccountReader**: Handles fetching and decoding on-chain CCIP accounts - **Models**: Type definitions shared across all components -### Token Pools - -- **TokenPoolClient**: Abstract interface for token pool operations -- **BurnMintTokenPoolClient**: Implementation for burn-mint token pools -- **TokenPoolFactory**: Factory for creating and detecting token pool types ### Bindings @@ -351,163 +348,6 @@ const [tokenPoolsSigner] = await findDynamicTokenPoolsSignerPDA( ); ``` -## Token Pool Support - -The SDK provides support for interacting with different types of token pools used by CCIP for cross-chain transfers. - -### Token Pool Types - -Currently, the SDK supports the following pool types: - -- **Burn-Mint Pools**: Tokens are burned on the source chain and minted on the destination chain. - -### Using Token Pools - -Token pools can be accessed through the `CCIPClient`: - -```typescript -// Get a burn-mint token pool client -const burnMintPool = client.getTokenPoolClient(TokenPoolType.BURN_MINT); - -// Or auto-detect the pool type for a specific token mint -const pool = await client.getTokenPoolClientForMint(tokenMint); - -// Create a new pool for a token -const txSignature = await pool.createPool(tokenMint); - -// Configure a chain for cross-chain transfers -const chainConfig = { - enabled: true, - maxTokensPerMessage: new BN(1000000000), // 1 token with 9 decimals - feeBps: 10, // 0.1% fee -}; -await pool.configureChain(tokenMint, destinationChainSelector, chainConfig); - -// Set rate limits for a token -await pool.setRateLimit( - tokenMint, - new BN(1000000000), // Capacity: 1 token with 9 decimals - new BN(100000000) // Rate: 0.1 tokens per second -); - -// Transfer admin role for a token pool (two-step process) -// Step 1: Current owner proposes new admin -await pool.transferAdminRole(tokenMint, { newAdmin: newAdminPublicKey }); - -// Step 2: Proposed admin accepts the role (must be signed by newAdminPublicKey) -await pool.acceptAdminRole(tokenMint); -``` - -### Pool Ownership Management - -Token pools use a two-step ownership transfer process for security. This ensures that ownership can only be transferred to a valid recipient who explicitly accepts the role. - -#### Transfer Pool Ownership - -```typescript -import { - TokenPoolManager, - TokenPoolType, - TransferAdminRoleOptions, - AcceptAdminRoleOptions -} from "../path/to/ccip-lib/svm"; - -// Create token pool manager -const poolManager = TokenPoolManager.create( - connection, - currentOwnerKeypair, - { burnMint: burnMintPoolProgramId }, - config -); - -// Get the pool client -const pool = poolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - -// Step 1: Current owner proposes new administrator -await pool.transferAdminRole(tokenMint, { - newAdmin: newOwnerPublicKey, - skipPreflight: false, // Optional transaction settings -}); -``` - -#### Accept Pool Ownership - -```typescript -// The proposed new owner must sign this transaction -const newOwnerPoolManager = TokenPoolManager.create( - connection, - newOwnerKeypair, // Must be the proposed owner - { burnMint: burnMintPoolProgramId }, - config -); - -const newOwnerPool = newOwnerPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - -// Step 2: Proposed owner accepts the admin role -await newOwnerPool.acceptAdminRole(tokenMint, { - skipPreflight: false, // Optional transaction settings -}); -``` - -#### Pool Ownership Best Practices - -- **Two-Step Process**: Always use the two-step transfer process - never skip the acceptance step -- **Verify Recipients**: Ensure the new owner address is correct before proposing transfer -- **Test First**: Test the ownership transfer process on devnet before mainnet -- **Secure Keys**: The new owner must have secure access to their keypair to accept ownership -- **Monitor State**: Check pool configuration to verify ownership transfer completed successfully - -#### Checking Current Pool Owner - -```typescript -// Get pool information to check current owner -const poolInfo = await pool.getPoolInfo(tokenMint); -console.log(`Current owner: ${poolInfo.config.config.owner.toString()}`); -console.log(`Proposed owner: ${poolInfo.config.config.proposedOwner?.toString() || 'none'}`); -``` - -### Token Pool Factory - -For advanced usage, you can use the `TokenPoolFactory` directly: - -```typescript -import { TokenPoolFactory, TokenPoolType } from "../path/to/ccip-lib/svm"; - -// Create a specific token pool type -const pool = TokenPoolFactory.create(TokenPoolType.BURN_MINT, context); - -// Auto-detect the token pool type for a mint -const poolType = await TokenPoolFactory.detectPoolType(tokenMint, context); -const pool = TokenPoolFactory.create(poolType, context); -``` - -### PDA Utilities for Token Pools - -The SDK provides functions to derive all program-derived addresses used in token pools: - -```typescript -import { - findBurnMintPoolConfigPDA, - findBurnMintPoolChainConfigPDA, - findRateLimitPDA, -} from "../path/to/ccip-lib/svm"; - -// Get the pool config PDA -const [poolConfigPDA] = findBurnMintPoolConfigPDA( - tokenMint, - burnMintPoolProgramId -); - -// Get the chain config PDA -const [chainConfigPDA] = findBurnMintPoolChainConfigPDA( - chainSelector, - tokenMint, - burnMintPoolProgramId -); - -// Get the rate limit PDA -const [rateLimitPDA] = findRateLimitPDA(tokenMint, burnMintPoolProgramId); -``` ## Error Handling @@ -661,79 +501,3 @@ const verification = SolanaAccountManager.explainBitmap(dataTokensBitmap, 7); console.log("Data and tokens bitmap breakdown:", verification.accounts); ``` -## Token Administration - -The CCIP SDK works in conjunction with command-line scripts for complete token administration and registration for cross-chain transfers. - -### Overview - -To enable a token for CCIP cross-chain transfers, you need to follow a multi-step process: - -1. **Propose Administrator**: Set up admin permissions for a token -2. **Accept Admin Role**: Complete the administrator transfer -3. **Create ALT**: Create an Address Lookup Table with required accounts -4. **Set Pool**: Register the ALT with the token to enable CCIP -5. **Inspect Token**: Validate configuration against existing tokens - -### Command-Line Scripts - -For detailed instructions on each step, including all options, security considerations, and examples, see the comprehensive **[CCIP Scripts Documentation](../ccip-scripts/svm/README.md#3-token-admin-registry-management)**. - -#### Quick Reference - -```bash -# Step 1: Propose administrator (as mint authority) -yarn svm:admin:propose-administrator --token-mint - -# Step 2: Accept admin role (as proposed administrator) -yarn svm:admin:accept-admin-role --token-mint - -# Step 3: Create ALT (anyone can pay for creation) -yarn svm:admin:create-alt --token-mint --pool-program - -# Step 3a: Create ALT with additional custom addresses (optional) -yarn svm:admin:create-alt --token-mint --pool-program --additional-addresses - -# Step 4: Set pool (as administrator) -yarn svm:admin:set-pool --token-mint --lookup-table --writable-indices 3,4,7 - -# Step 5: Verify configuration -yarn svm:admin:inspect-token --token-mint -``` - -### Writable Indices Pattern - -The writable indices vary based on the token pool type: - -#### **Burn-Mint Tokens (Most Common): [3, 4, 7]** - -- **Index 3**: Pool Configuration PDA (sequence numbers, rate limits) -- **Index 4**: Pool Token Account (token balance changes) -- **Index 7**: Token Mint (supply changes during burn/mint operations) - -#### **Lock-Release Tokens: [3, 4, 5]** - -- **Index 3**: Pool Configuration PDA (sequence numbers, rate limits) -- **Index 4**: Pool Token Account (token balance changes) -- **Index 5**: Pool Signer PDA (authorizes transfers, may pay fees) - -### Programmatic Usage - -For programmatic token administration using the SDK, you can work with the underlying components: - -```typescript -// Access token admin registry -const registry = await client - .getAccountReader() - .getTokenAdminRegistry(tokenMint); - -// Get token pool for a mint -const pool = await client.getTokenPoolClientForMint(tokenMint); - -// Check if token is configured for CCIP -const isConfigured = registry.lookupTable !== PublicKey.default; -``` - -### Integration with Scripts - -The SDK complements the command-line scripts by providing the underlying functionality. While scripts handle the setup and configuration, the SDK enables programmatic interaction with configured tokens for cross-chain operations. diff --git a/ccip-lib/svm/burnmint-pool-bindings/accounts/ChainConfig.ts b/ccip-lib/svm/burnmint-pool-bindings/accounts/ChainConfig.ts deleted file mode 100644 index ead1af7c..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/accounts/ChainConfig.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { PublicKey, Connection } from "@solana/web3.js" -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface ChainConfigFields { - base: types.BaseChainFields -} - -export interface ChainConfigJSON { - base: types.BaseChainJSON -} - -export class ChainConfig { - readonly base: types.BaseChain - - static readonly discriminator = Buffer.from([ - 13, 177, 233, 141, 212, 29, 148, 56, - ]) - - static readonly layout = borsh.struct([types.BaseChain.layout("base")]) - - constructor(fields: ChainConfigFields) { - this.base = new types.BaseChain({ ...fields.base }) - } - - static async fetch( - c: Connection, - address: PublicKey, - programId: PublicKey = PROGRAM_ID - ): Promise { - const info = await c.getAccountInfo(address) - - if (info === null) { - return null - } - if (!info.owner.equals(programId)) { - throw new Error("account doesn't belong to this program") - } - - return this.decode(info.data) - } - - static async fetchMultiple( - c: Connection, - addresses: PublicKey[], - programId: PublicKey = PROGRAM_ID - ): Promise> { - const infos = await c.getMultipleAccountsInfo(addresses) - - return infos.map((info) => { - if (info === null) { - return null - } - if (!info.owner.equals(programId)) { - throw new Error("account doesn't belong to this program") - } - - return this.decode(info.data) - }) - } - - static decode(data: Buffer): ChainConfig { - if (!data.slice(0, 8).equals(ChainConfig.discriminator)) { - throw new Error("invalid account discriminator") - } - - const dec = ChainConfig.layout.decode(data.slice(8)) - - return new ChainConfig({ - base: types.BaseChain.fromDecoded(dec.base), - }) - } - - toJSON(): ChainConfigJSON { - return { - base: this.base.toJSON(), - } - } - - static fromJSON(obj: ChainConfigJSON): ChainConfig { - return new ChainConfig({ - base: types.BaseChain.fromJSON(obj.base), - }) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/accounts/PoolConfig.ts b/ccip-lib/svm/burnmint-pool-bindings/accounts/PoolConfig.ts deleted file mode 100644 index 37faac47..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/accounts/PoolConfig.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { PublicKey, Connection } from "@solana/web3.js" -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface PoolConfigFields { - version: number - selfServedAllowed: boolean - router: PublicKey - rmnRemote: PublicKey -} - -export interface PoolConfigJSON { - version: number - selfServedAllowed: boolean - router: string - rmnRemote: string -} - -export class PoolConfig { - readonly version: number - readonly selfServedAllowed: boolean - readonly router: PublicKey - readonly rmnRemote: PublicKey - - static readonly discriminator = Buffer.from([ - 26, 108, 14, 123, 116, 230, 129, 43, - ]) - - static readonly layout = borsh.struct([ - borsh.u8("version"), - borsh.bool("selfServedAllowed"), - borsh.publicKey("router"), - borsh.publicKey("rmnRemote"), - ]) - - constructor(fields: PoolConfigFields) { - this.version = fields.version - this.selfServedAllowed = fields.selfServedAllowed - this.router = fields.router - this.rmnRemote = fields.rmnRemote - } - - static async fetch( - c: Connection, - address: PublicKey, - programId: PublicKey = PROGRAM_ID - ): Promise { - const info = await c.getAccountInfo(address) - - if (info === null) { - return null - } - if (!info.owner.equals(programId)) { - throw new Error("account doesn't belong to this program") - } - - return this.decode(info.data) - } - - static async fetchMultiple( - c: Connection, - addresses: PublicKey[], - programId: PublicKey = PROGRAM_ID - ): Promise> { - const infos = await c.getMultipleAccountsInfo(addresses) - - return infos.map((info) => { - if (info === null) { - return null - } - if (!info.owner.equals(programId)) { - throw new Error("account doesn't belong to this program") - } - - return this.decode(info.data) - }) - } - - static decode(data: Buffer): PoolConfig { - if (!data.slice(0, 8).equals(PoolConfig.discriminator)) { - throw new Error("invalid account discriminator") - } - - const dec = PoolConfig.layout.decode(data.slice(8)) - - return new PoolConfig({ - version: dec.version, - selfServedAllowed: dec.selfServedAllowed, - router: dec.router, - rmnRemote: dec.rmnRemote, - }) - } - - toJSON(): PoolConfigJSON { - return { - version: this.version, - selfServedAllowed: this.selfServedAllowed, - router: this.router.toString(), - rmnRemote: this.rmnRemote.toString(), - } - } - - static fromJSON(obj: PoolConfigJSON): PoolConfig { - return new PoolConfig({ - version: obj.version, - selfServedAllowed: obj.selfServedAllowed, - router: new PublicKey(obj.router), - rmnRemote: new PublicKey(obj.rmnRemote), - }) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/accounts/State.ts b/ccip-lib/svm/burnmint-pool-bindings/accounts/State.ts deleted file mode 100644 index 6e49bcd4..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/accounts/State.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { PublicKey, Connection } from "@solana/web3.js" -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface StateFields { - version: number - config: types.BaseConfigFields -} - -export interface StateJSON { - version: number - config: types.BaseConfigJSON -} - -export class State { - readonly version: number - readonly config: types.BaseConfig - - static readonly discriminator = Buffer.from([ - 216, 146, 107, 94, 104, 75, 182, 177, - ]) - - static readonly layout = borsh.struct([ - borsh.u8("version"), - types.BaseConfig.layout("config"), - ]) - - constructor(fields: StateFields) { - this.version = fields.version - this.config = new types.BaseConfig({ ...fields.config }) - } - - static async fetch( - c: Connection, - address: PublicKey, - programId: PublicKey = PROGRAM_ID - ): Promise { - const info = await c.getAccountInfo(address) - - if (info === null) { - return null - } - if (!info.owner.equals(programId)) { - throw new Error("account doesn't belong to this program") - } - - return this.decode(info.data) - } - - static async fetchMultiple( - c: Connection, - addresses: PublicKey[], - programId: PublicKey = PROGRAM_ID - ): Promise> { - const infos = await c.getMultipleAccountsInfo(addresses) - - return infos.map((info) => { - if (info === null) { - return null - } - if (!info.owner.equals(programId)) { - throw new Error("account doesn't belong to this program") - } - - return this.decode(info.data) - }) - } - - static decode(data: Buffer): State { - if (!data.slice(0, 8).equals(State.discriminator)) { - throw new Error("invalid account discriminator") - } - - const dec = State.layout.decode(data.slice(8)) - - return new State({ - version: dec.version, - config: types.BaseConfig.fromDecoded(dec.config), - }) - } - - toJSON(): StateJSON { - return { - version: this.version, - config: this.config.toJSON(), - } - } - - static fromJSON(obj: StateJSON): State { - return new State({ - version: obj.version, - config: types.BaseConfig.fromJSON(obj.config), - }) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/accounts/index.ts b/ccip-lib/svm/burnmint-pool-bindings/accounts/index.ts deleted file mode 100644 index 6cb1e2a4..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/accounts/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { PoolConfig } from "./PoolConfig" -export type { PoolConfigFields, PoolConfigJSON } from "./PoolConfig" -export { State } from "./State" -export type { StateFields, StateJSON } from "./State" -export { ChainConfig } from "./ChainConfig" -export type { ChainConfigFields, ChainConfigJSON } from "./ChainConfig" diff --git a/ccip-lib/svm/burnmint-pool-bindings/errors/anchor.ts b/ccip-lib/svm/burnmint-pool-bindings/errors/anchor.ts deleted file mode 100644 index f40da698..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/errors/anchor.ts +++ /dev/null @@ -1,773 +0,0 @@ -export type AnchorError = - | InstructionMissing - | InstructionFallbackNotFound - | InstructionDidNotDeserialize - | InstructionDidNotSerialize - | IdlInstructionStub - | IdlInstructionInvalidProgram - | ConstraintMut - | ConstraintHasOne - | ConstraintSigner - | ConstraintRaw - | ConstraintOwner - | ConstraintRentExempt - | ConstraintSeeds - | ConstraintExecutable - | ConstraintState - | ConstraintAssociated - | ConstraintAssociatedInit - | ConstraintClose - | ConstraintAddress - | ConstraintZero - | ConstraintTokenMint - | ConstraintTokenOwner - | ConstraintMintMintAuthority - | ConstraintMintFreezeAuthority - | ConstraintMintDecimals - | ConstraintSpace - | ConstraintAccountIsNone - | RequireViolated - | RequireEqViolated - | RequireKeysEqViolated - | RequireNeqViolated - | RequireKeysNeqViolated - | RequireGtViolated - | RequireGteViolated - | AccountDiscriminatorAlreadySet - | AccountDiscriminatorNotFound - | AccountDiscriminatorMismatch - | AccountDidNotDeserialize - | AccountDidNotSerialize - | AccountNotEnoughKeys - | AccountNotMutable - | AccountOwnedByWrongProgram - | InvalidProgramId - | InvalidProgramExecutable - | AccountNotSigner - | AccountNotSystemOwned - | AccountNotInitialized - | AccountNotProgramData - | AccountNotAssociatedTokenAccount - | AccountSysvarMismatch - | AccountReallocExceedsLimit - | AccountDuplicateReallocs - | DeclaredProgramIdMismatch - | Deprecated - -export class InstructionMissing extends Error { - static readonly code = 100 - readonly code = 100 - readonly name = "InstructionMissing" - readonly msg = "8 byte instruction identifier not provided" - - constructor(readonly logs?: string[]) { - super("100: 8 byte instruction identifier not provided") - } -} - -export class InstructionFallbackNotFound extends Error { - static readonly code = 101 - readonly code = 101 - readonly name = "InstructionFallbackNotFound" - readonly msg = "Fallback functions are not supported" - - constructor(readonly logs?: string[]) { - super("101: Fallback functions are not supported") - } -} - -export class InstructionDidNotDeserialize extends Error { - static readonly code = 102 - readonly code = 102 - readonly name = "InstructionDidNotDeserialize" - readonly msg = "The program could not deserialize the given instruction" - - constructor(readonly logs?: string[]) { - super("102: The program could not deserialize the given instruction") - } -} - -export class InstructionDidNotSerialize extends Error { - static readonly code = 103 - readonly code = 103 - readonly name = "InstructionDidNotSerialize" - readonly msg = "The program could not serialize the given instruction" - - constructor(readonly logs?: string[]) { - super("103: The program could not serialize the given instruction") - } -} - -export class IdlInstructionStub extends Error { - static readonly code = 1000 - readonly code = 1000 - readonly name = "IdlInstructionStub" - readonly msg = "The program was compiled without idl instructions" - - constructor(readonly logs?: string[]) { - super("1000: The program was compiled without idl instructions") - } -} - -export class IdlInstructionInvalidProgram extends Error { - static readonly code = 1001 - readonly code = 1001 - readonly name = "IdlInstructionInvalidProgram" - readonly msg = - "The transaction was given an invalid program for the IDL instruction" - - constructor(readonly logs?: string[]) { - super( - "1001: The transaction was given an invalid program for the IDL instruction" - ) - } -} - -export class ConstraintMut extends Error { - static readonly code = 2000 - readonly code = 2000 - readonly name = "ConstraintMut" - readonly msg = "A mut constraint was violated" - - constructor(readonly logs?: string[]) { - super("2000: A mut constraint was violated") - } -} - -export class ConstraintHasOne extends Error { - static readonly code = 2001 - readonly code = 2001 - readonly name = "ConstraintHasOne" - readonly msg = "A has one constraint was violated" - - constructor(readonly logs?: string[]) { - super("2001: A has one constraint was violated") - } -} - -export class ConstraintSigner extends Error { - static readonly code = 2002 - readonly code = 2002 - readonly name = "ConstraintSigner" - readonly msg = "A signer constraint was violated" - - constructor(readonly logs?: string[]) { - super("2002: A signer constraint was violated") - } -} - -export class ConstraintRaw extends Error { - static readonly code = 2003 - readonly code = 2003 - readonly name = "ConstraintRaw" - readonly msg = "A raw constraint was violated" - - constructor(readonly logs?: string[]) { - super("2003: A raw constraint was violated") - } -} - -export class ConstraintOwner extends Error { - static readonly code = 2004 - readonly code = 2004 - readonly name = "ConstraintOwner" - readonly msg = "An owner constraint was violated" - - constructor(readonly logs?: string[]) { - super("2004: An owner constraint was violated") - } -} - -export class ConstraintRentExempt extends Error { - static readonly code = 2005 - readonly code = 2005 - readonly name = "ConstraintRentExempt" - readonly msg = "A rent exemption constraint was violated" - - constructor(readonly logs?: string[]) { - super("2005: A rent exemption constraint was violated") - } -} - -export class ConstraintSeeds extends Error { - static readonly code = 2006 - readonly code = 2006 - readonly name = "ConstraintSeeds" - readonly msg = "A seeds constraint was violated" - - constructor(readonly logs?: string[]) { - super("2006: A seeds constraint was violated") - } -} - -export class ConstraintExecutable extends Error { - static readonly code = 2007 - readonly code = 2007 - readonly name = "ConstraintExecutable" - readonly msg = "An executable constraint was violated" - - constructor(readonly logs?: string[]) { - super("2007: An executable constraint was violated") - } -} - -export class ConstraintState extends Error { - static readonly code = 2008 - readonly code = 2008 - readonly name = "ConstraintState" - readonly msg = "Deprecated Error, feel free to replace with something else" - - constructor(readonly logs?: string[]) { - super("2008: Deprecated Error, feel free to replace with something else") - } -} - -export class ConstraintAssociated extends Error { - static readonly code = 2009 - readonly code = 2009 - readonly name = "ConstraintAssociated" - readonly msg = "An associated constraint was violated" - - constructor(readonly logs?: string[]) { - super("2009: An associated constraint was violated") - } -} - -export class ConstraintAssociatedInit extends Error { - static readonly code = 2010 - readonly code = 2010 - readonly name = "ConstraintAssociatedInit" - readonly msg = "An associated init constraint was violated" - - constructor(readonly logs?: string[]) { - super("2010: An associated init constraint was violated") - } -} - -export class ConstraintClose extends Error { - static readonly code = 2011 - readonly code = 2011 - readonly name = "ConstraintClose" - readonly msg = "A close constraint was violated" - - constructor(readonly logs?: string[]) { - super("2011: A close constraint was violated") - } -} - -export class ConstraintAddress extends Error { - static readonly code = 2012 - readonly code = 2012 - readonly name = "ConstraintAddress" - readonly msg = "An address constraint was violated" - - constructor(readonly logs?: string[]) { - super("2012: An address constraint was violated") - } -} - -export class ConstraintZero extends Error { - static readonly code = 2013 - readonly code = 2013 - readonly name = "ConstraintZero" - readonly msg = "Expected zero account discriminant" - - constructor(readonly logs?: string[]) { - super("2013: Expected zero account discriminant") - } -} - -export class ConstraintTokenMint extends Error { - static readonly code = 2014 - readonly code = 2014 - readonly name = "ConstraintTokenMint" - readonly msg = "A token mint constraint was violated" - - constructor(readonly logs?: string[]) { - super("2014: A token mint constraint was violated") - } -} - -export class ConstraintTokenOwner extends Error { - static readonly code = 2015 - readonly code = 2015 - readonly name = "ConstraintTokenOwner" - readonly msg = "A token owner constraint was violated" - - constructor(readonly logs?: string[]) { - super("2015: A token owner constraint was violated") - } -} - -export class ConstraintMintMintAuthority extends Error { - static readonly code = 2016 - readonly code = 2016 - readonly name = "ConstraintMintMintAuthority" - readonly msg = "A mint mint authority constraint was violated" - - constructor(readonly logs?: string[]) { - super("2016: A mint mint authority constraint was violated") - } -} - -export class ConstraintMintFreezeAuthority extends Error { - static readonly code = 2017 - readonly code = 2017 - readonly name = "ConstraintMintFreezeAuthority" - readonly msg = "A mint freeze authority constraint was violated" - - constructor(readonly logs?: string[]) { - super("2017: A mint freeze authority constraint was violated") - } -} - -export class ConstraintMintDecimals extends Error { - static readonly code = 2018 - readonly code = 2018 - readonly name = "ConstraintMintDecimals" - readonly msg = "A mint decimals constraint was violated" - - constructor(readonly logs?: string[]) { - super("2018: A mint decimals constraint was violated") - } -} - -export class ConstraintSpace extends Error { - static readonly code = 2019 - readonly code = 2019 - readonly name = "ConstraintSpace" - readonly msg = "A space constraint was violated" - - constructor(readonly logs?: string[]) { - super("2019: A space constraint was violated") - } -} - -export class ConstraintAccountIsNone extends Error { - static readonly code = 2020 - readonly code = 2020 - readonly name = "ConstraintAccountIsNone" - readonly msg = "A required account for the constraint is None" - - constructor(readonly logs?: string[]) { - super("2020: A required account for the constraint is None") - } -} - -export class RequireViolated extends Error { - static readonly code = 2500 - readonly code = 2500 - readonly name = "RequireViolated" - readonly msg = "A require expression was violated" - - constructor(readonly logs?: string[]) { - super("2500: A require expression was violated") - } -} - -export class RequireEqViolated extends Error { - static readonly code = 2501 - readonly code = 2501 - readonly name = "RequireEqViolated" - readonly msg = "A require_eq expression was violated" - - constructor(readonly logs?: string[]) { - super("2501: A require_eq expression was violated") - } -} - -export class RequireKeysEqViolated extends Error { - static readonly code = 2502 - readonly code = 2502 - readonly name = "RequireKeysEqViolated" - readonly msg = "A require_keys_eq expression was violated" - - constructor(readonly logs?: string[]) { - super("2502: A require_keys_eq expression was violated") - } -} - -export class RequireNeqViolated extends Error { - static readonly code = 2503 - readonly code = 2503 - readonly name = "RequireNeqViolated" - readonly msg = "A require_neq expression was violated" - - constructor(readonly logs?: string[]) { - super("2503: A require_neq expression was violated") - } -} - -export class RequireKeysNeqViolated extends Error { - static readonly code = 2504 - readonly code = 2504 - readonly name = "RequireKeysNeqViolated" - readonly msg = "A require_keys_neq expression was violated" - - constructor(readonly logs?: string[]) { - super("2504: A require_keys_neq expression was violated") - } -} - -export class RequireGtViolated extends Error { - static readonly code = 2505 - readonly code = 2505 - readonly name = "RequireGtViolated" - readonly msg = "A require_gt expression was violated" - - constructor(readonly logs?: string[]) { - super("2505: A require_gt expression was violated") - } -} - -export class RequireGteViolated extends Error { - static readonly code = 2506 - readonly code = 2506 - readonly name = "RequireGteViolated" - readonly msg = "A require_gte expression was violated" - - constructor(readonly logs?: string[]) { - super("2506: A require_gte expression was violated") - } -} - -export class AccountDiscriminatorAlreadySet extends Error { - static readonly code = 3000 - readonly code = 3000 - readonly name = "AccountDiscriminatorAlreadySet" - readonly msg = "The account discriminator was already set on this account" - - constructor(readonly logs?: string[]) { - super("3000: The account discriminator was already set on this account") - } -} - -export class AccountDiscriminatorNotFound extends Error { - static readonly code = 3001 - readonly code = 3001 - readonly name = "AccountDiscriminatorNotFound" - readonly msg = "No 8 byte discriminator was found on the account" - - constructor(readonly logs?: string[]) { - super("3001: No 8 byte discriminator was found on the account") - } -} - -export class AccountDiscriminatorMismatch extends Error { - static readonly code = 3002 - readonly code = 3002 - readonly name = "AccountDiscriminatorMismatch" - readonly msg = "8 byte discriminator did not match what was expected" - - constructor(readonly logs?: string[]) { - super("3002: 8 byte discriminator did not match what was expected") - } -} - -export class AccountDidNotDeserialize extends Error { - static readonly code = 3003 - readonly code = 3003 - readonly name = "AccountDidNotDeserialize" - readonly msg = "Failed to deserialize the account" - - constructor(readonly logs?: string[]) { - super("3003: Failed to deserialize the account") - } -} - -export class AccountDidNotSerialize extends Error { - static readonly code = 3004 - readonly code = 3004 - readonly name = "AccountDidNotSerialize" - readonly msg = "Failed to serialize the account" - - constructor(readonly logs?: string[]) { - super("3004: Failed to serialize the account") - } -} - -export class AccountNotEnoughKeys extends Error { - static readonly code = 3005 - readonly code = 3005 - readonly name = "AccountNotEnoughKeys" - readonly msg = "Not enough account keys given to the instruction" - - constructor(readonly logs?: string[]) { - super("3005: Not enough account keys given to the instruction") - } -} - -export class AccountNotMutable extends Error { - static readonly code = 3006 - readonly code = 3006 - readonly name = "AccountNotMutable" - readonly msg = "The given account is not mutable" - - constructor(readonly logs?: string[]) { - super("3006: The given account is not mutable") - } -} - -export class AccountOwnedByWrongProgram extends Error { - static readonly code = 3007 - readonly code = 3007 - readonly name = "AccountOwnedByWrongProgram" - readonly msg = - "The given account is owned by a different program than expected" - - constructor(readonly logs?: string[]) { - super( - "3007: The given account is owned by a different program than expected" - ) - } -} - -export class InvalidProgramId extends Error { - static readonly code = 3008 - readonly code = 3008 - readonly name = "InvalidProgramId" - readonly msg = "Program ID was not as expected" - - constructor(readonly logs?: string[]) { - super("3008: Program ID was not as expected") - } -} - -export class InvalidProgramExecutable extends Error { - static readonly code = 3009 - readonly code = 3009 - readonly name = "InvalidProgramExecutable" - readonly msg = "Program account is not executable" - - constructor(readonly logs?: string[]) { - super("3009: Program account is not executable") - } -} - -export class AccountNotSigner extends Error { - static readonly code = 3010 - readonly code = 3010 - readonly name = "AccountNotSigner" - readonly msg = "The given account did not sign" - - constructor(readonly logs?: string[]) { - super("3010: The given account did not sign") - } -} - -export class AccountNotSystemOwned extends Error { - static readonly code = 3011 - readonly code = 3011 - readonly name = "AccountNotSystemOwned" - readonly msg = "The given account is not owned by the system program" - - constructor(readonly logs?: string[]) { - super("3011: The given account is not owned by the system program") - } -} - -export class AccountNotInitialized extends Error { - static readonly code = 3012 - readonly code = 3012 - readonly name = "AccountNotInitialized" - readonly msg = "The program expected this account to be already initialized" - - constructor(readonly logs?: string[]) { - super("3012: The program expected this account to be already initialized") - } -} - -export class AccountNotProgramData extends Error { - static readonly code = 3013 - readonly code = 3013 - readonly name = "AccountNotProgramData" - readonly msg = "The given account is not a program data account" - - constructor(readonly logs?: string[]) { - super("3013: The given account is not a program data account") - } -} - -export class AccountNotAssociatedTokenAccount extends Error { - static readonly code = 3014 - readonly code = 3014 - readonly name = "AccountNotAssociatedTokenAccount" - readonly msg = "The given account is not the associated token account" - - constructor(readonly logs?: string[]) { - super("3014: The given account is not the associated token account") - } -} - -export class AccountSysvarMismatch extends Error { - static readonly code = 3015 - readonly code = 3015 - readonly name = "AccountSysvarMismatch" - readonly msg = "The given public key does not match the required sysvar" - - constructor(readonly logs?: string[]) { - super("3015: The given public key does not match the required sysvar") - } -} - -export class AccountReallocExceedsLimit extends Error { - static readonly code = 3016 - readonly code = 3016 - readonly name = "AccountReallocExceedsLimit" - readonly msg = - "The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit" - - constructor(readonly logs?: string[]) { - super( - "3016: The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit" - ) - } -} - -export class AccountDuplicateReallocs extends Error { - static readonly code = 3017 - readonly code = 3017 - readonly name = "AccountDuplicateReallocs" - readonly msg = "The account was duplicated for more than one reallocation" - - constructor(readonly logs?: string[]) { - super("3017: The account was duplicated for more than one reallocation") - } -} - -export class DeclaredProgramIdMismatch extends Error { - static readonly code = 4100 - readonly code = 4100 - readonly name = "DeclaredProgramIdMismatch" - readonly msg = "The declared program id does not match the actual program id" - - constructor(readonly logs?: string[]) { - super("4100: The declared program id does not match the actual program id") - } -} - -export class Deprecated extends Error { - static readonly code = 5000 - readonly code = 5000 - readonly name = "Deprecated" - readonly msg = "The API being used is deprecated and should no longer be used" - - constructor(readonly logs?: string[]) { - super("5000: The API being used is deprecated and should no longer be used") - } -} - -export function fromCode(code: number, logs?: string[]): AnchorError | null { - switch (code) { - case 100: - return new InstructionMissing(logs) - case 101: - return new InstructionFallbackNotFound(logs) - case 102: - return new InstructionDidNotDeserialize(logs) - case 103: - return new InstructionDidNotSerialize(logs) - case 1000: - return new IdlInstructionStub(logs) - case 1001: - return new IdlInstructionInvalidProgram(logs) - case 2000: - return new ConstraintMut(logs) - case 2001: - return new ConstraintHasOne(logs) - case 2002: - return new ConstraintSigner(logs) - case 2003: - return new ConstraintRaw(logs) - case 2004: - return new ConstraintOwner(logs) - case 2005: - return new ConstraintRentExempt(logs) - case 2006: - return new ConstraintSeeds(logs) - case 2007: - return new ConstraintExecutable(logs) - case 2008: - return new ConstraintState(logs) - case 2009: - return new ConstraintAssociated(logs) - case 2010: - return new ConstraintAssociatedInit(logs) - case 2011: - return new ConstraintClose(logs) - case 2012: - return new ConstraintAddress(logs) - case 2013: - return new ConstraintZero(logs) - case 2014: - return new ConstraintTokenMint(logs) - case 2015: - return new ConstraintTokenOwner(logs) - case 2016: - return new ConstraintMintMintAuthority(logs) - case 2017: - return new ConstraintMintFreezeAuthority(logs) - case 2018: - return new ConstraintMintDecimals(logs) - case 2019: - return new ConstraintSpace(logs) - case 2020: - return new ConstraintAccountIsNone(logs) - case 2500: - return new RequireViolated(logs) - case 2501: - return new RequireEqViolated(logs) - case 2502: - return new RequireKeysEqViolated(logs) - case 2503: - return new RequireNeqViolated(logs) - case 2504: - return new RequireKeysNeqViolated(logs) - case 2505: - return new RequireGtViolated(logs) - case 2506: - return new RequireGteViolated(logs) - case 3000: - return new AccountDiscriminatorAlreadySet(logs) - case 3001: - return new AccountDiscriminatorNotFound(logs) - case 3002: - return new AccountDiscriminatorMismatch(logs) - case 3003: - return new AccountDidNotDeserialize(logs) - case 3004: - return new AccountDidNotSerialize(logs) - case 3005: - return new AccountNotEnoughKeys(logs) - case 3006: - return new AccountNotMutable(logs) - case 3007: - return new AccountOwnedByWrongProgram(logs) - case 3008: - return new InvalidProgramId(logs) - case 3009: - return new InvalidProgramExecutable(logs) - case 3010: - return new AccountNotSigner(logs) - case 3011: - return new AccountNotSystemOwned(logs) - case 3012: - return new AccountNotInitialized(logs) - case 3013: - return new AccountNotProgramData(logs) - case 3014: - return new AccountNotAssociatedTokenAccount(logs) - case 3015: - return new AccountSysvarMismatch(logs) - case 3016: - return new AccountReallocExceedsLimit(logs) - case 3017: - return new AccountDuplicateReallocs(logs) - case 4100: - return new DeclaredProgramIdMismatch(logs) - case 5000: - return new Deprecated(logs) - } - - return null -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/errors/custom.ts b/ccip-lib/svm/burnmint-pool-bindings/errors/custom.ts deleted file mode 100644 index 2b0b76a3..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/errors/custom.ts +++ /dev/null @@ -1,185 +0,0 @@ -export type CustomError = - | InvalidMultisig - | MintAuthorityAlreadySet - | FixedMintToken - | UnsupportedTokenProgram - | InvalidToken2022Multisig - | InvalidSPLTokenMultisig - | PoolSignerNotInMultisig - | MultisigMustHaveAtLeastTwoSigners - | MultisigMustHaveMoreThanOneSigner - | InvalidMultisigOwner - | InvalidMultisigThreshold - | InvalidMultisigThresholdTooHigh - -export class InvalidMultisig extends Error { - static readonly code = 6000 - readonly code = 6000 - readonly name = "InvalidMultisig" - readonly msg = "Invalid Multisig Mint" - - constructor(readonly logs?: string[]) { - super("6000: Invalid Multisig Mint") - } -} - -export class MintAuthorityAlreadySet extends Error { - static readonly code = 6001 - readonly code = 6001 - readonly name = "MintAuthorityAlreadySet" - readonly msg = "Mint Authority already set" - - constructor(readonly logs?: string[]) { - super("6001: Mint Authority already set") - } -} - -export class FixedMintToken extends Error { - static readonly code = 6002 - readonly code = 6002 - readonly name = "FixedMintToken" - readonly msg = "Token with no Mint Authority" - - constructor(readonly logs?: string[]) { - super("6002: Token with no Mint Authority") - } -} - -export class UnsupportedTokenProgram extends Error { - static readonly code = 6003 - readonly code = 6003 - readonly name = "UnsupportedTokenProgram" - readonly msg = "Unsupported Token Program" - - constructor(readonly logs?: string[]) { - super("6003: Unsupported Token Program") - } -} - -export class InvalidToken2022Multisig extends Error { - static readonly code = 6004 - readonly code = 6004 - readonly name = "InvalidToken2022Multisig" - readonly msg = "Invalid Multisig Account Data for Token 2022" - - constructor(readonly logs?: string[]) { - super("6004: Invalid Multisig Account Data for Token 2022") - } -} - -export class InvalidSPLTokenMultisig extends Error { - static readonly code = 6005 - readonly code = 6005 - readonly name = "InvalidSPLTokenMultisig" - readonly msg = "Invalid Multisig Account Data for SPL Token" - - constructor(readonly logs?: string[]) { - super("6005: Invalid Multisig Account Data for SPL Token") - } -} - -export class PoolSignerNotInMultisig extends Error { - static readonly code = 6006 - readonly code = 6006 - readonly name = "PoolSignerNotInMultisig" - readonly msg = - "Token Pool Signer PDA must be m times a signer of the Multisig" - - constructor(readonly logs?: string[]) { - super( - "6006: Token Pool Signer PDA must be m times a signer of the Multisig" - ) - } -} - -export class MultisigMustHaveAtLeastTwoSigners extends Error { - static readonly code = 6007 - readonly code = 6007 - readonly name = "MultisigMustHaveAtLeastTwoSigners" - readonly msg = "Multisig must have more than 2 valid signers" - - constructor(readonly logs?: string[]) { - super("6007: Multisig must have more than 2 valid signers") - } -} - -export class MultisigMustHaveMoreThanOneSigner extends Error { - static readonly code = 6008 - readonly code = 6008 - readonly name = "MultisigMustHaveMoreThanOneSigner" - readonly msg = "Multisig must have more than one required signer" - - constructor(readonly logs?: string[]) { - super("6008: Multisig must have more than one required signer") - } -} - -export class InvalidMultisigOwner extends Error { - static readonly code = 6009 - readonly code = 6009 - readonly name = "InvalidMultisigOwner" - readonly msg = "Multisig Owner must match Token Program ID" - - constructor(readonly logs?: string[]) { - super("6009: Multisig Owner must match Token Program ID") - } -} - -export class InvalidMultisigThreshold extends Error { - static readonly code = 6010 - readonly code = 6010 - readonly name = "InvalidMultisigThreshold" - readonly msg = - "Invalid multisig threshold: required signatures cannot exceed total signers" - - constructor(readonly logs?: string[]) { - super( - "6010: Invalid multisig threshold: required signatures cannot exceed total signers" - ) - } -} - -export class InvalidMultisigThresholdTooHigh extends Error { - static readonly code = 6011 - readonly code = 6011 - readonly name = "InvalidMultisigThresholdTooHigh" - readonly msg = - "Invalid multisig m: required signatures cannot exceed the available for outside signers" - - constructor(readonly logs?: string[]) { - super( - "6011: Invalid multisig m: required signatures cannot exceed the available for outside signers" - ) - } -} - -export function fromCode(code: number, logs?: string[]): CustomError | null { - switch (code) { - case 6000: - return new InvalidMultisig(logs) - case 6001: - return new MintAuthorityAlreadySet(logs) - case 6002: - return new FixedMintToken(logs) - case 6003: - return new UnsupportedTokenProgram(logs) - case 6004: - return new InvalidToken2022Multisig(logs) - case 6005: - return new InvalidSPLTokenMultisig(logs) - case 6006: - return new PoolSignerNotInMultisig(logs) - case 6007: - return new MultisigMustHaveAtLeastTwoSigners(logs) - case 6008: - return new MultisigMustHaveMoreThanOneSigner(logs) - case 6009: - return new InvalidMultisigOwner(logs) - case 6010: - return new InvalidMultisigThreshold(logs) - case 6011: - return new InvalidMultisigThresholdTooHigh(logs) - } - - return null -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/errors/index.ts b/ccip-lib/svm/burnmint-pool-bindings/errors/index.ts deleted file mode 100644 index f5e92d69..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/errors/index.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { PublicKey } from "@solana/web3.js" -import { PROGRAM_ID } from "../programId" -import * as anchor from "./anchor" -import * as custom from "./custom" - -export function fromCode( - code: number, - logs?: string[] -): custom.CustomError | anchor.AnchorError | null { - return code >= 6000 - ? custom.fromCode(code, logs) - : anchor.fromCode(code, logs) -} - -function hasOwnProperty( - obj: X, - prop: Y -): obj is X & Record { - return Object.hasOwnProperty.call(obj, prop) -} - -const errorRe = /Program (\w+) failed: custom program error: (\w+)/ - -export function fromTxError( - err: unknown, - programId: PublicKey = PROGRAM_ID -): custom.CustomError | anchor.AnchorError | null { - if ( - typeof err !== "object" || - err === null || - !hasOwnProperty(err, "logs") || - !Array.isArray(err.logs) - ) { - return null - } - - let firstMatch: RegExpExecArray | null = null - for (const logLine of err.logs) { - firstMatch = errorRe.exec(logLine) - if (firstMatch !== null) { - break - } - } - - if (firstMatch === null) { - return null - } - - const [programIdRaw, codeRaw] = firstMatch.slice(1) - if (programIdRaw !== programId.toString()) { - return null - } - - let errorCode: number - try { - errorCode = parseInt(codeRaw, 16) - } catch (parseErr) { - return null - } - - return fromCode(errorCode, err.logs) -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/acceptOwnership.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/acceptOwnership.ts deleted file mode 100644 index c1cf8c3b..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/acceptOwnership.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface AcceptOwnershipAccounts { - state: PublicKey - mint: PublicKey - authority: PublicKey -} - -export function acceptOwnership( - accounts: AcceptOwnershipAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - { pubkey: accounts.mint, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - ] - const identifier = Buffer.from([172, 23, 43, 13, 238, 213, 85, 150]) - const data = identifier - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/accept_ownership.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/accept_ownership.ts deleted file mode 100644 index f30c1dc1..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/accept_ownership.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Accept_ownershipAccounts { - state: PublicKey - mint: PublicKey - authority: PublicKey -} - -export function accept_ownership( - accounts: Accept_ownershipAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - { pubkey: accounts.mint, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - ] - const identifier = Buffer.from([172, 23, 43, 13, 238, 213, 85, 150]) - const data = identifier - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/appendRemotePoolAddresses.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/appendRemotePoolAddresses.ts deleted file mode 100644 index 9fa624ba..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/appendRemotePoolAddresses.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface AppendRemotePoolAddressesArgs { - remoteChainSelector: BN - mint: PublicKey - addresses: Array -} - -export interface AppendRemotePoolAddressesAccounts { - state: PublicKey - chainConfig: PublicKey - authority: PublicKey - systemProgram: PublicKey -} - -export const layout = borsh.struct([ - borsh.u64("remoteChainSelector"), - borsh.publicKey("mint"), - borsh.vec(types.RemoteAddress.layout(), "addresses"), -]) - -export function appendRemotePoolAddresses( - args: AppendRemotePoolAddressesArgs, - accounts: AppendRemotePoolAddressesAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.chainConfig, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.systemProgram, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([172, 57, 83, 55, 70, 112, 26, 197]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - remoteChainSelector: args.remoteChainSelector, - mint: args.mint, - addresses: args.addresses.map((item) => - types.RemoteAddress.toEncodable(item) - ), - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/append_remote_pool_addresses.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/append_remote_pool_addresses.ts deleted file mode 100644 index 9d17f44e..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/append_remote_pool_addresses.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Append_remote_pool_addressesArgs { - remote_chain_selector: BN - _mint: PublicKey - addresses: Array -} - -export interface Append_remote_pool_addressesAccounts { - state: PublicKey - chain_config: PublicKey - authority: PublicKey - system_program: PublicKey -} - -export const layout = borsh.struct([ - borsh.u64("remote_chain_selector"), - borsh.publicKey("_mint"), - borsh.vec(types.RemoteAddress.layout(), "addresses"), -]) - -export function append_remote_pool_addresses( - args: Append_remote_pool_addressesArgs, - accounts: Append_remote_pool_addressesAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.chain_config, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.system_program, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([172, 57, 83, 55, 70, 112, 26, 197]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - remote_chain_selector: args.remote_chain_selector, - _mint: args._mint, - addresses: args.addresses.map((item) => - types.RemoteAddress.toEncodable(item) - ), - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/configureAllowList.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/configureAllowList.ts deleted file mode 100644 index 72cc766a..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/configureAllowList.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface ConfigureAllowListArgs { - add: Array - enabled: boolean -} - -export interface ConfigureAllowListAccounts { - state: PublicKey - mint: PublicKey - authority: PublicKey - systemProgram: PublicKey -} - -export const layout = borsh.struct([ - borsh.vec(borsh.publicKey(), "add"), - borsh.bool("enabled"), -]) - -export function configureAllowList( - args: ConfigureAllowListArgs, - accounts: ConfigureAllowListAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - { pubkey: accounts.mint, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.systemProgram, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([18, 180, 102, 187, 209, 0, 130, 191]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - add: args.add, - enabled: args.enabled, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/configure_allow_list.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/configure_allow_list.ts deleted file mode 100644 index f073c2d0..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/configure_allow_list.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Configure_allow_listArgs { - add: Array - enabled: boolean -} - -export interface Configure_allow_listAccounts { - state: PublicKey - mint: PublicKey - authority: PublicKey - system_program: PublicKey -} - -export const layout = borsh.struct([ - borsh.vec(borsh.publicKey(), "add"), - borsh.bool("enabled"), -]) - -export function configure_allow_list( - args: Configure_allow_listArgs, - accounts: Configure_allow_listAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - { pubkey: accounts.mint, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.system_program, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([18, 180, 102, 187, 209, 0, 130, 191]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - add: args.add, - enabled: args.enabled, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/deleteChainConfig.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/deleteChainConfig.ts deleted file mode 100644 index 378afbd2..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/deleteChainConfig.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface DeleteChainConfigArgs { - remoteChainSelector: BN - mint: PublicKey -} - -export interface DeleteChainConfigAccounts { - state: PublicKey - chainConfig: PublicKey - authority: PublicKey -} - -export const layout = borsh.struct([ - borsh.u64("remoteChainSelector"), - borsh.publicKey("mint"), -]) - -export function deleteChainConfig( - args: DeleteChainConfigArgs, - accounts: DeleteChainConfigAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.chainConfig, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - ] - const identifier = Buffer.from([241, 159, 142, 210, 64, 173, 77, 179]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - remoteChainSelector: args.remoteChainSelector, - mint: args.mint, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/delete_chain_config.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/delete_chain_config.ts deleted file mode 100644 index 35fd1aa9..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/delete_chain_config.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Delete_chain_configArgs { - remote_chain_selector: BN - mint: PublicKey -} - -export interface Delete_chain_configAccounts { - state: PublicKey - chain_config: PublicKey - authority: PublicKey -} - -export const layout = borsh.struct([ - borsh.u64("remote_chain_selector"), - borsh.publicKey("mint"), -]) - -export function delete_chain_config( - args: Delete_chain_configArgs, - accounts: Delete_chain_configAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.chain_config, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - ] - const identifier = Buffer.from([241, 159, 142, 210, 64, 173, 77, 179]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - remote_chain_selector: args.remote_chain_selector, - mint: args.mint, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/editChainRemoteConfig.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/editChainRemoteConfig.ts deleted file mode 100644 index ef3d806e..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/editChainRemoteConfig.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface EditChainRemoteConfigArgs { - remoteChainSelector: BN - mint: PublicKey - cfg: types.RemoteConfigFields -} - -export interface EditChainRemoteConfigAccounts { - state: PublicKey - chainConfig: PublicKey - authority: PublicKey - systemProgram: PublicKey -} - -export const layout = borsh.struct([ - borsh.u64("remoteChainSelector"), - borsh.publicKey("mint"), - types.RemoteConfig.layout("cfg"), -]) - -export function editChainRemoteConfig( - args: EditChainRemoteConfigArgs, - accounts: EditChainRemoteConfigAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.chainConfig, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.systemProgram, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([149, 112, 186, 72, 116, 217, 159, 175]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - remoteChainSelector: args.remoteChainSelector, - mint: args.mint, - cfg: types.RemoteConfig.toEncodable(args.cfg), - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/edit_chain_remote_config.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/edit_chain_remote_config.ts deleted file mode 100644 index 13c6deca..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/edit_chain_remote_config.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Edit_chain_remote_configArgs { - remote_chain_selector: BN - mint: PublicKey - cfg: types.RemoteConfigFields -} - -export interface Edit_chain_remote_configAccounts { - state: PublicKey - chain_config: PublicKey - authority: PublicKey - system_program: PublicKey -} - -export const layout = borsh.struct([ - borsh.u64("remote_chain_selector"), - borsh.publicKey("mint"), - types.RemoteConfig.layout("cfg"), -]) - -export function edit_chain_remote_config( - args: Edit_chain_remote_configArgs, - accounts: Edit_chain_remote_configAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.chain_config, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.system_program, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([149, 112, 186, 72, 116, 217, 159, 175]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - remote_chain_selector: args.remote_chain_selector, - mint: args.mint, - cfg: types.RemoteConfig.toEncodable(args.cfg), - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/index.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/index.ts deleted file mode 100644 index 80ab9dc9..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/index.ts +++ /dev/null @@ -1,87 +0,0 @@ -export { initGlobalConfig } from "./initGlobalConfig" -export type { - InitGlobalConfigArgs, - InitGlobalConfigAccounts, -} from "./initGlobalConfig" -export { updateSelfServedAllowed } from "./updateSelfServedAllowed" -export type { - UpdateSelfServedAllowedArgs, - UpdateSelfServedAllowedAccounts, -} from "./updateSelfServedAllowed" -export { updateDefaultRouter } from "./updateDefaultRouter" -export type { - UpdateDefaultRouterArgs, - UpdateDefaultRouterAccounts, -} from "./updateDefaultRouter" -export { updateDefaultRmn } from "./updateDefaultRmn" -export type { - UpdateDefaultRmnArgs, - UpdateDefaultRmnAccounts, -} from "./updateDefaultRmn" -export { initialize } from "./initialize" -export type { InitializeAccounts } from "./initialize" -export { transferMintAuthorityToMultisig } from "./transferMintAuthorityToMultisig" -export type { TransferMintAuthorityToMultisigAccounts } from "./transferMintAuthorityToMultisig" -export { typeVersion } from "./typeVersion" -export type { TypeVersionAccounts } from "./typeVersion" -export { transferOwnership } from "./transferOwnership" -export type { - TransferOwnershipArgs, - TransferOwnershipAccounts, -} from "./transferOwnership" -export { acceptOwnership } from "./acceptOwnership" -export type { AcceptOwnershipAccounts } from "./acceptOwnership" -export { setRouter } from "./setRouter" -export type { SetRouterArgs, SetRouterAccounts } from "./setRouter" -export { setRmn } from "./setRmn" -export type { SetRmnArgs, SetRmnAccounts } from "./setRmn" -export { initializeStateVersion } from "./initializeStateVersion" -export type { - InitializeStateVersionArgs, - InitializeStateVersionAccounts, -} from "./initializeStateVersion" -export { initChainRemoteConfig } from "./initChainRemoteConfig" -export type { - InitChainRemoteConfigArgs, - InitChainRemoteConfigAccounts, -} from "./initChainRemoteConfig" -export { editChainRemoteConfig } from "./editChainRemoteConfig" -export type { - EditChainRemoteConfigArgs, - EditChainRemoteConfigAccounts, -} from "./editChainRemoteConfig" -export { appendRemotePoolAddresses } from "./appendRemotePoolAddresses" -export type { - AppendRemotePoolAddressesArgs, - AppendRemotePoolAddressesAccounts, -} from "./appendRemotePoolAddresses" -export { setChainRateLimit } from "./setChainRateLimit" -export type { - SetChainRateLimitArgs, - SetChainRateLimitAccounts, -} from "./setChainRateLimit" -export { deleteChainConfig } from "./deleteChainConfig" -export type { - DeleteChainConfigArgs, - DeleteChainConfigAccounts, -} from "./deleteChainConfig" -export { configureAllowList } from "./configureAllowList" -export type { - ConfigureAllowListArgs, - ConfigureAllowListAccounts, -} from "./configureAllowList" -export { removeFromAllowList } from "./removeFromAllowList" -export type { - RemoveFromAllowListArgs, - RemoveFromAllowListAccounts, -} from "./removeFromAllowList" -export { releaseOrMintTokens } from "./releaseOrMintTokens" -export type { - ReleaseOrMintTokensArgs, - ReleaseOrMintTokensAccounts, -} from "./releaseOrMintTokens" -export { lockOrBurnTokens } from "./lockOrBurnTokens" -export type { - LockOrBurnTokensArgs, - LockOrBurnTokensAccounts, -} from "./lockOrBurnTokens" diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/initChainRemoteConfig.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/initChainRemoteConfig.ts deleted file mode 100644 index 38d05b21..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/initChainRemoteConfig.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface InitChainRemoteConfigArgs { - remoteChainSelector: BN - mint: PublicKey - cfg: types.RemoteConfigFields -} - -export interface InitChainRemoteConfigAccounts { - state: PublicKey - chainConfig: PublicKey - authority: PublicKey - systemProgram: PublicKey -} - -export const layout = borsh.struct([ - borsh.u64("remoteChainSelector"), - borsh.publicKey("mint"), - types.RemoteConfig.layout("cfg"), -]) - -export function initChainRemoteConfig( - args: InitChainRemoteConfigArgs, - accounts: InitChainRemoteConfigAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.chainConfig, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.systemProgram, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([21, 150, 133, 36, 2, 116, 199, 129]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - remoteChainSelector: args.remoteChainSelector, - mint: args.mint, - cfg: types.RemoteConfig.toEncodable(args.cfg), - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/initGlobalConfig.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/initGlobalConfig.ts deleted file mode 100644 index f4834dac..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/initGlobalConfig.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface InitGlobalConfigArgs { - routerAddress: PublicKey - rmnAddress: PublicKey -} - -export interface InitGlobalConfigAccounts { - config: PublicKey - authority: PublicKey - systemProgram: PublicKey - program: PublicKey - programData: PublicKey -} - -export const layout = borsh.struct([ - borsh.publicKey("routerAddress"), - borsh.publicKey("rmnAddress"), -]) - -export function initGlobalConfig( - args: InitGlobalConfigArgs, - accounts: InitGlobalConfigAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.config, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.systemProgram, isSigner: false, isWritable: false }, - { pubkey: accounts.program, isSigner: false, isWritable: false }, - { pubkey: accounts.programData, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([140, 136, 214, 48, 87, 0, 120, 255]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - routerAddress: args.routerAddress, - rmnAddress: args.rmnAddress, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/init_chain_remote_config.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/init_chain_remote_config.ts deleted file mode 100644 index ee813a28..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/init_chain_remote_config.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Init_chain_remote_configArgs { - remote_chain_selector: BN - mint: PublicKey - cfg: types.RemoteConfigFields -} - -export interface Init_chain_remote_configAccounts { - state: PublicKey - chain_config: PublicKey - authority: PublicKey - system_program: PublicKey -} - -export const layout = borsh.struct([ - borsh.u64("remote_chain_selector"), - borsh.publicKey("mint"), - types.RemoteConfig.layout("cfg"), -]) - -export function init_chain_remote_config( - args: Init_chain_remote_configArgs, - accounts: Init_chain_remote_configAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.chain_config, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.system_program, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([21, 150, 133, 36, 2, 116, 199, 129]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - remote_chain_selector: args.remote_chain_selector, - mint: args.mint, - cfg: types.RemoteConfig.toEncodable(args.cfg), - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/init_global_config.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/init_global_config.ts deleted file mode 100644 index 4e9c00a4..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/init_global_config.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Init_global_configAccounts { - config: PublicKey - authority: PublicKey - system_program: PublicKey - program: PublicKey - program_data: PublicKey -} - -export function init_global_config( - accounts: Init_global_configAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.config, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.system_program, isSigner: false, isWritable: false }, - { pubkey: accounts.program, isSigner: false, isWritable: false }, - { pubkey: accounts.program_data, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([140, 136, 214, 48, 87, 0, 120, 255]) - const data = identifier - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/initialize.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/initialize.ts deleted file mode 100644 index afd5b825..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/initialize.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface InitializeAccounts { - state: PublicKey - mint: PublicKey - authority: PublicKey - systemProgram: PublicKey - program: PublicKey - programData: PublicKey - config: PublicKey -} - -export function initialize( - accounts: InitializeAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - { pubkey: accounts.mint, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.systemProgram, isSigner: false, isWritable: false }, - { pubkey: accounts.program, isSigner: false, isWritable: false }, - { pubkey: accounts.programData, isSigner: false, isWritable: false }, - { pubkey: accounts.config, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([175, 175, 109, 31, 13, 152, 155, 237]) - const data = identifier - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/initializeStateVersion.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/initializeStateVersion.ts deleted file mode 100644 index a602dd6d..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/initializeStateVersion.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface InitializeStateVersionArgs { - mint: PublicKey -} - -export interface InitializeStateVersionAccounts { - state: PublicKey -} - -export const layout = borsh.struct([borsh.publicKey("mint")]) - -export function initializeStateVersion( - args: InitializeStateVersionArgs, - accounts: InitializeStateVersionAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - ] - const identifier = Buffer.from([54, 186, 181, 26, 2, 198, 200, 158]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - mint: args.mint, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/initialize_state_version.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/initialize_state_version.ts deleted file mode 100644 index e95a5428..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/initialize_state_version.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Initialize_state_versionArgs { - _mint: PublicKey -} - -export interface Initialize_state_versionAccounts { - state: PublicKey -} - -export const layout = borsh.struct([borsh.publicKey("_mint")]) - -export function initialize_state_version( - args: Initialize_state_versionArgs, - accounts: Initialize_state_versionAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - ] - const identifier = Buffer.from([54, 186, 181, 26, 2, 198, 200, 158]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - _mint: args._mint, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/lockOrBurnTokens.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/lockOrBurnTokens.ts deleted file mode 100644 index 544c72bc..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/lockOrBurnTokens.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface LockOrBurnTokensArgs { - lockOrBurn: types.LockOrBurnInV1Fields -} - -export interface LockOrBurnTokensAccounts { - authority: PublicKey - state: PublicKey - tokenProgram: PublicKey - mint: PublicKey - poolSigner: PublicKey - poolTokenAccount: PublicKey - rmnRemote: PublicKey - rmnRemoteCurses: PublicKey - rmnRemoteConfig: PublicKey - chainConfig: PublicKey -} - -export const layout = borsh.struct([types.LockOrBurnInV1.layout("lockOrBurn")]) - -export function lockOrBurnTokens( - args: LockOrBurnTokensArgs, - accounts: LockOrBurnTokensAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false }, - { pubkey: accounts.mint, isSigner: false, isWritable: true }, - { pubkey: accounts.poolSigner, isSigner: false, isWritable: false }, - { pubkey: accounts.poolTokenAccount, isSigner: false, isWritable: true }, - { pubkey: accounts.rmnRemote, isSigner: false, isWritable: false }, - { pubkey: accounts.rmnRemoteCurses, isSigner: false, isWritable: false }, - { pubkey: accounts.rmnRemoteConfig, isSigner: false, isWritable: false }, - { pubkey: accounts.chainConfig, isSigner: false, isWritable: true }, - ] - const identifier = Buffer.from([114, 161, 94, 29, 147, 25, 232, 191]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - lockOrBurn: types.LockOrBurnInV1.toEncodable(args.lockOrBurn), - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/lock_or_burn_tokens.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/lock_or_burn_tokens.ts deleted file mode 100644 index da4c8a30..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/lock_or_burn_tokens.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Lock_or_burn_tokensArgs { - lock_or_burn: types.LockOrBurnInV1Fields -} - -export interface Lock_or_burn_tokensAccounts { - authority: PublicKey - state: PublicKey - token_program: PublicKey - mint: PublicKey - pool_signer: PublicKey - pool_token_account: PublicKey - rmn_remote: PublicKey - rmn_remote_curses: PublicKey - rmn_remote_config: PublicKey - chain_config: PublicKey -} - -export const layout = borsh.struct([ - types.LockOrBurnInV1.layout("lock_or_burn"), -]) - -export function lock_or_burn_tokens( - args: Lock_or_burn_tokensArgs, - accounts: Lock_or_burn_tokensAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.token_program, isSigner: false, isWritable: false }, - { pubkey: accounts.mint, isSigner: false, isWritable: true }, - { pubkey: accounts.pool_signer, isSigner: false, isWritable: false }, - { pubkey: accounts.pool_token_account, isSigner: false, isWritable: true }, - { pubkey: accounts.rmn_remote, isSigner: false, isWritable: false }, - { pubkey: accounts.rmn_remote_curses, isSigner: false, isWritable: false }, - { pubkey: accounts.rmn_remote_config, isSigner: false, isWritable: false }, - { pubkey: accounts.chain_config, isSigner: false, isWritable: true }, - ] - const identifier = Buffer.from([114, 161, 94, 29, 147, 25, 232, 191]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - lock_or_burn: types.LockOrBurnInV1.toEncodable(args.lock_or_burn), - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/releaseOrMintTokens.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/releaseOrMintTokens.ts deleted file mode 100644 index 3c5950fe..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/releaseOrMintTokens.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface ReleaseOrMintTokensArgs { - releaseOrMint: types.ReleaseOrMintInV1Fields -} - -export interface ReleaseOrMintTokensAccounts { - authority: PublicKey - /** - * CHECK offramp program: exists only to derive the allowed offramp PDA - * and the authority PDA. - */ - offrampProgram: PublicKey - /** - * CHECK PDA of the router program verifying the signer is an allowed offramp. - * If PDA does not exist, the router doesn't allow this offramp - */ - allowedOfframp: PublicKey - state: PublicKey - tokenProgram: PublicKey - mint: PublicKey - poolSigner: PublicKey - poolTokenAccount: PublicKey - chainConfig: PublicKey - rmnRemote: PublicKey - rmnRemoteCurses: PublicKey - rmnRemoteConfig: PublicKey - receiverTokenAccount: PublicKey -} - -export const layout = borsh.struct([ - types.ReleaseOrMintInV1.layout("releaseOrMint"), -]) - -export function releaseOrMintTokens( - args: ReleaseOrMintTokensArgs, - accounts: ReleaseOrMintTokensAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - { pubkey: accounts.offrampProgram, isSigner: false, isWritable: false }, - { pubkey: accounts.allowedOfframp, isSigner: false, isWritable: false }, - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false }, - { pubkey: accounts.mint, isSigner: false, isWritable: true }, - { pubkey: accounts.poolSigner, isSigner: false, isWritable: false }, - { pubkey: accounts.poolTokenAccount, isSigner: false, isWritable: true }, - { pubkey: accounts.chainConfig, isSigner: false, isWritable: true }, - { pubkey: accounts.rmnRemote, isSigner: false, isWritable: false }, - { pubkey: accounts.rmnRemoteCurses, isSigner: false, isWritable: false }, - { pubkey: accounts.rmnRemoteConfig, isSigner: false, isWritable: false }, - { - pubkey: accounts.receiverTokenAccount, - isSigner: false, - isWritable: true, - }, - ] - const identifier = Buffer.from([92, 100, 150, 198, 252, 63, 164, 228]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - releaseOrMint: types.ReleaseOrMintInV1.toEncodable(args.releaseOrMint), - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/release_or_mint_tokens.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/release_or_mint_tokens.ts deleted file mode 100644 index 0a2944f3..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/release_or_mint_tokens.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Release_or_mint_tokensArgs { - release_or_mint: types.ReleaseOrMintInV1Fields -} - -export interface Release_or_mint_tokensAccounts { - authority: PublicKey - /** - * CHECK offramp program: exists only to derive the allowed offramp PDA - * and the authority PDA. - */ - offramp_program: PublicKey - /** - * CHECK PDA of the router program verifying the signer is an allowed offramp. - * If PDA does not exist, the router doesn't allow this offramp - */ - allowed_offramp: PublicKey - state: PublicKey - token_program: PublicKey - mint: PublicKey - pool_signer: PublicKey - pool_token_account: PublicKey - chain_config: PublicKey - rmn_remote: PublicKey - rmn_remote_curses: PublicKey - rmn_remote_config: PublicKey - receiver_token_account: PublicKey -} - -export const layout = borsh.struct([ - types.ReleaseOrMintInV1.layout("release_or_mint"), -]) - -export function release_or_mint_tokens( - args: Release_or_mint_tokensArgs, - accounts: Release_or_mint_tokensAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - { pubkey: accounts.offramp_program, isSigner: false, isWritable: false }, - { pubkey: accounts.allowed_offramp, isSigner: false, isWritable: false }, - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.token_program, isSigner: false, isWritable: false }, - { pubkey: accounts.mint, isSigner: false, isWritable: true }, - { pubkey: accounts.pool_signer, isSigner: false, isWritable: false }, - { pubkey: accounts.pool_token_account, isSigner: false, isWritable: true }, - { pubkey: accounts.chain_config, isSigner: false, isWritable: true }, - { pubkey: accounts.rmn_remote, isSigner: false, isWritable: false }, - { pubkey: accounts.rmn_remote_curses, isSigner: false, isWritable: false }, - { pubkey: accounts.rmn_remote_config, isSigner: false, isWritable: false }, - { - pubkey: accounts.receiver_token_account, - isSigner: false, - isWritable: true, - }, - ] - const identifier = Buffer.from([92, 100, 150, 198, 252, 63, 164, 228]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - release_or_mint: types.ReleaseOrMintInV1.toEncodable( - args.release_or_mint - ), - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/removeFromAllowList.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/removeFromAllowList.ts deleted file mode 100644 index 82cdf4e7..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/removeFromAllowList.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface RemoveFromAllowListArgs { - remove: Array -} - -export interface RemoveFromAllowListAccounts { - state: PublicKey - mint: PublicKey - authority: PublicKey - systemProgram: PublicKey -} - -export const layout = borsh.struct([borsh.vec(borsh.publicKey(), "remove")]) - -export function removeFromAllowList( - args: RemoveFromAllowListArgs, - accounts: RemoveFromAllowListAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - { pubkey: accounts.mint, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.systemProgram, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([44, 46, 123, 213, 40, 11, 107, 18]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - remove: args.remove, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/remove_from_allow_list.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/remove_from_allow_list.ts deleted file mode 100644 index 13fd66c6..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/remove_from_allow_list.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Remove_from_allow_listArgs { - remove: Array -} - -export interface Remove_from_allow_listAccounts { - state: PublicKey - mint: PublicKey - authority: PublicKey - system_program: PublicKey -} - -export const layout = borsh.struct([borsh.vec(borsh.publicKey(), "remove")]) - -export function remove_from_allow_list( - args: Remove_from_allow_listArgs, - accounts: Remove_from_allow_listAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - { pubkey: accounts.mint, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.system_program, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([44, 46, 123, 213, 40, 11, 107, 18]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - remove: args.remove, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/setChainRateLimit.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/setChainRateLimit.ts deleted file mode 100644 index 3a319263..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/setChainRateLimit.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface SetChainRateLimitArgs { - remoteChainSelector: BN - mint: PublicKey - inbound: types.RateLimitConfigFields - outbound: types.RateLimitConfigFields -} - -export interface SetChainRateLimitAccounts { - state: PublicKey - chainConfig: PublicKey - authority: PublicKey -} - -export const layout = borsh.struct([ - borsh.u64("remoteChainSelector"), - borsh.publicKey("mint"), - types.RateLimitConfig.layout("inbound"), - types.RateLimitConfig.layout("outbound"), -]) - -export function setChainRateLimit( - args: SetChainRateLimitArgs, - accounts: SetChainRateLimitAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.chainConfig, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - ] - const identifier = Buffer.from([188, 188, 161, 37, 100, 249, 123, 170]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - remoteChainSelector: args.remoteChainSelector, - mint: args.mint, - inbound: types.RateLimitConfig.toEncodable(args.inbound), - outbound: types.RateLimitConfig.toEncodable(args.outbound), - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/setRmn.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/setRmn.ts deleted file mode 100644 index 851d79e0..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/setRmn.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface SetRmnArgs { - rmnAddress: PublicKey -} - -export interface SetRmnAccounts { - state: PublicKey - mint: PublicKey - authority: PublicKey - program: PublicKey - programData: PublicKey -} - -export const layout = borsh.struct([borsh.publicKey("rmnAddress")]) - -export function setRmn( - args: SetRmnArgs, - accounts: SetRmnAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.mint, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.program, isSigner: false, isWritable: false }, - { pubkey: accounts.programData, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([252, 89, 60, 179, 198, 54, 169, 120]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - rmnAddress: args.rmnAddress, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/setRouter.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/setRouter.ts deleted file mode 100644 index b79b10df..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/setRouter.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface SetRouterArgs { - newRouter: PublicKey -} - -export interface SetRouterAccounts { - state: PublicKey - mint: PublicKey - authority: PublicKey - program: PublicKey - programData: PublicKey -} - -export const layout = borsh.struct([borsh.publicKey("newRouter")]) - -export function setRouter( - args: SetRouterArgs, - accounts: SetRouterAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.mint, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - { pubkey: accounts.program, isSigner: false, isWritable: false }, - { pubkey: accounts.programData, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([236, 248, 107, 200, 151, 160, 44, 250]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - newRouter: args.newRouter, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/set_chain_rate_limit.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/set_chain_rate_limit.ts deleted file mode 100644 index 8644fe6c..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/set_chain_rate_limit.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Set_chain_rate_limitArgs { - remote_chain_selector: BN - mint: PublicKey - inbound: types.RateLimitConfigFields - outbound: types.RateLimitConfigFields -} - -export interface Set_chain_rate_limitAccounts { - state: PublicKey - chain_config: PublicKey - authority: PublicKey -} - -export const layout = borsh.struct([ - borsh.u64("remote_chain_selector"), - borsh.publicKey("mint"), - types.RateLimitConfig.layout("inbound"), - types.RateLimitConfig.layout("outbound"), -]) - -export function set_chain_rate_limit( - args: Set_chain_rate_limitArgs, - accounts: Set_chain_rate_limitAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: false }, - { pubkey: accounts.chain_config, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: true }, - ] - const identifier = Buffer.from([188, 188, 161, 37, 100, 249, 123, 170]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - remote_chain_selector: args.remote_chain_selector, - mint: args.mint, - inbound: types.RateLimitConfig.toEncodable(args.inbound), - outbound: types.RateLimitConfig.toEncodable(args.outbound), - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/set_router.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/set_router.ts deleted file mode 100644 index 49bf94ce..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/set_router.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Set_routerArgs { - new_router: PublicKey -} - -export interface Set_routerAccounts { - state: PublicKey - mint: PublicKey - authority: PublicKey -} - -export const layout = borsh.struct([borsh.publicKey("new_router")]) - -export function set_router( - args: Set_routerArgs, - accounts: Set_routerAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - { pubkey: accounts.mint, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - ] - const identifier = Buffer.from([236, 248, 107, 200, 151, 160, 44, 250]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - new_router: args.new_router, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/transferMintAuthorityToMultisig.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/transferMintAuthorityToMultisig.ts deleted file mode 100644 index 6d5d968b..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/transferMintAuthorityToMultisig.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface TransferMintAuthorityToMultisigAccounts { - state: PublicKey - mint: PublicKey - tokenProgram: PublicKey - poolSigner: PublicKey - authority: PublicKey - newMultisigMintAuthority: PublicKey - program: PublicKey - programData: PublicKey -} - -export function transferMintAuthorityToMultisig( - accounts: TransferMintAuthorityToMultisigAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - { pubkey: accounts.mint, isSigner: false, isWritable: true }, - { pubkey: accounts.tokenProgram, isSigner: false, isWritable: false }, - { pubkey: accounts.poolSigner, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - { - pubkey: accounts.newMultisigMintAuthority, - isSigner: false, - isWritable: false, - }, - { pubkey: accounts.program, isSigner: false, isWritable: false }, - { pubkey: accounts.programData, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([229, 13, 219, 109, 252, 176, 138, 118]) - const data = identifier - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/transferOwnership.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/transferOwnership.ts deleted file mode 100644 index 78ca5627..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/transferOwnership.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface TransferOwnershipArgs { - proposedOwner: PublicKey -} - -export interface TransferOwnershipAccounts { - state: PublicKey - mint: PublicKey - authority: PublicKey -} - -export const layout = borsh.struct([borsh.publicKey("proposedOwner")]) - -export function transferOwnership( - args: TransferOwnershipArgs, - accounts: TransferOwnershipAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - { pubkey: accounts.mint, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - ] - const identifier = Buffer.from([65, 177, 215, 73, 53, 45, 99, 47]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - proposedOwner: args.proposedOwner, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/transfer_mint_authority_to_multisig.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/transfer_mint_authority_to_multisig.ts deleted file mode 100644 index 6b8dc20f..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/transfer_mint_authority_to_multisig.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Transfer_mint_authority_to_multisigAccounts { - state: PublicKey - mint: PublicKey - token_program: PublicKey - pool_signer: PublicKey - authority: PublicKey - new_multisig_mint_authority: PublicKey - program: PublicKey - program_data: PublicKey -} - -export function transfer_mint_authority_to_multisig( - accounts: Transfer_mint_authority_to_multisigAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - { pubkey: accounts.mint, isSigner: false, isWritable: true }, - { pubkey: accounts.token_program, isSigner: false, isWritable: false }, - { pubkey: accounts.pool_signer, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - { - pubkey: accounts.new_multisig_mint_authority, - isSigner: false, - isWritable: false, - }, - { pubkey: accounts.program, isSigner: false, isWritable: false }, - { pubkey: accounts.program_data, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([229, 13, 219, 109, 252, 176, 138, 118]) - const data = identifier - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/transfer_ownership.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/transfer_ownership.ts deleted file mode 100644 index 220e9dc3..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/transfer_ownership.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Transfer_ownershipArgs { - proposed_owner: PublicKey -} - -export interface Transfer_ownershipAccounts { - state: PublicKey - mint: PublicKey - authority: PublicKey -} - -export const layout = borsh.struct([borsh.publicKey("proposed_owner")]) - -export function transfer_ownership( - args: Transfer_ownershipArgs, - accounts: Transfer_ownershipAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.state, isSigner: false, isWritable: true }, - { pubkey: accounts.mint, isSigner: false, isWritable: false }, - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - ] - const identifier = Buffer.from([65, 177, 215, 73, 53, 45, 99, 47]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - proposed_owner: args.proposed_owner, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/typeVersion.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/typeVersion.ts deleted file mode 100644 index 5202bb13..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/typeVersion.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface TypeVersionAccounts { - clock: PublicKey -} - -/** - * Returns the program type (name) and version. - * Used by offchain code to easily determine which program & version is being interacted with. - * - * # Arguments - * * `ctx` - The context - */ -export function typeVersion( - accounts: TypeVersionAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.clock, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([129, 251, 8, 243, 122, 229, 252, 164]) - const data = identifier - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/type_version.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/type_version.ts deleted file mode 100644 index bf7a1c43..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/type_version.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Type_versionAccounts { - clock: PublicKey -} - -/** - * Returns the program type (name) and version. - * Used by offchain code to easily determine which program & version is being interacted with. - * - * # Arguments - * * `ctx` - The context - */ -export function type_version( - accounts: Type_versionAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.clock, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([129, 251, 8, 243, 122, 229, 252, 164]) - const data = identifier - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/updateDefaultRmn.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/updateDefaultRmn.ts deleted file mode 100644 index 838e9a03..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/updateDefaultRmn.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface UpdateDefaultRmnArgs { - rmnAddress: PublicKey -} - -export interface UpdateDefaultRmnAccounts { - config: PublicKey - authority: PublicKey - program: PublicKey - programData: PublicKey -} - -export const layout = borsh.struct([borsh.publicKey("rmnAddress")]) - -export function updateDefaultRmn( - args: UpdateDefaultRmnArgs, - accounts: UpdateDefaultRmnAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.config, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - { pubkey: accounts.program, isSigner: false, isWritable: false }, - { pubkey: accounts.programData, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([204, 186, 36, 125, 180, 133, 227, 162]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - rmnAddress: args.rmnAddress, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/updateDefaultRouter.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/updateDefaultRouter.ts deleted file mode 100644 index 1648ab1f..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/updateDefaultRouter.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface UpdateDefaultRouterArgs { - routerAddress: PublicKey -} - -export interface UpdateDefaultRouterAccounts { - config: PublicKey - authority: PublicKey - program: PublicKey - programData: PublicKey -} - -export const layout = borsh.struct([borsh.publicKey("routerAddress")]) - -export function updateDefaultRouter( - args: UpdateDefaultRouterArgs, - accounts: UpdateDefaultRouterAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.config, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - { pubkey: accounts.program, isSigner: false, isWritable: false }, - { pubkey: accounts.programData, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([29, 86, 6, 222, 73, 220, 6, 186]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - routerAddress: args.routerAddress, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/updateSelfServedAllowed.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/updateSelfServedAllowed.ts deleted file mode 100644 index 67bb54ed..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/updateSelfServedAllowed.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface UpdateSelfServedAllowedArgs { - selfServedAllowed: boolean -} - -export interface UpdateSelfServedAllowedAccounts { - config: PublicKey - authority: PublicKey - program: PublicKey - programData: PublicKey -} - -export const layout = borsh.struct([borsh.bool("selfServedAllowed")]) - -export function updateSelfServedAllowed( - args: UpdateSelfServedAllowedArgs, - accounts: UpdateSelfServedAllowedAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.config, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - { pubkey: accounts.program, isSigner: false, isWritable: false }, - { pubkey: accounts.programData, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([210, 165, 57, 132, 64, 203, 100, 73]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - selfServedAllowed: args.selfServedAllowed, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/instructions/update_global_config.ts b/ccip-lib/svm/burnmint-pool-bindings/instructions/update_global_config.ts deleted file mode 100644 index 637a4210..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/instructions/update_global_config.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { TransactionInstruction, PublicKey, AccountMeta } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import { PROGRAM_ID } from "../programId" - -export interface Update_global_configArgs { - self_served_allowed: boolean -} - -export interface Update_global_configAccounts { - config: PublicKey - authority: PublicKey - system_program: PublicKey - program: PublicKey - program_data: PublicKey -} - -export const layout = borsh.struct([borsh.bool("self_served_allowed")]) - -export function update_global_config( - args: Update_global_configArgs, - accounts: Update_global_configAccounts, - programId: PublicKey = PROGRAM_ID -) { - const keys: Array = [ - { pubkey: accounts.config, isSigner: false, isWritable: true }, - { pubkey: accounts.authority, isSigner: true, isWritable: false }, - { pubkey: accounts.system_program, isSigner: false, isWritable: false }, - { pubkey: accounts.program, isSigner: false, isWritable: false }, - { pubkey: accounts.program_data, isSigner: false, isWritable: false }, - ] - const identifier = Buffer.from([164, 84, 130, 189, 111, 58, 250, 200]) - const buffer = Buffer.alloc(1000) - const len = layout.encode( - { - self_served_allowed: args.self_served_allowed, - }, - buffer - ) - const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len) - const ix = new TransactionInstruction({ keys, programId, data }) - return ix -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/programId.ts b/ccip-lib/svm/burnmint-pool-bindings/programId.ts deleted file mode 100644 index 4f74486a..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/programId.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { PublicKey } from "@solana/web3.js" - -// Program ID defined in the provided IDL. Do not edit, it will get overwritten. -export const PROGRAM_ID_IDL = new PublicKey( - "3BrkN1XcyeafuMZxomLZBUVdasEtpdMmpWfsEQmzN7vo" -) - -// This constant will not get overwritten on subsequent code generations and it's safe to modify it's value. -export const PROGRAM_ID: PublicKey = PROGRAM_ID_IDL diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/BaseChain.ts b/ccip-lib/svm/burnmint-pool-bindings/types/BaseChain.ts deleted file mode 100644 index bc5bfa63..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/BaseChain.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { PublicKey } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" - -export interface BaseChainFields { - remote: types.RemoteConfigFields - inboundRateLimit: types.RateLimitTokenBucketFields - outboundRateLimit: types.RateLimitTokenBucketFields -} - -export interface BaseChainJSON { - remote: types.RemoteConfigJSON - inboundRateLimit: types.RateLimitTokenBucketJSON - outboundRateLimit: types.RateLimitTokenBucketJSON -} - -export class BaseChain { - readonly remote: types.RemoteConfig - readonly inboundRateLimit: types.RateLimitTokenBucket - readonly outboundRateLimit: types.RateLimitTokenBucket - - constructor(fields: BaseChainFields) { - this.remote = new types.RemoteConfig({ ...fields.remote }) - this.inboundRateLimit = new types.RateLimitTokenBucket({ - ...fields.inboundRateLimit, - }) - this.outboundRateLimit = new types.RateLimitTokenBucket({ - ...fields.outboundRateLimit, - }) - } - - static layout(property?: string) { - return borsh.struct( - [ - types.RemoteConfig.layout("remote"), - types.RateLimitTokenBucket.layout("inboundRateLimit"), - types.RateLimitTokenBucket.layout("outboundRateLimit"), - ], - property - ) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static fromDecoded(obj: any) { - return new BaseChain({ - remote: types.RemoteConfig.fromDecoded(obj.remote), - inboundRateLimit: types.RateLimitTokenBucket.fromDecoded( - obj.inboundRateLimit - ), - outboundRateLimit: types.RateLimitTokenBucket.fromDecoded( - obj.outboundRateLimit - ), - }) - } - - static toEncodable(fields: BaseChainFields) { - return { - remote: types.RemoteConfig.toEncodable(fields.remote), - inboundRateLimit: types.RateLimitTokenBucket.toEncodable( - fields.inboundRateLimit - ), - outboundRateLimit: types.RateLimitTokenBucket.toEncodable( - fields.outboundRateLimit - ), - } - } - - toJSON(): BaseChainJSON { - return { - remote: this.remote.toJSON(), - inboundRateLimit: this.inboundRateLimit.toJSON(), - outboundRateLimit: this.outboundRateLimit.toJSON(), - } - } - - static fromJSON(obj: BaseChainJSON): BaseChain { - return new BaseChain({ - remote: types.RemoteConfig.fromJSON(obj.remote), - inboundRateLimit: types.RateLimitTokenBucket.fromJSON( - obj.inboundRateLimit - ), - outboundRateLimit: types.RateLimitTokenBucket.fromJSON( - obj.outboundRateLimit - ), - }) - } - - toEncodable() { - return BaseChain.toEncodable(this) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/BaseConfig.ts b/ccip-lib/svm/burnmint-pool-bindings/types/BaseConfig.ts deleted file mode 100644 index 3aa091e9..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/BaseConfig.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { PublicKey } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" - -export interface BaseConfigFields { - tokenProgram: PublicKey - mint: PublicKey - decimals: number - poolSigner: PublicKey - poolTokenAccount: PublicKey - owner: PublicKey - proposedOwner: PublicKey - rateLimitAdmin: PublicKey - routerOnrampAuthority: PublicKey - router: PublicKey - rebalancer: PublicKey - canAcceptLiquidity: boolean - listEnabled: boolean - allowList: Array - rmnRemote: PublicKey -} - -export interface BaseConfigJSON { - tokenProgram: string - mint: string - decimals: number - poolSigner: string - poolTokenAccount: string - owner: string - proposedOwner: string - rateLimitAdmin: string - routerOnrampAuthority: string - router: string - rebalancer: string - canAcceptLiquidity: boolean - listEnabled: boolean - allowList: Array - rmnRemote: string -} - -export class BaseConfig { - readonly tokenProgram: PublicKey - readonly mint: PublicKey - readonly decimals: number - readonly poolSigner: PublicKey - readonly poolTokenAccount: PublicKey - readonly owner: PublicKey - readonly proposedOwner: PublicKey - readonly rateLimitAdmin: PublicKey - readonly routerOnrampAuthority: PublicKey - readonly router: PublicKey - readonly rebalancer: PublicKey - readonly canAcceptLiquidity: boolean - readonly listEnabled: boolean - readonly allowList: Array - readonly rmnRemote: PublicKey - - constructor(fields: BaseConfigFields) { - this.tokenProgram = fields.tokenProgram - this.mint = fields.mint - this.decimals = fields.decimals - this.poolSigner = fields.poolSigner - this.poolTokenAccount = fields.poolTokenAccount - this.owner = fields.owner - this.proposedOwner = fields.proposedOwner - this.rateLimitAdmin = fields.rateLimitAdmin - this.routerOnrampAuthority = fields.routerOnrampAuthority - this.router = fields.router - this.rebalancer = fields.rebalancer - this.canAcceptLiquidity = fields.canAcceptLiquidity - this.listEnabled = fields.listEnabled - this.allowList = fields.allowList - this.rmnRemote = fields.rmnRemote - } - - static layout(property?: string) { - return borsh.struct( - [ - borsh.publicKey("tokenProgram"), - borsh.publicKey("mint"), - borsh.u8("decimals"), - borsh.publicKey("poolSigner"), - borsh.publicKey("poolTokenAccount"), - borsh.publicKey("owner"), - borsh.publicKey("proposedOwner"), - borsh.publicKey("rateLimitAdmin"), - borsh.publicKey("routerOnrampAuthority"), - borsh.publicKey("router"), - borsh.publicKey("rebalancer"), - borsh.bool("canAcceptLiquidity"), - borsh.bool("listEnabled"), - borsh.vec(borsh.publicKey(), "allowList"), - borsh.publicKey("rmnRemote"), - ], - property - ) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static fromDecoded(obj: any) { - return new BaseConfig({ - tokenProgram: obj.tokenProgram, - mint: obj.mint, - decimals: obj.decimals, - poolSigner: obj.poolSigner, - poolTokenAccount: obj.poolTokenAccount, - owner: obj.owner, - proposedOwner: obj.proposedOwner, - rateLimitAdmin: obj.rateLimitAdmin, - routerOnrampAuthority: obj.routerOnrampAuthority, - router: obj.router, - rebalancer: obj.rebalancer, - canAcceptLiquidity: obj.canAcceptLiquidity, - listEnabled: obj.listEnabled, - allowList: obj.allowList, - rmnRemote: obj.rmnRemote, - }) - } - - static toEncodable(fields: BaseConfigFields) { - return { - tokenProgram: fields.tokenProgram, - mint: fields.mint, - decimals: fields.decimals, - poolSigner: fields.poolSigner, - poolTokenAccount: fields.poolTokenAccount, - owner: fields.owner, - proposedOwner: fields.proposedOwner, - rateLimitAdmin: fields.rateLimitAdmin, - routerOnrampAuthority: fields.routerOnrampAuthority, - router: fields.router, - rebalancer: fields.rebalancer, - canAcceptLiquidity: fields.canAcceptLiquidity, - listEnabled: fields.listEnabled, - allowList: fields.allowList, - rmnRemote: fields.rmnRemote, - } - } - - toJSON(): BaseConfigJSON { - return { - tokenProgram: this.tokenProgram.toString(), - mint: this.mint.toString(), - decimals: this.decimals, - poolSigner: this.poolSigner.toString(), - poolTokenAccount: this.poolTokenAccount.toString(), - owner: this.owner.toString(), - proposedOwner: this.proposedOwner.toString(), - rateLimitAdmin: this.rateLimitAdmin.toString(), - routerOnrampAuthority: this.routerOnrampAuthority.toString(), - router: this.router.toString(), - rebalancer: this.rebalancer.toString(), - canAcceptLiquidity: this.canAcceptLiquidity, - listEnabled: this.listEnabled, - allowList: this.allowList.map((item) => item.toString()), - rmnRemote: this.rmnRemote.toString(), - } - } - - static fromJSON(obj: BaseConfigJSON): BaseConfig { - return new BaseConfig({ - tokenProgram: new PublicKey(obj.tokenProgram), - mint: new PublicKey(obj.mint), - decimals: obj.decimals, - poolSigner: new PublicKey(obj.poolSigner), - poolTokenAccount: new PublicKey(obj.poolTokenAccount), - owner: new PublicKey(obj.owner), - proposedOwner: new PublicKey(obj.proposedOwner), - rateLimitAdmin: new PublicKey(obj.rateLimitAdmin), - routerOnrampAuthority: new PublicKey(obj.routerOnrampAuthority), - router: new PublicKey(obj.router), - rebalancer: new PublicKey(obj.rebalancer), - canAcceptLiquidity: obj.canAcceptLiquidity, - listEnabled: obj.listEnabled, - allowList: obj.allowList.map((item) => new PublicKey(item)), - rmnRemote: new PublicKey(obj.rmnRemote), - }) - } - - toEncodable() { - return BaseConfig.toEncodable(this) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/ChainConfig.ts b/ccip-lib/svm/burnmint-pool-bindings/types/ChainConfig.ts deleted file mode 100644 index a868ea54..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/ChainConfig.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { PublicKey } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" - -export interface ChainConfigFields { - base: types.BaseChainFields -} - -export interface ChainConfigJSON { - base: types.BaseChainJSON -} - -export class ChainConfig { - readonly base: types.BaseChain - - constructor(fields: ChainConfigFields) { - this.base = new types.BaseChain({ ...fields.base }) - } - - static layout(property?: string) { - return borsh.struct([types.BaseChain.layout("base")], property) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static fromDecoded(obj: any) { - return new ChainConfig({ - base: types.BaseChain.fromDecoded(obj.base), - }) - } - - static toEncodable(fields: ChainConfigFields) { - return { - base: types.BaseChain.toEncodable(fields.base), - } - } - - toJSON(): ChainConfigJSON { - return { - base: this.base.toJSON(), - } - } - - static fromJSON(obj: ChainConfigJSON): ChainConfig { - return new ChainConfig({ - base: types.BaseChain.fromJSON(obj.base), - }) - } - - toEncodable() { - return ChainConfig.toEncodable(this) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/LockOrBurnInV1.ts b/ccip-lib/svm/burnmint-pool-bindings/types/LockOrBurnInV1.ts deleted file mode 100644 index 9e2d3982..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/LockOrBurnInV1.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { PublicKey } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" - -export interface LockOrBurnInV1Fields { - receiver: Uint8Array - remoteChainSelector: BN - originalSender: PublicKey - amount: BN - localToken: PublicKey -} - -export interface LockOrBurnInV1JSON { - receiver: Array - remoteChainSelector: string - originalSender: string - amount: string - localToken: string -} - -export class LockOrBurnInV1 { - readonly receiver: Uint8Array - readonly remoteChainSelector: BN - readonly originalSender: PublicKey - readonly amount: BN - readonly localToken: PublicKey - - constructor(fields: LockOrBurnInV1Fields) { - this.receiver = fields.receiver - this.remoteChainSelector = fields.remoteChainSelector - this.originalSender = fields.originalSender - this.amount = fields.amount - this.localToken = fields.localToken - } - - static layout(property?: string) { - return borsh.struct( - [ - borsh.vecU8("receiver"), - borsh.u64("remoteChainSelector"), - borsh.publicKey("originalSender"), - borsh.u64("amount"), - borsh.publicKey("localToken"), - ], - property - ) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static fromDecoded(obj: any) { - return new LockOrBurnInV1({ - receiver: new Uint8Array( - obj.receiver.buffer, - obj.receiver.byteOffset, - obj.receiver.length - ), - remoteChainSelector: obj.remoteChainSelector, - originalSender: obj.originalSender, - amount: obj.amount, - localToken: obj.localToken, - }) - } - - static toEncodable(fields: LockOrBurnInV1Fields) { - return { - receiver: Buffer.from( - fields.receiver.buffer, - fields.receiver.byteOffset, - fields.receiver.length - ), - remoteChainSelector: fields.remoteChainSelector, - originalSender: fields.originalSender, - amount: fields.amount, - localToken: fields.localToken, - } - } - - toJSON(): LockOrBurnInV1JSON { - return { - receiver: Array.from(this.receiver.values()), - remoteChainSelector: this.remoteChainSelector.toString(), - originalSender: this.originalSender.toString(), - amount: this.amount.toString(), - localToken: this.localToken.toString(), - } - } - - static fromJSON(obj: LockOrBurnInV1JSON): LockOrBurnInV1 { - return new LockOrBurnInV1({ - receiver: Uint8Array.from(obj.receiver), - remoteChainSelector: new BN(obj.remoteChainSelector), - originalSender: new PublicKey(obj.originalSender), - amount: new BN(obj.amount), - localToken: new PublicKey(obj.localToken), - }) - } - - toEncodable() { - return LockOrBurnInV1.toEncodable(this) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/LockOrBurnOutV1.ts b/ccip-lib/svm/burnmint-pool-bindings/types/LockOrBurnOutV1.ts deleted file mode 100644 index 09a975e0..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/LockOrBurnOutV1.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { PublicKey } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" - -export interface LockOrBurnOutV1Fields { - destTokenAddress: types.RemoteAddressFields - destPoolData: Uint8Array -} - -export interface LockOrBurnOutV1JSON { - destTokenAddress: types.RemoteAddressJSON - destPoolData: Array -} - -export class LockOrBurnOutV1 { - readonly destTokenAddress: types.RemoteAddress - readonly destPoolData: Uint8Array - - constructor(fields: LockOrBurnOutV1Fields) { - this.destTokenAddress = new types.RemoteAddress({ - ...fields.destTokenAddress, - }) - this.destPoolData = fields.destPoolData - } - - static layout(property?: string) { - return borsh.struct( - [ - types.RemoteAddress.layout("destTokenAddress"), - borsh.vecU8("destPoolData"), - ], - property - ) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static fromDecoded(obj: any) { - return new LockOrBurnOutV1({ - destTokenAddress: types.RemoteAddress.fromDecoded(obj.destTokenAddress), - destPoolData: new Uint8Array( - obj.destPoolData.buffer, - obj.destPoolData.byteOffset, - obj.destPoolData.length - ), - }) - } - - static toEncodable(fields: LockOrBurnOutV1Fields) { - return { - destTokenAddress: types.RemoteAddress.toEncodable( - fields.destTokenAddress - ), - destPoolData: Buffer.from( - fields.destPoolData.buffer, - fields.destPoolData.byteOffset, - fields.destPoolData.length - ), - } - } - - toJSON(): LockOrBurnOutV1JSON { - return { - destTokenAddress: this.destTokenAddress.toJSON(), - destPoolData: Array.from(this.destPoolData.values()), - } - } - - static fromJSON(obj: LockOrBurnOutV1JSON): LockOrBurnOutV1 { - return new LockOrBurnOutV1({ - destTokenAddress: types.RemoteAddress.fromJSON(obj.destTokenAddress), - destPoolData: Uint8Array.from(obj.destPoolData), - }) - } - - toEncodable() { - return LockOrBurnOutV1.toEncodable(this) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/PoolConfig.ts b/ccip-lib/svm/burnmint-pool-bindings/types/PoolConfig.ts deleted file mode 100644 index ed2f3808..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/PoolConfig.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { PublicKey } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" - -export interface PoolConfigFields { - version: number - self_served_allowed: boolean -} - -export interface PoolConfigJSON { - version: number - self_served_allowed: boolean -} - -export class PoolConfig { - readonly version: number - readonly self_served_allowed: boolean - - constructor(fields: PoolConfigFields) { - this.version = fields.version - this.self_served_allowed = fields.self_served_allowed - } - - static layout(property?: string) { - return borsh.struct( - [borsh.u8("version"), borsh.bool("self_served_allowed")], - property - ) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static fromDecoded(obj: any) { - return new PoolConfig({ - version: obj.version, - self_served_allowed: obj.self_served_allowed, - }) - } - - static toEncodable(fields: PoolConfigFields) { - return { - version: fields.version, - self_served_allowed: fields.self_served_allowed, - } - } - - toJSON(): PoolConfigJSON { - return { - version: this.version, - self_served_allowed: this.self_served_allowed, - } - } - - static fromJSON(obj: PoolConfigJSON): PoolConfig { - return new PoolConfig({ - version: obj.version, - self_served_allowed: obj.self_served_allowed, - }) - } - - toEncodable() { - return PoolConfig.toEncodable(this) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/RateLimitConfig.ts b/ccip-lib/svm/burnmint-pool-bindings/types/RateLimitConfig.ts deleted file mode 100644 index 67f6283f..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/RateLimitConfig.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { PublicKey } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" - -export interface RateLimitConfigFields { - enabled: boolean - capacity: BN - rate: BN -} - -export interface RateLimitConfigJSON { - enabled: boolean - capacity: string - rate: string -} - -export class RateLimitConfig { - readonly enabled: boolean - readonly capacity: BN - readonly rate: BN - - constructor(fields: RateLimitConfigFields) { - this.enabled = fields.enabled - this.capacity = fields.capacity - this.rate = fields.rate - } - - static layout(property?: string) { - return borsh.struct( - [borsh.bool("enabled"), borsh.u64("capacity"), borsh.u64("rate")], - property - ) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static fromDecoded(obj: any) { - return new RateLimitConfig({ - enabled: obj.enabled, - capacity: obj.capacity, - rate: obj.rate, - }) - } - - static toEncodable(fields: RateLimitConfigFields) { - return { - enabled: fields.enabled, - capacity: fields.capacity, - rate: fields.rate, - } - } - - toJSON(): RateLimitConfigJSON { - return { - enabled: this.enabled, - capacity: this.capacity.toString(), - rate: this.rate.toString(), - } - } - - static fromJSON(obj: RateLimitConfigJSON): RateLimitConfig { - return new RateLimitConfig({ - enabled: obj.enabled, - capacity: new BN(obj.capacity), - rate: new BN(obj.rate), - }) - } - - toEncodable() { - return RateLimitConfig.toEncodable(this) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/RateLimitTokenBucket.ts b/ccip-lib/svm/burnmint-pool-bindings/types/RateLimitTokenBucket.ts deleted file mode 100644 index 470472e6..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/RateLimitTokenBucket.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { PublicKey } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" - -export interface RateLimitTokenBucketFields { - tokens: BN - lastUpdated: BN - cfg: types.RateLimitConfigFields -} - -export interface RateLimitTokenBucketJSON { - tokens: string - lastUpdated: string - cfg: types.RateLimitConfigJSON -} - -export class RateLimitTokenBucket { - readonly tokens: BN - readonly lastUpdated: BN - readonly cfg: types.RateLimitConfig - - constructor(fields: RateLimitTokenBucketFields) { - this.tokens = fields.tokens - this.lastUpdated = fields.lastUpdated - this.cfg = new types.RateLimitConfig({ ...fields.cfg }) - } - - static layout(property?: string) { - return borsh.struct( - [ - borsh.u64("tokens"), - borsh.u64("lastUpdated"), - types.RateLimitConfig.layout("cfg"), - ], - property - ) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static fromDecoded(obj: any) { - return new RateLimitTokenBucket({ - tokens: obj.tokens, - lastUpdated: obj.lastUpdated, - cfg: types.RateLimitConfig.fromDecoded(obj.cfg), - }) - } - - static toEncodable(fields: RateLimitTokenBucketFields) { - return { - tokens: fields.tokens, - lastUpdated: fields.lastUpdated, - cfg: types.RateLimitConfig.toEncodable(fields.cfg), - } - } - - toJSON(): RateLimitTokenBucketJSON { - return { - tokens: this.tokens.toString(), - lastUpdated: this.lastUpdated.toString(), - cfg: this.cfg.toJSON(), - } - } - - static fromJSON(obj: RateLimitTokenBucketJSON): RateLimitTokenBucket { - return new RateLimitTokenBucket({ - tokens: new BN(obj.tokens), - lastUpdated: new BN(obj.lastUpdated), - cfg: types.RateLimitConfig.fromJSON(obj.cfg), - }) - } - - toEncodable() { - return RateLimitTokenBucket.toEncodable(this) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/ReleaseOrMintInV1.ts b/ccip-lib/svm/burnmint-pool-bindings/types/ReleaseOrMintInV1.ts deleted file mode 100644 index 55dee693..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/ReleaseOrMintInV1.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { PublicKey } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" - -export interface ReleaseOrMintInV1Fields { - originalSender: types.RemoteAddressFields - remoteChainSelector: BN - receiver: PublicKey - amount: Array - localToken: PublicKey - /** - * @dev WARNING: sourcePoolAddress should be checked prior to any processing of funds. Make sure it matches the - * expected pool address for the given remoteChainSelector. - */ - sourcePoolAddress: types.RemoteAddressFields - sourcePoolData: Uint8Array - /** @dev WARNING: offchainTokenData is untrusted data. */ - offchainTokenData: Uint8Array -} - -export interface ReleaseOrMintInV1JSON { - originalSender: types.RemoteAddressJSON - remoteChainSelector: string - receiver: string - amount: Array - localToken: string - /** - * @dev WARNING: sourcePoolAddress should be checked prior to any processing of funds. Make sure it matches the - * expected pool address for the given remoteChainSelector. - */ - sourcePoolAddress: types.RemoteAddressJSON - sourcePoolData: Array - /** @dev WARNING: offchainTokenData is untrusted data. */ - offchainTokenData: Array -} - -export class ReleaseOrMintInV1 { - readonly originalSender: types.RemoteAddress - readonly remoteChainSelector: BN - readonly receiver: PublicKey - readonly amount: Array - readonly localToken: PublicKey - /** - * @dev WARNING: sourcePoolAddress should be checked prior to any processing of funds. Make sure it matches the - * expected pool address for the given remoteChainSelector. - */ - readonly sourcePoolAddress: types.RemoteAddress - readonly sourcePoolData: Uint8Array - /** @dev WARNING: offchainTokenData is untrusted data. */ - readonly offchainTokenData: Uint8Array - - constructor(fields: ReleaseOrMintInV1Fields) { - this.originalSender = new types.RemoteAddress({ ...fields.originalSender }) - this.remoteChainSelector = fields.remoteChainSelector - this.receiver = fields.receiver - this.amount = fields.amount - this.localToken = fields.localToken - this.sourcePoolAddress = new types.RemoteAddress({ - ...fields.sourcePoolAddress, - }) - this.sourcePoolData = fields.sourcePoolData - this.offchainTokenData = fields.offchainTokenData - } - - static layout(property?: string) { - return borsh.struct( - [ - types.RemoteAddress.layout("originalSender"), - borsh.u64("remoteChainSelector"), - borsh.publicKey("receiver"), - borsh.array(borsh.u8(), 32, "amount"), - borsh.publicKey("localToken"), - types.RemoteAddress.layout("sourcePoolAddress"), - borsh.vecU8("sourcePoolData"), - borsh.vecU8("offchainTokenData"), - ], - property - ) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static fromDecoded(obj: any) { - return new ReleaseOrMintInV1({ - originalSender: types.RemoteAddress.fromDecoded(obj.originalSender), - remoteChainSelector: obj.remoteChainSelector, - receiver: obj.receiver, - amount: obj.amount, - localToken: obj.localToken, - sourcePoolAddress: types.RemoteAddress.fromDecoded(obj.sourcePoolAddress), - sourcePoolData: new Uint8Array( - obj.sourcePoolData.buffer, - obj.sourcePoolData.byteOffset, - obj.sourcePoolData.length - ), - offchainTokenData: new Uint8Array( - obj.offchainTokenData.buffer, - obj.offchainTokenData.byteOffset, - obj.offchainTokenData.length - ), - }) - } - - static toEncodable(fields: ReleaseOrMintInV1Fields) { - return { - originalSender: types.RemoteAddress.toEncodable(fields.originalSender), - remoteChainSelector: fields.remoteChainSelector, - receiver: fields.receiver, - amount: fields.amount, - localToken: fields.localToken, - sourcePoolAddress: types.RemoteAddress.toEncodable( - fields.sourcePoolAddress - ), - sourcePoolData: Buffer.from( - fields.sourcePoolData.buffer, - fields.sourcePoolData.byteOffset, - fields.sourcePoolData.length - ), - offchainTokenData: Buffer.from( - fields.offchainTokenData.buffer, - fields.offchainTokenData.byteOffset, - fields.offchainTokenData.length - ), - } - } - - toJSON(): ReleaseOrMintInV1JSON { - return { - originalSender: this.originalSender.toJSON(), - remoteChainSelector: this.remoteChainSelector.toString(), - receiver: this.receiver.toString(), - amount: this.amount, - localToken: this.localToken.toString(), - sourcePoolAddress: this.sourcePoolAddress.toJSON(), - sourcePoolData: Array.from(this.sourcePoolData.values()), - offchainTokenData: Array.from(this.offchainTokenData.values()), - } - } - - static fromJSON(obj: ReleaseOrMintInV1JSON): ReleaseOrMintInV1 { - return new ReleaseOrMintInV1({ - originalSender: types.RemoteAddress.fromJSON(obj.originalSender), - remoteChainSelector: new BN(obj.remoteChainSelector), - receiver: new PublicKey(obj.receiver), - amount: obj.amount, - localToken: new PublicKey(obj.localToken), - sourcePoolAddress: types.RemoteAddress.fromJSON(obj.sourcePoolAddress), - sourcePoolData: Uint8Array.from(obj.sourcePoolData), - offchainTokenData: Uint8Array.from(obj.offchainTokenData), - }) - } - - toEncodable() { - return ReleaseOrMintInV1.toEncodable(this) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/ReleaseOrMintOutV1.ts b/ccip-lib/svm/burnmint-pool-bindings/types/ReleaseOrMintOutV1.ts deleted file mode 100644 index 0373270c..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/ReleaseOrMintOutV1.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { PublicKey } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" - -export interface ReleaseOrMintOutV1Fields { - destinationAmount: BN -} - -export interface ReleaseOrMintOutV1JSON { - destinationAmount: string -} - -export class ReleaseOrMintOutV1 { - readonly destinationAmount: BN - - constructor(fields: ReleaseOrMintOutV1Fields) { - this.destinationAmount = fields.destinationAmount - } - - static layout(property?: string) { - return borsh.struct([borsh.u64("destinationAmount")], property) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static fromDecoded(obj: any) { - return new ReleaseOrMintOutV1({ - destinationAmount: obj.destinationAmount, - }) - } - - static toEncodable(fields: ReleaseOrMintOutV1Fields) { - return { - destinationAmount: fields.destinationAmount, - } - } - - toJSON(): ReleaseOrMintOutV1JSON { - return { - destinationAmount: this.destinationAmount.toString(), - } - } - - static fromJSON(obj: ReleaseOrMintOutV1JSON): ReleaseOrMintOutV1 { - return new ReleaseOrMintOutV1({ - destinationAmount: new BN(obj.destinationAmount), - }) - } - - toEncodable() { - return ReleaseOrMintOutV1.toEncodable(this) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/RemoteAddress.ts b/ccip-lib/svm/burnmint-pool-bindings/types/RemoteAddress.ts deleted file mode 100644 index 51fe7ee1..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/RemoteAddress.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { PublicKey } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" - -export interface RemoteAddressFields { - address: Uint8Array -} - -export interface RemoteAddressJSON { - address: Array -} - -export class RemoteAddress { - readonly address: Uint8Array - - constructor(fields: RemoteAddressFields) { - this.address = fields.address - } - - static layout(property?: string) { - return borsh.struct([borsh.vecU8("address")], property) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static fromDecoded(obj: any) { - return new RemoteAddress({ - address: new Uint8Array( - obj.address.buffer, - obj.address.byteOffset, - obj.address.length - ), - }) - } - - static toEncodable(fields: RemoteAddressFields) { - return { - address: Buffer.from( - fields.address.buffer, - fields.address.byteOffset, - fields.address.length - ), - } - } - - toJSON(): RemoteAddressJSON { - return { - address: Array.from(this.address.values()), - } - } - - static fromJSON(obj: RemoteAddressJSON): RemoteAddress { - return new RemoteAddress({ - address: Uint8Array.from(obj.address), - }) - } - - toEncodable() { - return RemoteAddress.toEncodable(this) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/RemoteConfig.ts b/ccip-lib/svm/burnmint-pool-bindings/types/RemoteConfig.ts deleted file mode 100644 index 3cc275ab..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/RemoteConfig.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { PublicKey } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" - -export interface RemoteConfigFields { - poolAddresses: Array - tokenAddress: types.RemoteAddressFields - decimals: number -} - -export interface RemoteConfigJSON { - poolAddresses: Array - tokenAddress: types.RemoteAddressJSON - decimals: number -} - -export class RemoteConfig { - readonly poolAddresses: Array - readonly tokenAddress: types.RemoteAddress - readonly decimals: number - - constructor(fields: RemoteConfigFields) { - this.poolAddresses = fields.poolAddresses.map( - (item) => new types.RemoteAddress({ ...item }) - ) - this.tokenAddress = new types.RemoteAddress({ ...fields.tokenAddress }) - this.decimals = fields.decimals - } - - static layout(property?: string) { - return borsh.struct( - [ - borsh.vec(types.RemoteAddress.layout(), "poolAddresses"), - types.RemoteAddress.layout("tokenAddress"), - borsh.u8("decimals"), - ], - property - ) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static fromDecoded(obj: any) { - return new RemoteConfig({ - poolAddresses: obj.poolAddresses.map( - ( - item: any /* eslint-disable-line @typescript-eslint/no-explicit-any */ - ) => types.RemoteAddress.fromDecoded(item) - ), - tokenAddress: types.RemoteAddress.fromDecoded(obj.tokenAddress), - decimals: obj.decimals, - }) - } - - static toEncodable(fields: RemoteConfigFields) { - return { - poolAddresses: fields.poolAddresses.map((item) => - types.RemoteAddress.toEncodable(item) - ), - tokenAddress: types.RemoteAddress.toEncodable(fields.tokenAddress), - decimals: fields.decimals, - } - } - - toJSON(): RemoteConfigJSON { - return { - poolAddresses: this.poolAddresses.map((item) => item.toJSON()), - tokenAddress: this.tokenAddress.toJSON(), - decimals: this.decimals, - } - } - - static fromJSON(obj: RemoteConfigJSON): RemoteConfig { - return new RemoteConfig({ - poolAddresses: obj.poolAddresses.map((item) => - types.RemoteAddress.fromJSON(item) - ), - tokenAddress: types.RemoteAddress.fromJSON(obj.tokenAddress), - decimals: obj.decimals, - }) - } - - toEncodable() { - return RemoteConfig.toEncodable(this) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/State.ts b/ccip-lib/svm/burnmint-pool-bindings/types/State.ts deleted file mode 100644 index 87657282..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/State.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { PublicKey } from "@solana/web3.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import BN from "bn.js" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as types from "../types" // eslint-disable-line @typescript-eslint/no-unused-vars -import * as borsh from "@coral-xyz/borsh" - -export interface StateFields { - version: number - config: types.BaseConfigFields -} - -export interface StateJSON { - version: number - config: types.BaseConfigJSON -} - -export class State { - readonly version: number - readonly config: types.BaseConfig - - constructor(fields: StateFields) { - this.version = fields.version - this.config = new types.BaseConfig({ ...fields.config }) - } - - static layout(property?: string) { - return borsh.struct( - [borsh.u8("version"), types.BaseConfig.layout("config")], - property - ) - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - static fromDecoded(obj: any) { - return new State({ - version: obj.version, - config: types.BaseConfig.fromDecoded(obj.config), - }) - } - - static toEncodable(fields: StateFields) { - return { - version: fields.version, - config: types.BaseConfig.toEncodable(fields.config), - } - } - - toJSON(): StateJSON { - return { - version: this.version, - config: this.config.toJSON(), - } - } - - static fromJSON(obj: StateJSON): State { - return new State({ - version: obj.version, - config: types.BaseConfig.fromJSON(obj.config), - }) - } - - toEncodable() { - return State.toEncodable(this) - } -} diff --git a/ccip-lib/svm/burnmint-pool-bindings/types/index.ts b/ccip-lib/svm/burnmint-pool-bindings/types/index.ts deleted file mode 100644 index e0609de6..00000000 --- a/ccip-lib/svm/burnmint-pool-bindings/types/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -export { BaseChain } from "./BaseChain" -export type { BaseChainFields, BaseChainJSON } from "./BaseChain" -export { BaseConfig } from "./BaseConfig" -export type { BaseConfigFields, BaseConfigJSON } from "./BaseConfig" -export { LockOrBurnInV1 } from "./LockOrBurnInV1" -export type { LockOrBurnInV1Fields, LockOrBurnInV1JSON } from "./LockOrBurnInV1" -export { LockOrBurnOutV1 } from "./LockOrBurnOutV1" -export type { - LockOrBurnOutV1Fields, - LockOrBurnOutV1JSON, -} from "./LockOrBurnOutV1" -export { RateLimitConfig } from "./RateLimitConfig" -export type { - RateLimitConfigFields, - RateLimitConfigJSON, -} from "./RateLimitConfig" -export { RateLimitTokenBucket } from "./RateLimitTokenBucket" -export type { - RateLimitTokenBucketFields, - RateLimitTokenBucketJSON, -} from "./RateLimitTokenBucket" -export { ReleaseOrMintInV1 } from "./ReleaseOrMintInV1" -export type { - ReleaseOrMintInV1Fields, - ReleaseOrMintInV1JSON, -} from "./ReleaseOrMintInV1" -export { ReleaseOrMintOutV1 } from "./ReleaseOrMintOutV1" -export type { - ReleaseOrMintOutV1Fields, - ReleaseOrMintOutV1JSON, -} from "./ReleaseOrMintOutV1" -export { RemoteAddress } from "./RemoteAddress" -export type { RemoteAddressFields, RemoteAddressJSON } from "./RemoteAddress" -export { RemoteConfig } from "./RemoteConfig" -export type { RemoteConfigFields, RemoteConfigJSON } from "./RemoteConfig" diff --git a/ccip-lib/svm/core/client/tokenpools.ts b/ccip-lib/svm/core/client/tokenpools.ts deleted file mode 100644 index dafa66c0..00000000 --- a/ccip-lib/svm/core/client/tokenpools.ts +++ /dev/null @@ -1,230 +0,0 @@ -import { PublicKey, Connection, Keypair } from "@solana/web3.js"; -import { CCIPContext, CCIPProvider, CCIPCoreConfig } from "../models"; -import { createLogger, Logger, LogLevel } from "../../utils/logger"; -import { TokenPoolClient } from "../../tokenpools/abstract"; -import { - TokenPoolFactory, - TokenPoolProgramIds, -} from "../../tokenpools/factory"; -import { TokenPoolType } from "../../tokenpools"; -import { TokenRegistryClient } from "./tokenregistry"; -import { loadKeypair } from "../../utils/keypair"; - -/** - * Manages token pool operations for CCIP - */ -export class TokenPoolManager { - private readonly logger: Logger; - private readonly registryClient: TokenRegistryClient; - - /** - * Creates a new TokenPoolManager - * @param context CCIP context - * @param programIds Map of program IDs for different token pool types - */ - constructor( - private readonly context: CCIPContext, - private readonly programIds: TokenPoolProgramIds - ) { - this.logger = - context.logger ?? - createLogger("token-pool-manager", { level: LogLevel.INFO }); - this.registryClient = new TokenRegistryClient( - context, - context.config.ccipRouterProgramId - ); - this.logger.debug("TokenPoolManager initialized"); - } - - /** - * Creates a new TokenPoolManager from simplified configuration - * @param connection Solana connection - * @param wallet Keypair for signing - * @param programIds Pool program IDs - * @param config Partial configuration - * @param options Optional manager options - * @returns A new TokenPoolManager instance - */ - static create( - connection: Connection, - wallet: Keypair, - programIds: TokenPoolProgramIds, - config: { - ccipRouterProgramId: string; - feeQuoterProgramId: string; - rmnRemoteProgramId: string; - linkTokenMint?: string; - receiverProgramId?: string; - }, - options?: { logLevel?: LogLevel } - ): TokenPoolManager { - // Create provider - const provider: CCIPProvider = { - connection, - wallet, - getAddress: () => wallet.publicKey, - signTransaction: async (tx) => { - if ('version' in tx) { - tx.sign([wallet]); - } else { - tx.partialSign(wallet); - } - return tx; - }, - }; - - // Build core config - const coreConfig: CCIPCoreConfig = { - ccipRouterProgramId: new PublicKey(config.ccipRouterProgramId), - feeQuoterProgramId: new PublicKey(config.feeQuoterProgramId), - rmnRemoteProgramId: new PublicKey(config.rmnRemoteProgramId), - linkTokenMint: new PublicKey(config.linkTokenMint || "LinkhB3afbBKb2EQQu7s7umdZceV3wcvAUJhQAfQ23L"), - tokenMint: PublicKey.default, - nativeSol: PublicKey.default, - systemProgramId: new PublicKey("11111111111111111111111111111111"), - programId: new PublicKey(config.receiverProgramId || "BqmcnLFSbKwyMEgi7VhVeJCis1wW26VySztF34CJrKFq"), - }; - - // Create context - const context: CCIPContext = { - provider, - config: coreConfig, - logger: createLogger("token-pool-manager", { level: options?.logLevel ?? LogLevel.INFO }), - }; - - return new TokenPoolManager(context, programIds); - } - - /** - * Creates a new TokenPoolManager from keypair file - * @param keypairPath Path to keypair file - * @param endpoint RPC endpoint - * @param programIds Pool program IDs - * @param config Configuration - * @param options Optional manager options - * @returns A new TokenPoolManager instance - */ - static createFromKeypair( - keypairPath: string, - endpoint: string, - programIds: TokenPoolProgramIds, - config: { - ccipRouterProgramId: string; - feeQuoterProgramId: string; - rmnRemoteProgramId: string; - linkTokenMint?: string; - receiverProgramId?: string; - }, - options?: { logLevel?: LogLevel; commitment?: string } - ): TokenPoolManager { - const wallet = loadKeypair(keypairPath); - const connection = new Connection(endpoint, options?.commitment as any || "confirmed"); - return TokenPoolManager.create(connection, wallet, programIds, config, options); - } - - /** - * Get a token pool client for a specific pool type - * @param type Pool type to use - * @returns TokenPoolClient instance for the specified type - */ - getTokenPoolClient(type: TokenPoolType): TokenPoolClient { - this.logger.debug(`Creating token pool client of type: ${type}`); - return TokenPoolFactory.create(type, this.context, this.programIds); - } - - /** - * Get the token registry client for managing token pool registrations - * @returns TokenRegistryClient instance - */ - getRegistryClient(): TokenRegistryClient { - return this.registryClient; - } - - /** - * Detect and get the appropriate token pool client for a mint - * This looks at on-chain accounts to determine which pool type is used - * - * @param mint Token mint public key - * @returns TokenPoolClient instance for the detected pool type - * @throws If no token pool is found for the mint - */ - async getTokenPoolClientForMint(mint: PublicKey): Promise { - this.logger.debug(`Detecting token pool type for mint: ${mint.toString()}`); - const poolType = await TokenPoolFactory.detectPoolType( - mint, - this.context, - this.programIds - ); - return this.getTokenPoolClient(poolType); - } - - /** - * Initialize a chain remote configuration for a token pool. - * - * This method creates a new chain configuration for the specified remoteChainSelector. - * The chain configuration must not already exist for this operation to succeed. - * - * @param mint Token mint identifying the pool - * @param destChainSelector The unique identifier of the remote blockchain network - * @param options Configuration options including remote token address, pool addresses, and decimals - * @param poolType Optional pool type (if not provided, it will be auto-detected) - * @returns Transaction signature - * @throws If the pool doesn't exist, if the chain config already exists, or if the transaction fails - */ - async initChainRemoteConfig( - mint: PublicKey, - destChainSelector: bigint, - options: any, - poolType?: TokenPoolType - ): Promise { - this.logger.debug( - `Initializing chain remote config for mint: ${mint.toString()}, chain: ${destChainSelector.toString()}` - ); - - const client = poolType - ? this.getTokenPoolClient(poolType) - : await this.getTokenPoolClientForMint(mint); - - const result = await client.initChainRemoteConfig( - mint, - destChainSelector, - options - ); - return result.signature; - } - - /** - * Edit an existing chain remote configuration for a token pool. - * - * This method updates an existing chain configuration for the specified remoteChainSelector. - * The chain configuration must already exist for this operation to succeed. - * - * @param mint Token mint identifying the pool - * @param destChainSelector The unique identifier of the remote blockchain network - * @param options Configuration options including remote token address, pool addresses, and decimals - * @param poolType Optional pool type (if not provided, it will be auto-detected) - * @returns Transaction signature - * @throws If the pool doesn't exist, if the chain config doesn't exist, or if the transaction fails - */ - async editChainRemoteConfig( - mint: PublicKey, - destChainSelector: bigint, - options: any, - poolType?: TokenPoolType - ): Promise { - this.logger.debug( - `Editing chain remote config for mint: ${mint.toString()}, chain: ${destChainSelector.toString()}` - ); - - const client = poolType - ? this.getTokenPoolClient(poolType) - : await this.getTokenPoolClientForMint(mint); - - const result = await client.editChainRemoteConfig( - mint, - destChainSelector, - options - ); - return result.signature; - } -} diff --git a/ccip-lib/svm/core/client/tokenregistry.ts b/ccip-lib/svm/core/client/tokenregistry.ts deleted file mode 100644 index 75e90dde..00000000 --- a/ccip-lib/svm/core/client/tokenregistry.ts +++ /dev/null @@ -1,1167 +0,0 @@ -import { - PublicKey, - SystemProgram, - AddressLookupTableProgram, - Connection, - Keypair, -} from "@solana/web3.js"; -import { CCIPContext, CCIPProvider, CCIPCoreConfig } from "../models"; -import { createLogger, Logger, LogLevel } from "../../utils/logger"; -import { createErrorEnhancer } from "../../utils/errors"; -import { - executeTransaction, - extractTxOptions, - TransactionExecutionOptions, -} from "../../utils/transaction"; -import { detectTokenProgram } from "../../utils/token"; -import { - findConfigPDA, - findTokenAdminRegistryPDA, - ROUTER_SEEDS, -} from "../../utils/pdas/router"; -import { TxOptions } from "../../tokenpools/abstract"; -import { TokenAdminRegistry } from "../../bindings/accounts/tokenAdminRegistry"; -import { - findBurnMintPoolConfigPDA, - findPoolSignerPDA, - TOKEN_POOL_STATE_SEED, - TOKEN_POOL_POOL_SIGNER_SEED, -} from "../../utils/pdas/tokenpool"; -import { findFqBillingTokenConfigPDA } from "../../utils/pdas/feeQuoter"; -import { findExternalTokenPoolsSignerPDA } from "../../utils/pdas/router"; -import { - getAssociatedTokenAddressSync, - TOKEN_PROGRAM_ID, - TOKEN_2022_PROGRAM_ID, -} from "@solana/spl-token"; -import { loadKeypair } from "../../utils/keypair"; - -// Import from bindings for ccip-router -import { - ownerProposeAdministrator, - acceptAdminRoleTokenAdminRegistry, - transferAdminRoleTokenAdminRegistry, - setPool, - OwnerProposeAdministratorAccounts, - OwnerProposeAdministratorArgs, - AcceptAdminRoleTokenAdminRegistryAccounts, - TransferAdminRoleTokenAdminRegistryAccounts, - TransferAdminRoleTokenAdminRegistryArgs, - SetPoolAccounts, -} from "../../bindings/instructions"; - -/** - * Common base options extending TxOptions - */ -export interface TokenRegistryTxOptions extends TxOptions {} - -/** - * Options for proposing an administrator - */ -export interface ProposeAdministratorOptions extends TokenRegistryTxOptions { - tokenMint: PublicKey; - newAdmin: PublicKey; -} - -/** - * Options for accepting an admin role - */ -export interface AcceptAdminRoleOptions extends TokenRegistryTxOptions { - tokenMint: PublicKey; -} - -/** - * Options for transferring an admin role - */ -export interface TransferAdminRoleOptions extends TokenRegistryTxOptions { - tokenMint: PublicKey; - newAdmin: PublicKey; -} - -/** - * Options for setting a pool - */ -export interface SetPoolOptions extends TokenRegistryTxOptions { - tokenMint: PublicKey; - lookupTable: PublicKey; - writableIndices: number[]; -} - -/** - * Options for creating a token pool lookup table - */ -export interface CreateTokenPoolLookupTableOptions - extends TokenRegistryTxOptions { - tokenMint: PublicKey; - poolProgramId: PublicKey; - feeQuoterProgramId: PublicKey; - additionalAddresses?: PublicKey[]; - // tokenProgramId is now auto-detected, removed from interface -} - -/** - * Result of creating a token pool lookup table - */ -export interface CreateTokenPoolLookupTableResult { - signature: string; - lookupTableAddress: PublicKey; - addresses: PublicKey[]; -} - -/** - * Options for extending a token pool lookup table - */ -export interface ExtendTokenPoolLookupTableOptions - extends TokenRegistryTxOptions { - lookupTableAddress: PublicKey; - newAddresses: PublicKey[]; -} - -/** - * Result of extending a token pool lookup table - */ -export interface ExtendTokenPoolLookupTableResult { - signature: string; - lookupTableAddress: PublicKey; - newAddresses: PublicKey[]; - totalAddresses: number; -} - -/** - * Client for managing token registry administration - * Used to register and manage token pools with the CCIP router - */ -export class TokenRegistryClient { - private readonly logger: Logger; - - /** - * Creates a new TokenRegistryClient - * @param context CCIP context - * @param routerProgramId CCIP Router program ID - */ - constructor( - readonly context: CCIPContext, - readonly routerProgramId: PublicKey - ) { - this.logger = - context.logger ?? - createLogger("token-registry-client", { level: LogLevel.INFO }); - this.logger.debug( - `TokenRegistryClient initialized: routerProgramId=${this.routerProgramId.toString()}` - ); - } - - /** - * Creates a new TokenRegistryClient from simplified configuration - * @param connection Solana connection - * @param wallet Keypair for signing - * @param routerProgramId CCIP Router program ID - * @param config Additional configuration - * @param options Optional client options - * @returns A new TokenRegistryClient instance - */ - static create( - connection: Connection, - wallet: Keypair, - routerProgramId: string, - config?: { - feeQuoterProgramId?: string; - rmnRemoteProgramId?: string; - linkTokenMint?: string; - receiverProgramId?: string; - }, - options?: { logLevel?: LogLevel } - ): TokenRegistryClient { - // Create provider - const provider: CCIPProvider = { - connection, - wallet, - getAddress: () => wallet.publicKey, - signTransaction: async (tx) => { - if ('version' in tx) { - tx.sign([wallet]); - } else { - tx.partialSign(wallet); - } - return tx; - }, - }; - - // Build core config with defaults - const coreConfig: CCIPCoreConfig = { - ccipRouterProgramId: new PublicKey(routerProgramId), - feeQuoterProgramId: new PublicKey(config?.feeQuoterProgramId || "FeeQPGkKDeRV1MgoYfMH6L8o3KeuYjwUZrgn4LRKfjHi"), - rmnRemoteProgramId: new PublicKey(config?.rmnRemoteProgramId || "RmnXLft1mSEwDgMKu2okYuHkiazxntFFcZFrrcXxYg7"), - linkTokenMint: new PublicKey(config?.linkTokenMint || "LinkhB3afbBKb2EQQu7s7umdZceV3wcvAUJhQAfQ23L"), - tokenMint: PublicKey.default, - nativeSol: PublicKey.default, - systemProgramId: new PublicKey("11111111111111111111111111111111"), - programId: new PublicKey(config?.receiverProgramId || "BqmcnLFSbKwyMEgi7VhVeJCis1wW26VySztF34CJrKFq"), - }; - - // Create context - const context: CCIPContext = { - provider, - config: coreConfig, - logger: createLogger("token-registry-client", { level: options?.logLevel ?? LogLevel.INFO }), - }; - - return new TokenRegistryClient(context, new PublicKey(routerProgramId)); - } - - /** - * Creates a new TokenRegistryClient from keypair file - * @param keypairPath Path to keypair file - * @param endpoint RPC endpoint - * @param routerProgramId CCIP Router program ID - * @param config Additional configuration - * @param options Optional client options - * @returns A new TokenRegistryClient instance - */ - static createFromKeypair( - keypairPath: string, - endpoint: string, - routerProgramId: string, - config?: { - feeQuoterProgramId?: string; - rmnRemoteProgramId?: string; - linkTokenMint?: string; - receiverProgramId?: string; - }, - options?: { logLevel?: LogLevel; commitment?: string } - ): TokenRegistryClient { - const wallet = loadKeypair(keypairPath); - const connection = new Connection(endpoint, options?.commitment as any || "confirmed"); - return TokenRegistryClient.create(connection, wallet, routerProgramId, config, options); - } - - /** - * Retrieves the token admin registry account for a token - * - * @param tokenMint The mint of the token to fetch the registry for - * @returns The token admin registry account if it exists, null otherwise - */ - async getTokenAdminRegistry( - tokenMint: PublicKey - ): Promise { - const errorContext = { - operation: "getTokenAdminRegistry", - mint: tokenMint.toString(), - }; - - try { - this.logger.info( - `Fetching token admin registry for mint: ${tokenMint.toString()}` - ); - - // Find the PDA for the token admin registry - const [tokenAdminRegistryPDA, tokenAdminRegistryBump] = - findTokenAdminRegistryPDA(tokenMint, this.routerProgramId); - this.logger.debug( - `Token Admin Registry PDA: ${tokenAdminRegistryPDA.toString()} (bump: ${tokenAdminRegistryBump})` - ); - this.logger.trace( - `Token Admin Registry PDA derivation: seeds=["${ - ROUTER_SEEDS.TOKEN_ADMIN_REGISTRY - }", ${tokenMint.toString()}], program=${this.routerProgramId.toString()}` - ); - - // Fetch the account using TokenAdminRegistry helper - const tokenAdmin = await TokenAdminRegistry.fetch( - this.context.provider.connection, - tokenAdminRegistryPDA, - this.routerProgramId - ); - - if (tokenAdmin) { - this.logger.debug( - `Token admin data retrieved for ${tokenMint.toString()}` - ); - } else { - this.logger.debug( - `No token admin data found for ${tokenMint.toString()}` - ); - } - - return tokenAdmin; - } catch (error) { - const enhanceError = createErrorEnhancer(this.logger); - throw enhanceError(error, errorContext); - } - } - - /** - * Proposes a new administrator for a token's registry. - * Only the token owner (mint authority) can call this method. - * - * This is the first step in a two-step process to set or change - * the administrator for a token. The proposed administrator must - * call `acceptAdminRole` to complete the process. - * - * @param options Configuration options including token mint and proposed admin - * @returns Promise resolving to the transaction signature - * @throws Error if the caller is not the token owner or if the transaction fails - */ - async proposeAdministrator( - options: ProposeAdministratorOptions - ): Promise { - const errorContext = { - operation: "proposeAdministrator", - mint: options.tokenMint.toString(), - newAdmin: options.newAdmin.toString(), - }; - - try { - this.logger.info( - `Proposing administrator for token ${options.tokenMint.toString()}: new admin ${options.newAdmin.toString()}` - ); - - // Get signer and derive necessary PDAs - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug("Propose administrator details:", { - mint: options.tokenMint.toString(), - newAdmin: options.newAdmin.toString(), - signer: signerPublicKey.toString(), - programId: this.routerProgramId.toString(), - }); - - // Use bindings to find PDAs - const [tokenAdminRegistryPDA, tokenAdminRegistryBump] = - findTokenAdminRegistryPDA(options.tokenMint, this.routerProgramId); - this.logger.debug( - `Token Admin Registry PDA: ${tokenAdminRegistryPDA.toString()} (bump: ${tokenAdminRegistryBump})` - ); - this.logger.trace( - `Token Admin Registry PDA derivation: seeds=["${ - ROUTER_SEEDS.TOKEN_ADMIN_REGISTRY - }", ${options.tokenMint.toString()}], program=${this.routerProgramId.toString()}` - ); - - const [configPDA, configBump] = findConfigPDA(this.routerProgramId); - this.logger.debug( - `Config PDA: ${configPDA.toString()} (bump: ${configBump})` - ); - this.logger.trace( - `Config PDA derivation: seeds=["${ - ROUTER_SEEDS.CONFIG - }"], program=${this.routerProgramId.toString()}` - ); - - // Build accounts using the bindings structures - const accounts: OwnerProposeAdministratorAccounts = { - config: configPDA, - tokenAdminRegistry: tokenAdminRegistryPDA, - mint: options.tokenMint, - authority: signerPublicKey, - systemProgram: SystemProgram.programId, - }; - this.logger.debug("Propose administrator accounts:", { - config: accounts.config.toString(), - tokenAdminRegistry: accounts.tokenAdminRegistry.toString(), - mint: accounts.mint.toString(), - authority: accounts.authority.toString(), - systemProgram: accounts.systemProgram.toString(), - }); - - // Build args - const args: OwnerProposeAdministratorArgs = { - tokenAdminRegistryAdmin: options.newAdmin, - }; - this.logger.debug("Propose administrator args:", { - tokenAdminRegistryAdmin: args.tokenAdminRegistryAdmin.toString(), - }); - - // Create instruction using the bindings - this.logger.debug("Creating ownerProposeAdministrator instruction..."); - const instruction = ownerProposeAdministrator( - args, - accounts, - this.routerProgramId - ); - this.logger.debug("Instruction created:", { - programId: instruction.programId.toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((k, i) => ({ - index: i, - pubkey: k.pubkey.toString(), - isSigner: k.isSigner, - isWritable: k.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute transaction - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "proposeAdministrator", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info( - `Administrator proposed successfully. Tx signature: ${signature}` - ); - return signature; - } catch (error) { - const enhanceError = createErrorEnhancer(this.logger); - throw enhanceError(error, errorContext); - } - } - - /** - * Accept the admin role for a token's registry. - * - * This is the second step in a two-step process for setting or changing - * the administrator for a token. Only the proposed administrator - * (set via `proposeAdministrator`) can call this method. - * - * @param options Configuration options including token mint - * @returns Promise resolving to the transaction signature - * @throws Error if the caller is not the proposed admin or if the transaction fails - */ - async acceptAdminRole(options: AcceptAdminRoleOptions): Promise { - const errorContext = { - operation: "acceptAdminRole", - mint: options.tokenMint.toString(), - }; - - try { - this.logger.info( - `Accepting admin role for token: ${options.tokenMint.toString()}` - ); - - // Get signer and derive PDAs using bindings - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug("Accept admin role details:", { - mint: options.tokenMint.toString(), - signer: signerPublicKey.toString(), - programId: this.routerProgramId.toString(), - }); - - const [tokenAdminRegistryPDA, tokenAdminRegistryBump] = - findTokenAdminRegistryPDA(options.tokenMint, this.routerProgramId); - this.logger.debug( - `Token Admin Registry PDA: ${tokenAdminRegistryPDA.toString()} (bump: ${tokenAdminRegistryBump})` - ); - this.logger.trace( - `Token Admin Registry PDA derivation: seeds=["${ - ROUTER_SEEDS.TOKEN_ADMIN_REGISTRY - }", ${options.tokenMint.toString()}], program=${this.routerProgramId.toString()}` - ); - - const [configPDA, configBump] = findConfigPDA(this.routerProgramId); - this.logger.debug( - `Config PDA: ${configPDA.toString()} (bump: ${configBump})` - ); - this.logger.trace( - `Config PDA derivation: seeds=["${ - ROUTER_SEEDS.CONFIG - }"], program=${this.routerProgramId.toString()}` - ); - - // Build accounts using binding structures - const accounts: AcceptAdminRoleTokenAdminRegistryAccounts = { - config: configPDA, - tokenAdminRegistry: tokenAdminRegistryPDA, - mint: options.tokenMint, - authority: signerPublicKey, - }; - this.logger.debug("Accept admin role accounts:", { - config: accounts.config.toString(), - tokenAdminRegistry: accounts.tokenAdminRegistry.toString(), - mint: accounts.mint.toString(), - authority: accounts.authority.toString(), - }); - - // Create instruction using bindings (no args for this one) - this.logger.debug( - "Creating acceptAdminRoleTokenAdminRegistry instruction..." - ); - const instruction = acceptAdminRoleTokenAdminRegistry( - accounts, - this.routerProgramId - ); - this.logger.debug("Instruction created:", { - programId: instruction.programId.toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((k, i) => ({ - index: i, - pubkey: k.pubkey.toString(), - isSigner: k.isSigner, - isWritable: k.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute transaction - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "acceptAdminRole", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info( - `Admin role accepted successfully. Tx signature: ${signature}` - ); - return signature; - } catch (error) { - const enhanceError = createErrorEnhancer(this.logger); - throw enhanceError(error, errorContext); - } - } - - /** - * Transfer the admin role for a token to a new admin. - * - * This is the first step in a two-step ownership transfer process. - * Only the current administrator can transfer the admin role. - * The proposed new administrator must call `acceptAdminRole` to complete the transfer. - * - * @param options Configuration options including token mint and new admin - * @returns Promise resolving to the transaction signature - * @throws Error if the caller is not the current admin or if the transaction fails - */ - async transferAdminRole(options: TransferAdminRoleOptions): Promise { - const errorContext = { - operation: "transferAdminRole", - mint: options.tokenMint.toString(), - newAdmin: options.newAdmin.toString(), - }; - - try { - this.logger.info( - `Transferring admin role for token ${options.tokenMint.toString()} to ${options.newAdmin.toString()}` - ); - - // Get signer and derive PDAs - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug("Transfer admin role details:", { - mint: options.tokenMint.toString(), - newAdmin: options.newAdmin.toString(), - signer: signerPublicKey.toString(), - programId: this.routerProgramId.toString(), - }); - - const [tokenAdminRegistryPDA, tokenAdminRegistryBump] = - findTokenAdminRegistryPDA(options.tokenMint, this.routerProgramId); - this.logger.debug( - `Token Admin Registry PDA: ${tokenAdminRegistryPDA.toString()} (bump: ${tokenAdminRegistryBump})` - ); - this.logger.trace( - `Token Admin Registry PDA derivation: seeds=["${ - ROUTER_SEEDS.TOKEN_ADMIN_REGISTRY - }", ${options.tokenMint.toString()}], program=${this.routerProgramId.toString()}` - ); - - const [configPDA, configBump] = findConfigPDA(this.routerProgramId); - this.logger.debug( - `Config PDA: ${configPDA.toString()} (bump: ${configBump})` - ); - this.logger.trace( - `Config PDA derivation: seeds=["${ - ROUTER_SEEDS.CONFIG - }"], program=${this.routerProgramId.toString()}` - ); - - // Build accounts - const accounts: TransferAdminRoleTokenAdminRegistryAccounts = { - config: configPDA, - tokenAdminRegistry: tokenAdminRegistryPDA, - mint: options.tokenMint, - authority: signerPublicKey, - }; - this.logger.debug("Transfer admin role accounts:", { - config: accounts.config.toString(), - tokenAdminRegistry: accounts.tokenAdminRegistry.toString(), - mint: accounts.mint.toString(), - authority: accounts.authority.toString(), - }); - - // Build args - const args: TransferAdminRoleTokenAdminRegistryArgs = { - newAdmin: options.newAdmin, - }; - this.logger.debug("Transfer admin role args:", { - newAdmin: args.newAdmin.toString(), - }); - - // Create instruction - this.logger.debug( - "Creating transferAdminRoleTokenAdminRegistry instruction..." - ); - const instruction = transferAdminRoleTokenAdminRegistry( - args, - accounts, - this.routerProgramId - ); - this.logger.debug("Instruction created:", { - programId: instruction.programId.toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((k, i) => ({ - index: i, - pubkey: k.pubkey.toString(), - isSigner: k.isSigner, - isWritable: k.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute transaction - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "transferAdminRole", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info( - `Admin role transfer initiated successfully. Tx signature: ${signature}` - ); - return signature; - } catch (error) { - const enhanceError = createErrorEnhancer(this.logger); - throw enhanceError(error, errorContext); - } - } - - /** - * Sets the pool lookup table for a token. - * - * This configures which token pool should be used for a specific token. - * Only the token administrator can set the pool. - * Setting the lookup table to the zero address effectively delists the token from CCIP. - * - * @param options Configuration options including token mint and lookup table - * @returns Promise resolving to the transaction signature - * @throws Error if the caller is not the administrator or if the transaction fails - */ - async setPool(options: SetPoolOptions): Promise { - const errorContext = { - operation: "setPool", - mint: options.tokenMint.toString(), - lookupTable: options.lookupTable.toString(), - }; - - try { - this.logger.info( - `Setting pool for token ${options.tokenMint.toString()} with lookup table ${options.lookupTable.toString()}` - ); - - // Get signer and derive PDAs - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug("Set pool details:", { - mint: options.tokenMint.toString(), - lookupTable: options.lookupTable.toString(), - writableIndices: options.writableIndices, - signer: signerPublicKey.toString(), - programId: this.routerProgramId.toString(), - }); - - const [tokenAdminRegistryPDA, tokenAdminRegistryBump] = - findTokenAdminRegistryPDA(options.tokenMint, this.routerProgramId); - this.logger.debug( - `Token Admin Registry PDA: ${tokenAdminRegistryPDA.toString()} (bump: ${tokenAdminRegistryBump})` - ); - this.logger.trace( - `Token Admin Registry PDA derivation: seeds=["${ - ROUTER_SEEDS.TOKEN_ADMIN_REGISTRY - }", ${options.tokenMint.toString()}], program=${this.routerProgramId.toString()}` - ); - - const [configPDA, configBump] = findConfigPDA(this.routerProgramId); - this.logger.debug( - `Config PDA: ${configPDA.toString()} (bump: ${configBump})` - ); - this.logger.trace( - `Config PDA derivation: seeds=["${ - ROUTER_SEEDS.CONFIG - }"], program=${this.routerProgramId.toString()}` - ); - - // Build accounts - const accounts: SetPoolAccounts = { - config: configPDA, - tokenAdminRegistry: tokenAdminRegistryPDA, - mint: options.tokenMint, - poolLookuptable: options.lookupTable, - authority: signerPublicKey, - }; - this.logger.debug("Set pool accounts:", { - config: accounts.config.toString(), - tokenAdminRegistry: accounts.tokenAdminRegistry.toString(), - mint: accounts.mint.toString(), - poolLookuptable: accounts.poolLookuptable.toString(), - authority: accounts.authority.toString(), - }); - - const args = { - writableIndexes: Uint8Array.from(options.writableIndices), - }; - this.logger.debug("Set pool args:", { - writableIndexes: options.writableIndices, - }); - - // Create instruction - this.logger.debug("Creating setPool instruction..."); - const instruction = setPool(args, accounts, this.routerProgramId); - this.logger.debug("Instruction created:", { - programId: instruction.programId.toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((k, i) => ({ - index: i, - pubkey: k.pubkey.toString(), - isSigner: k.isSigner, - isWritable: k.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute transaction - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "setPool", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Pool set successfully. Tx signature: ${signature}`); - return signature; - } catch (error) { - const enhanceError = createErrorEnhancer(this.logger); - throw enhanceError(error, errorContext); - } - } - - /** - * Creates an Address Lookup Table (ALT) for a token pool with all necessary addresses. - * - * This method creates and extends an ALT with all the addresses required for CCIP token operations. - * The ALT is essential for efficient cross-chain transactions as it reduces transaction size - * by allowing address references instead of full public keys. - * - * The ALT includes: - * - The lookup table itself - * - Token admin registry PDA - * - Pool program ID - * - Pool configuration PDA - * - Pool token account (ATA) - * - Pool signer PDA - * - Token program ID - * - Token mint - * - Fee billing token config PDA - * - CCIP router pool signer PDA - * - * @param options Configuration options including token mint and program IDs - * @returns Promise resolving to the creation result with signature and ALT details - * @throws Error if the caller doesn't have sufficient SOL or if the transaction fails - */ - async createTokenPoolLookupTable( - options: CreateTokenPoolLookupTableOptions - ): Promise { - const errorContext = { - operation: "createTokenPoolLookupTable", - mint: options.tokenMint.toString(), - poolProgram: options.poolProgramId.toString(), - }; - - try { - this.logger.info( - `Creating token pool lookup table for mint: ${options.tokenMint.toString()}` - ); - - // Get signer and auto-detect token program - const signerPublicKey = this.context.provider.getAddress(); - - this.logger.debug("Auto-detecting token program for mint..."); - const tokenProgramId = await detectTokenProgram( - options.tokenMint, - this.context.provider.connection, - this.logger - ); - - this.logger.debug("Create ALT details:", { - mint: options.tokenMint.toString(), - poolProgram: options.poolProgramId.toString(), - tokenProgram: tokenProgramId.toString(), - feeQuoterProgram: options.feeQuoterProgramId.toString(), - signer: signerPublicKey.toString(), - routerProgram: this.routerProgramId.toString(), - }); - - // Get the current slot for ALT creation - const slot = await this.context.provider.connection.getSlot("finalized"); - this.logger.debug(`Using finalized slot for ALT creation: ${slot}`); - - // Step 1: Create the lookup table - this.logger.debug("Creating Address Lookup Table..."); - const [createInstruction, lookupTableAddress] = - AddressLookupTableProgram.createLookupTable({ - authority: signerPublicKey, - payer: signerPublicKey, - recentSlot: slot, - }); - - this.logger.debug( - `ALT will be created at address: ${lookupTableAddress.toString()}` - ); - this.logger.trace("Create ALT instruction:", { - programId: createInstruction.programId.toString(), - dataLength: createInstruction.data.length, - keyCount: createInstruction.keys.length, - }); - - // Derive all necessary PDAs and addresses - this.logger.debug("Deriving PDAs and addresses for ALT..."); - - // Token Admin Registry PDA - const [tokenAdminRegistryPDA, tokenAdminRegistryBump] = - findTokenAdminRegistryPDA(options.tokenMint, this.routerProgramId); - this.logger.debug( - `Token Admin Registry PDA: ${tokenAdminRegistryPDA.toString()} (bump: ${tokenAdminRegistryBump})` - ); - this.logger.trace( - `Token Admin Registry PDA derivation: seeds=["${ - ROUTER_SEEDS.TOKEN_ADMIN_REGISTRY - }", ${options.tokenMint.toString()}], program=${this.routerProgramId.toString()}` - ); - - // Pool Configuration PDA (using burn-mint pool structure) - const [poolConfigPDA, poolConfigBump] = findBurnMintPoolConfigPDA( - options.tokenMint, - options.poolProgramId - ); - this.logger.debug( - `Pool Config PDA: ${poolConfigPDA.toString()} (bump: ${poolConfigBump})` - ); - this.logger.trace( - `Pool Config PDA derivation: seeds=["${TOKEN_POOL_STATE_SEED}", ${options.tokenMint.toString()}], program=${options.poolProgramId.toString()}` - ); - - // Pool Signer PDA - const [poolSignerPDA, poolSignerBump] = findPoolSignerPDA( - options.tokenMint, - options.poolProgramId - ); - this.logger.debug( - `Pool Signer PDA: ${poolSignerPDA.toString()} (bump: ${poolSignerBump})` - ); - this.logger.trace( - `Pool Signer PDA derivation: seeds=["${TOKEN_POOL_POOL_SIGNER_SEED}", ${options.tokenMint.toString()}], program=${options.poolProgramId.toString()}` - ); - - // Pool Token Account (ATA for pool signer) - const poolTokenAccount = getAssociatedTokenAddressSync( - options.tokenMint, - poolSignerPDA, - true, // allowOwnerOffCurve - tokenProgramId - ); - this.logger.debug( - `Pool Token Account (ATA): ${poolTokenAccount.toString()}` - ); - this.logger.trace( - `Pool Token Account derivation: mint=${options.tokenMint.toString()}, owner=${poolSignerPDA.toString()}, tokenProgram=${tokenProgramId.toString()}` - ); - - // Fee Billing Token Config PDA - const [feeTokenConfigPDA, feeTokenConfigBump] = - findFqBillingTokenConfigPDA( - options.tokenMint, - options.feeQuoterProgramId - ); - this.logger.debug( - `Fee Token Config PDA: ${feeTokenConfigPDA.toString()} (bump: ${feeTokenConfigBump})` - ); - this.logger.trace( - `Fee Token Config PDA derivation: mint=${options.tokenMint.toString()}, program=${options.feeQuoterProgramId.toString()}` - ); - - // CCIP Router Pool Signer PDA (follows dummy script pattern) - const [ccipRouterPoolSignerPDA, ccipRouterPoolSignerBump] = - PublicKey.findProgramAddressSync( - [ - Buffer.from(ROUTER_SEEDS.EXTERNAL_TOKEN_POOLS_SIGNER), - options.poolProgramId.toBuffer(), - ], - this.routerProgramId - ); - this.logger.debug( - `CCIP Router Pool Signer PDA: ${ccipRouterPoolSignerPDA.toString()} (bump: ${ccipRouterPoolSignerBump})` - ); - this.logger.trace( - `CCIP Router Pool Signer PDA derivation: seeds=["${ - ROUTER_SEEDS.EXTERNAL_TOKEN_POOLS_SIGNER - }", ${options.poolProgramId.toString()}], program=${this.routerProgramId.toString()}` - ); - - // Build the addresses array for the lookup table - const baseAddresses = [ - lookupTableAddress, // Index 0: The lookup table itself - tokenAdminRegistryPDA, // Index 1: Token admin registry - options.poolProgramId, // Index 2: Pool program - poolConfigPDA, // Index 3: Pool configuration - poolTokenAccount, // Index 4: Pool token account - poolSignerPDA, // Index 5: Pool signer - tokenProgramId, // Index 6: Token program - options.tokenMint, // Index 7: Token mint - feeTokenConfigPDA, // Index 8: Fee token config - ccipRouterPoolSignerPDA, // Index 9: CCIP router pool signer - ]; - - // Append additional addresses if provided - const addresses = options.additionalAddresses - ? [...baseAddresses, ...options.additionalAddresses] - : baseAddresses; - - this.logger.debug(`ALT will contain ${addresses.length} addresses (${baseAddresses.length} base + ${options.additionalAddresses?.length || 0} additional):`); - addresses.forEach((addr, index) => { - const isAdditional = index >= baseAddresses.length; - const description = isAdditional ? "additional" : "base"; - this.logger.trace(` [${index}]: ${addr.toString()} (${description})`); - }); - - // Step 2: Extend the lookup table with addresses - this.logger.debug("Creating extend ALT instruction..."); - const extendInstruction = AddressLookupTableProgram.extendLookupTable({ - lookupTable: lookupTableAddress, - authority: signerPublicKey, - payer: signerPublicKey, - addresses: addresses, - }); - - this.logger.trace("Extend ALT instruction:", { - programId: extendInstruction.programId.toString(), - dataLength: extendInstruction.data.length, - keyCount: extendInstruction.keys.length, - addressCount: addresses.length, - }); - - // Execute both instructions in a single transaction - this.logger.debug("Executing ALT creation and extension transaction..."); - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "createTokenPoolLookupTable", - }; - - const signature = await executeTransaction( - this.context, - [createInstruction, extendInstruction], - executionOptions - ); - - const result: CreateTokenPoolLookupTableResult = { - signature, - lookupTableAddress, - addresses, - }; - - this.logger.info( - `Token pool lookup table created successfully. ALT address: ${lookupTableAddress.toString()}` - ); - this.logger.info(`Transaction signature: ${signature}`); - this.logger.debug("ALT creation result:", { - lookupTableAddress: result.lookupTableAddress.toString(), - addressCount: result.addresses.length, - }); - - return result; - } catch (error) { - const enhanceError = createErrorEnhancer(this.logger); - throw enhanceError(error, errorContext); - } - } - - /** - * Extends an existing Address Lookup Table (ALT) with additional addresses. - * - * This method adds new addresses to an existing ALT, allowing for more flexible - * transaction composition. The caller must be the authority of the ALT to extend it. - * - * IMPORTANT CONSIDERATIONS: - * - ALTs can hold up to 256 addresses maximum - * - Each extend operation can add approximately 20-30 addresses per transaction - * - You can only extend ALTs where you are the authority - * - Extended addresses will be appended to the end of the existing addresses - * - The ALT must "warm up" for 1 slot before new addresses can be used - * - * @param options Configuration options including ALT address and new addresses - * @returns Promise resolving to the extension result with signature and ALT details - * @throws Error if the caller is not the authority, ALT is frozen, or capacity exceeded - */ - async extendTokenPoolLookupTable( - options: ExtendTokenPoolLookupTableOptions - ): Promise { - const errorContext = { - operation: "extendTokenPoolLookupTable", - lookupTableAddress: options.lookupTableAddress.toString(), - newAddressCount: options.newAddresses.length.toString(), - }; - - try { - this.logger.info( - `Extending lookup table ${options.lookupTableAddress.toString()} with ${ - options.newAddresses.length - } new addresses` - ); - - // Get signer - const signerPublicKey = this.context.provider.getAddress(); - - this.logger.debug("Extend ALT details:", { - lookupTableAddress: options.lookupTableAddress.toString(), - newAddressCount: options.newAddresses.length, - signer: signerPublicKey.toString(), - }); - - // Verify the ALT exists and we have authority - this.logger.debug("Verifying ALT exists and checking authority..."); - const altAccount = - await this.context.provider.connection.getAddressLookupTable( - options.lookupTableAddress - ); - - if (!altAccount.value) { - throw new Error( - `Address Lookup Table not found: ${options.lookupTableAddress.toString()}` - ); - } - - const currentAuthority = altAccount.value.state.authority; - if (!currentAuthority) { - throw new Error( - `ALT has no authority (frozen): ${options.lookupTableAddress.toString()}` - ); - } - - if (!currentAuthority.equals(signerPublicKey)) { - throw new Error( - `You are not the authority of this ALT. Authority: ${currentAuthority.toString()}, Your key: ${signerPublicKey.toString()}` - ); - } - - this.logger.debug( - `ALT verified. Current authority: ${currentAuthority.toString()}` - ); - this.logger.debug( - `Current ALT contains ${altAccount.value.state.addresses.length} addresses` - ); - - // Check if ALT has space for new addresses - const currentAddressCount = altAccount.value.state.addresses.length; - const newAddressCount = options.newAddresses.length; - const totalAfterExtend = currentAddressCount + newAddressCount; - - if (totalAfterExtend > 256) { - throw new Error( - `ALT capacity exceeded. Current: ${currentAddressCount}, Adding: ${newAddressCount}, Total would be: ${totalAfterExtend}, Max: 256` - ); - } - - this.logger.debug( - `ALT capacity check passed: ${currentAddressCount} + ${newAddressCount} = ${totalAfterExtend} / 256` - ); - - // Log the addresses being added - this.logger.debug("New addresses to add:"); - options.newAddresses.forEach((addr, index) => { - this.logger.trace( - ` [${currentAddressCount + index}]: ${addr.toString()}` - ); - }); - - // Create extend instruction - this.logger.debug("Creating extend ALT instruction..."); - const extendInstruction = AddressLookupTableProgram.extendLookupTable({ - lookupTable: options.lookupTableAddress, - authority: signerPublicKey, - payer: signerPublicKey, - addresses: options.newAddresses, - }); - - this.logger.trace("Extend ALT instruction:", { - programId: extendInstruction.programId.toString(), - dataLength: extendInstruction.data.length, - keyCount: extendInstruction.keys.length, - addressCount: options.newAddresses.length, - }); - - // Execute the transaction - this.logger.debug("Executing ALT extension transaction..."); - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "extendTokenPoolLookupTable", - }; - - const signature = await executeTransaction( - this.context, - [extendInstruction], - executionOptions - ); - - const result: ExtendTokenPoolLookupTableResult = { - signature, - lookupTableAddress: options.lookupTableAddress, - newAddresses: options.newAddresses, - totalAddresses: totalAfterExtend, - }; - - this.logger.info( - `Token pool lookup table extended successfully. ALT address: ${options.lookupTableAddress.toString()}` - ); - this.logger.info(`Transaction signature: ${signature}`); - this.logger.debug("ALT extension result:", { - lookupTableAddress: result.lookupTableAddress.toString(), - newAddressCount: result.newAddresses.length, - totalAddresses: result.totalAddresses, - }); - - return result; - } catch (error) { - const enhanceError = createErrorEnhancer(this.logger); - throw enhanceError(error, errorContext); - } - } -} diff --git a/ccip-lib/svm/core/token-manager.ts b/ccip-lib/svm/core/token-manager.ts deleted file mode 100644 index 47c806ab..00000000 --- a/ccip-lib/svm/core/token-manager.ts +++ /dev/null @@ -1,452 +0,0 @@ -/** - * Token Manager Client for SPL Token and Token-2022 Operations - * - * This module provides a high-level client for managing both SPL Token and Token-2022 tokens - * with Metaplex metadata, following the established patterns of the CCIP library. - */ - -import { PublicKey, Connection, Keypair } from "@solana/web3.js"; -import { - TokenCreationUtils, - TokenConfig, - Token2022Config, - SplTokenConfig, - TokenProgram, - TokenCreationResult, - MintResult, - TokenOperationOptions, -} from "../utils/token-creation"; -import { createLogger, LogLevel } from "../utils/logger"; - -/** - * Minimal chain configuration interface for TokenManager - * This avoids importing from ccip-scripts and keeps the library independent - */ -export interface TokenManagerChainConfig { - id: string; - connection: Connection; -} - -/** - * Options for TokenManager initialization - */ -export interface TokenManagerOptions { - /** Logging level */ - logLevel?: LogLevel; - /** Skip transaction preflight checks by default */ - skipPreflight?: boolean; - /** Default transaction commitment level */ - commitment?: "processed" | "confirmed" | "finalized"; -} - -/** - * Extended token configuration with optional overrides for Token-2022 - */ -export interface ExtendedToken2022Config - extends Omit { - /** Metadata URI (optional if using inline metadata) */ - uri?: string; - /** Inline metadata object (alternative to URI) */ - metadata?: { - name: string; - description: string; - image?: string; - external_url?: string; - attributes?: Array<{ - trait_type: string; - value: string | number; - }>; - }; -} - -/** - * Extended token configuration with optional overrides for SPL Token - */ -export interface ExtendedSplTokenConfig - extends Omit { - /** Metadata URI (optional if using inline metadata) */ - uri?: string; - /** Inline metadata object (alternative to URI) */ - metadata?: { - name: string; - description: string; - image?: string; - external_url?: string; - attributes?: Array<{ - trait_type: string; - value: string | number; - }>; - }; -} - -/** - * High-level client for SPL Token and Token-2022 operations - */ -export class TokenManager { - private utils: TokenCreationUtils; - private connection: Connection; - private options: TokenManagerOptions; - private logger: any; - private walletPublicKey: PublicKey; - - constructor( - config: TokenManagerChainConfig, - keypair: Keypair, - options: TokenManagerOptions = {} - ) { - this.connection = config.connection; - this.walletPublicKey = keypair.publicKey; - this.options = { - logLevel: LogLevel.INFO, - skipPreflight: false, - commitment: "confirmed", - ...options, - }; - - // Initialize logger - this.logger = createLogger("token-manager", { - level: this.options.logLevel!, - }); - - // Initialize utilities - this.utils = new TokenCreationUtils( - this.connection, - keypair, - this.options.logLevel! - ); - - this.logger.debug("TokenManager initialized", { - chainId: config.id, - rpcEndpoint: this.connection.rpcEndpoint, - }); - } - - /** - * Create a new Token-2022 token with metadata - */ - async createToken( - config: ExtendedToken2022Config - ): Promise { - this.logger.info("Starting Token-2022 creation with metadata", { - name: config.name, - symbol: config.symbol, - decimals: config.decimals, - initialSupply: config.initialSupply?.toString(), - sellerFeeBasisPoints: config.sellerFeeBasisPoints, - hasUri: !!config.uri, - hasInlineMetadata: !!config.metadata, - }); - - try { - // Validate and prepare configuration - this.logger.debug("Preparing token configuration"); - const tokenConfig = await this.prepareToken2022Config(config); - - this.logger.debug( - "Configuration prepared, delegating to TokenCreationUtils", - { - uri: tokenConfig.uri, - } - ); - - // Create the token - const result = await this.utils.createTokenWithMetadata( - tokenConfig, - this.getOperationOptions() - ); - - this.logger.info("Token creation completed successfully", { - mint: result.mint.toString(), - signature: result.signature, - tokenAccount: result.tokenAccount?.toString(), - hasTokenAccount: !!result.tokenAccount, - }); - - return result; - } catch (error) { - this.logger.error("Failed to create token", { - error: error instanceof Error ? error.message : String(error), - name: config.name, - symbol: config.symbol, - decimals: config.decimals, - }); - throw error; - } - } - - /** - * Create a new SPL Token with metadata - */ - async createSplToken( - config: ExtendedSplTokenConfig - ): Promise { - this.logger.info("Starting SPL Token creation with metadata", { - name: config.name, - symbol: config.symbol, - decimals: config.decimals, - initialSupply: config.initialSupply?.toString(), - sellerFeeBasisPoints: config.sellerFeeBasisPoints, - hasUri: !!config.uri, - hasInlineMetadata: !!config.metadata, - }); - - try { - // Validate and prepare configuration - this.logger.debug("Preparing token configuration"); - const tokenConfig = await this.prepareSplTokenConfig(config); - - this.logger.debug( - "Configuration prepared, delegating to TokenCreationUtils", - { - uri: tokenConfig.uri, - } - ); - - // Create the token - const result = await this.utils.createTokenWithMetadata( - tokenConfig, - this.getOperationOptions() - ); - - this.logger.info("Token creation completed successfully", { - mint: result.mint.toString(), - signature: result.signature, - tokenAccount: result.tokenAccount?.toString(), - hasTokenAccount: !!result.tokenAccount, - }); - - return result; - } catch (error) { - this.logger.error("Failed to create token", { - error: error instanceof Error ? error.message : String(error), - name: config.name, - symbol: config.symbol, - decimals: config.decimals, - }); - throw error; - } - } - - /** - * Mint tokens to a specific recipient (creates ATA if needed) - */ - async mintTokens( - mint: PublicKey, - amount: bigint, - recipient?: PublicKey - ): Promise { - const recipientKey = recipient || this.getDefaultRecipient(); - - this.logger.info("Starting token mint operation", { - mint: mint.toString(), - amount: amount.toString(), - recipient: recipientKey.toString(), - isDefaultRecipient: !recipient, - }); - - try { - this.logger.debug("Delegating to TokenCreationUtils for minting"); - - const result = await this.utils.mintToAssociatedAccount( - mint, - amount, - recipientKey, - undefined, // Use default token program (TOKEN_2022) - this.getOperationOptions() - ); - - this.logger.info("Token mint operation completed successfully", { - signature: result.signature, - amount: result.amount.toString(), - tokenAccount: result.tokenAccount.toString(), - newBalance: result.newBalance, - }); - - return result; - } catch (error) { - this.logger.error("Failed to mint tokens", { - error: error instanceof Error ? error.message : String(error), - mint: mint.toString(), - amount: amount.toString(), - recipient: recipientKey.toString(), - }); - throw error; - } - } - - /** - * Get or create an Associated Token Account - */ - async getOrCreateATA(mint: PublicKey, owner?: PublicKey): Promise { - const ownerKey = owner || this.getDefaultRecipient(); - - this.logger.debug("Starting ATA resolution", { - mint: mint.toString(), - owner: ownerKey.toString(), - isDefaultOwner: !owner, - }); - - try { - this.logger.debug("Delegating to TokenCreationUtils for ATA resolution"); - - const tokenAccount = await this.utils.findOrCreateATA( - mint, - ownerKey, - undefined, // Use default token program (TOKEN_2022) - this.getOperationOptions() - ); - - this.logger.debug("ATA resolution completed successfully", { - tokenAccount: tokenAccount.toString(), - mint: mint.toString(), - owner: ownerKey.toString(), - }); - - return tokenAccount; - } catch (error) { - this.logger.error("Failed to get or create ATA", { - error: error instanceof Error ? error.message : String(error), - mint: mint.toString(), - owner: ownerKey.toString(), - }); - throw error; - } - } - - /** - * Get token balance for an account - */ - async getTokenBalance(tokenAccount: PublicKey): Promise { - this.logger.debug("Starting token balance lookup", { - tokenAccount: tokenAccount.toString(), - }); - - try { - this.logger.debug("Delegating to TokenCreationUtils for balance lookup"); - - const balance = await this.utils.getTokenBalance(tokenAccount); - - this.logger.debug("Token balance lookup completed successfully", { - tokenAccount: tokenAccount.toString(), - balance: balance.toString(), - }); - - return balance; - } catch (error) { - this.logger.error("Failed to get token balance", { - error: error instanceof Error ? error.message : String(error), - tokenAccount: tokenAccount.toString(), - }); - throw error; - } - } - - /** - * Prepare Token-2022 configuration, handling metadata URI generation if needed - */ - private async prepareToken2022Config( - config: ExtendedToken2022Config - ): Promise { - this.logger.trace("Preparing Token-2022 configuration", { - hasUri: !!config.uri, - hasInlineMetadata: !!config.metadata, - }); - - if (config.uri) { - this.logger.debug("Using provided metadata URI", { - uri: config.uri, - }); - - // URI provided, use as-is - return { - name: config.name, - symbol: config.symbol, - uri: config.uri, - decimals: config.decimals, - initialSupply: config.initialSupply, - sellerFeeBasisPoints: config.sellerFeeBasisPoints, - tokenProgram: TokenProgram.TOKEN_2022, - }; - } - - if (config.metadata) { - this.logger.error( - "Inline metadata upload attempted but not implemented", - { - metadata: config.metadata, - } - ); - // Inline metadata provided, we would need to upload to IPFS/Arweave - // For now, we'll require a URI to be provided - throw new Error( - "Inline metadata upload not implemented. Please provide a metadata URI." - ); - } - - this.logger.error("No metadata URI or inline metadata provided"); - throw new Error("Either 'uri' or 'metadata' must be provided"); - } - - /** - * Prepare SPL Token configuration, handling metadata URI generation if needed - */ - private async prepareSplTokenConfig( - config: ExtendedSplTokenConfig - ): Promise { - this.logger.trace("Preparing SPL Token configuration", { - hasUri: !!config.uri, - hasInlineMetadata: !!config.metadata, - }); - - if (config.uri) { - this.logger.debug("Using provided metadata URI", { - uri: config.uri, - }); - - // URI provided, use as-is - return { - name: config.name, - symbol: config.symbol, - uri: config.uri, - decimals: config.decimals, - initialSupply: config.initialSupply, - sellerFeeBasisPoints: config.sellerFeeBasisPoints, - tokenProgram: TokenProgram.SPL_TOKEN, - }; - } - - if (config.metadata) { - this.logger.error( - "Inline metadata upload attempted but not implemented", - { - metadata: config.metadata, - } - ); - // Inline metadata provided, we would need to upload to IPFS/Arweave - // For now, we'll require a URI to be provided - throw new Error( - "Inline metadata upload not implemented. Please provide a metadata URI." - ); - } - - this.logger.error("No metadata URI or inline metadata provided"); - throw new Error("Either 'uri' or 'metadata' must be provided"); - } - - /** - * Get operation options with defaults - */ - private getOperationOptions(): TokenOperationOptions { - return { - skipPreflight: this.options.skipPreflight, - commitment: this.options.commitment, - }; - } - - /** - * Get default recipient (the wallet that initialized this manager) - */ - private getDefaultRecipient(): PublicKey { - return this.walletPublicKey; - } -} diff --git a/ccip-lib/svm/index.ts b/ccip-lib/svm/index.ts index e0336b59..b08d9f1b 100644 --- a/ccip-lib/svm/index.ts +++ b/ccip-lib/svm/index.ts @@ -1,8 +1,6 @@ // Core components export * from "./core/client/accounts"; export * from "./core/client/index"; -export { TokenPoolManager } from "./core/client/tokenpools"; -export { TokenRegistryClient } from "./core/client/tokenregistry"; // Export models with specific names to avoid conflicts export type { @@ -33,31 +31,5 @@ export type { AccountSpec } from "./utils/accounts"; export * from "./bindings/types"; export * from "./bindings/accounts"; -// Token Pool exports -export * from "./tokenpools/abstract"; -export * from "./tokenpools/factory"; -export { BurnMintTokenPoolClient } from "./tokenpools/burnmint"; -export type { - InitChainRemoteConfigOptions, - EditChainRemoteConfigOptions, - RemoteChainConfigResult, -} from "./tokenpools"; - -// Token Creation exports -export * from "./utils/token-creation"; -export * from "./core/token-manager"; -export type { - TokenMetadata, - Token2022Config, - TokenCreationResult, - MintResult, - TokenOperationOptions, -} from "./utils/token-creation"; -export type { - TokenManagerOptions, - ExtendedToken2022Config, - TokenManagerChainConfig, -} from "./core/token-manager"; - // Export version export const SDK_VERSION = "0.1.0"; diff --git a/ccip-lib/svm/tokenpools/abstract.ts b/ccip-lib/svm/tokenpools/abstract.ts deleted file mode 100644 index 9d4d0bdd..00000000 --- a/ccip-lib/svm/tokenpools/abstract.ts +++ /dev/null @@ -1,671 +0,0 @@ -import { Commitment, PublicKey } from "@solana/web3.js"; -import { TokenPoolChainConfigResponse } from "../core/models"; -import { RemoteChainConfiguredEvent } from "./burnmint/events"; - -/** - * Options for controlling Solana transaction execution. - */ -export interface TxOptions { - /** Whether to skip preflight transaction checks */ - skipPreflight?: boolean; - /** Commitment level for preflight checks */ - preflightCommitment?: Commitment; - /** Maximum number of transaction resubmissions */ - maxRetries?: number; - /** Commitment level for getting recent blockhash */ - commitment?: Commitment; - /** Commitment level for transaction confirmation */ - confirmationCommitment?: Commitment; -} - -/** - * Generic configuration fields that should exist on all pool configs - */ -export interface BasePoolConfigFields { - mint: PublicKey; - owner: PublicKey; -} - -/** - * Base token pool information - * - * This creates a union type that can be easily implemented by different pool types - * by extending their config with programId and poolType fields - */ -export interface TokenPoolInfo { - /** Pool program ID */ - programId: PublicKey; - /** Pool type identifier */ - poolType: string; -} - -/** - * Token pool rate limit information - */ -export interface TokenPoolRateLimit { - mint: PublicKey; - outbound: { - capacity: bigint; - rate: bigint; - consumed: bigint; - lastUpdated: bigint; - isEnabled: boolean; - }; - inbound: { - capacity: bigint; - rate: bigint; - consumed: bigint; - lastUpdated: bigint; - isEnabled: boolean; - }; -} - -/** - * Options for creating a token pool - */ -export interface TokenPoolCreateOptions { - /** Initial administrator (defaults to the context provider address) */ - administrator?: PublicKey; - /** Whether the pool should be enabled immediately */ - enabled?: boolean; -} - -/** - * Options for updating a token pool - */ -export interface TokenPoolUpdateOptions { - /** New administrator (if changing) */ - administrator?: PublicKey; - /** Update enabled status */ - enabled?: boolean; -} - -/** - * Result type for chain configuration operations that includes event data - */ -export interface RemoteChainConfigResult { - /** Transaction signature */ - signature: string; - /** Parsed RemoteChainConfigured event data (if parsing succeeds) */ - event?: RemoteChainConfiguredEvent; -} - -/** - * Options for initializing a chain remote configuration - */ -export interface InitChainRemoteConfigOptions { - /** Pool addresses on the remote chain (must be empty for initialization, as required by Rust program) */ - poolAddresses?: string[]; - /** Token address on the remote chain */ - tokenAddress: string; - /** Token decimals on the remote chain */ - decimals: number; - /** Transaction options */ - txOptions?: TxOptions; -} - -/** - * Options for editing a chain remote configuration - */ -export interface EditChainRemoteConfigOptions { - /** Pool addresses on the remote chain */ - poolAddresses: string[]; - /** Token address on the remote chain */ - tokenAddress: string; - /** Token decimals on the remote chain */ - decimals: number; - /** Transaction options */ - txOptions?: TxOptions; -} - -/** - * Options for initializing a burn-mint token pool - */ -export interface BurnMintPoolInitializeOptions { - /** Transaction options */ - txOptions?: TxOptions; -} - -/** - * Configuration for a single rate limit (inbound or outbound) - */ -export interface BurnMintRateLimitConfigOptions { - /** Whether this rate limit direction is enabled */ - enabled: boolean; - /** Maximum token capacity of the bucket (in token's smallest unit) */ - capacity: bigint; - /** Refill rate in tokens per second (in token's smallest unit) */ - rate: bigint; -} - -/** - * Options for setting rate limits for a specific chain in a burn-mint token pool - */ -export interface BurnMintSetRateLimitOptions { - /** Configuration for the inbound rate limit */ - inbound: BurnMintRateLimitConfigOptions; - /** Configuration for the outbound rate limit */ - outbound: BurnMintRateLimitConfigOptions; - /** Transaction options */ - txOptions?: TxOptions; -} - -/** - * Token pool account reader interface - * - * Interface for reading account data for token pools, including chain configurations - * and rate limits. Implementations of this interface should provide access to on-chain - * data without modifying state. - */ -export interface TokenPoolAccountReader { - /** - * Fetch the global configuration for the token pool program - * - * Retrieves the program-wide configuration that applies to all pools, - * including global settings like self-served pool creation permissions. - * - * @returns Global configuration data including version and global settings - * @throws Error if global configuration is not found or not initialized - */ - getGlobalConfigInfo(): Promise; - - /** - * Fetch the base configuration for a token pool - * - * Retrieves the foundational configuration for a specific token mint's pool, - * including ownership information, token details, and general pool settings. - * - * @param mint Token mint address to query - * @returns Pool configuration data including owner, token info, and settings - * @throws Error if pool configuration is not found for the given mint - */ - getPoolConfig(mint: PublicKey): Promise; - - /** - * Fetch chain configurations for a token pool. - * - * Retrieves detailed configuration data for interacting with specific destination chains - * associated with the token pool. This includes information like remote addresses, - * rate limits, and supported features for cross-chain transfers. - * - * Use `getChainConfig` to fetch the configuration for a single destination chain, - * identified by its unique `remoteChainSelector`. - * - * Use `listChainConfigs` to retrieve configurations for multiple destination chains - * by providing an array of `remoteChainSelectors`. This method fetches and decodes - * the raw chain configuration data from on-chain accounts. - * - * @param mint Token mint address identifying the pool. - * @param remoteChainSelector (For getChainConfig) The destination chain selector. - * @param remoteChainSelectors (For listChainConfigs) An array of destination chain selectors. - * @returns (For getChainConfig) Chain configuration data in a user-friendly format. - * @returns (For listChainConfigs) An array of chain configuration data, one for each found selector. - * @throws Error if the configuration is not found for the given mint and selector(s), - * or if an error occurs during retrieval (e.g., empty selectors array for listChainConfigs). - */ - getChainConfig( - mint: PublicKey, - remoteChainSelector: bigint - ): Promise; - - listChainConfigs( - mint: PublicKey, - remoteChainSelectors: bigint[] - ): Promise; - - /** - * Read rate limit configuration for a specific chain - * - * Retrieves the rate limit settings and current usage for a specified chain. - * Rate limits control the maximum amount of tokens that can be transferred - * over a given time period. - * - * @param mint Token mint address to query - * @param chainSelector Blockchain network identifier - * @returns Rate limit information including capacity, rate, current consumption, and timestamp - * @throws Error if chain configuration is not found for the given mint and chain selector - */ - getRateLimitConfigForChain( - mint: PublicKey, - remoteChainSelector: bigint - ): Promise; - - /** - * Read rate limit configurations for multiple chains - * - * Batch retrieval of rate limit settings for multiple chains in a single call. - * This is more efficient than making multiple individual requests when rate limits - * for several chains are needed. - * - * @param mint Token mint address to query - * @param remoteChainSelectors Array of blockchain network identifiers - * @returns Array of rate limit information, one entry per chain selector - * @throws Error if no chain selectors are provided or if an error occurs during retrieval - */ - getRateLimitConfigsForChains( - mint: PublicKey, - remoteChainSelectors: bigint[] - ): Promise; -} - -/** - * Options for transferring admin role (proposing a new owner) - */ -export interface TransferAdminRoleOptions extends TxOptions { - /** PublicKey of the proposed new administrator */ - newAdmin: PublicKey; -} - -/** - * Options for accepting admin role - */ -export interface AcceptAdminRoleOptions extends TxOptions { - // No additional fields required -} - -/** - * Options for setting the router address - */ -export interface SetRouterOptions extends TxOptions { - /** PublicKey of the new router program */ - newRouter: PublicKey; -} - -/** - * Options for appending remote pool addresses - */ -export interface AppendRemotePoolAddressesOptions extends TxOptions { - /** The unique identifier (bigint) of the remote blockchain network */ - remoteChainSelector: bigint; - /** An array of remote pool addresses (0x-hex), stored as raw bytes */ - addresses: string[]; -} - -/** - * Options for deleting a chain configuration - */ -export interface DeleteChainConfigOptions extends TxOptions { - /** The unique identifier (bigint) of the remote chain configuration to delete */ - remoteChainSelector: bigint; -} - -/** - * Options for configuring the allowlist - */ -export interface ConfigureAllowlistOptions extends TxOptions { - /** An array of PublicKeys to add to the allowlist */ - add: PublicKey[]; - /** Whether the allowlist check should be enabled for on-ramp operations */ - enabled: boolean; -} - -/** - * Options for removing from the allowlist - */ -export interface RemoveFromAllowlistOptions extends TxOptions { - /** An array of PublicKeys to remove from the allowlist */ - remove: PublicKey[]; -} - -/** - * Options for initializing state version - */ -export interface InitializeStateVersionOptions extends TxOptions { - // No additional fields required -} - -/** - * Options for updating the global self-served allowed flag - */ -export interface UpdateSelfServedAllowedOptions extends TxOptions { - /** Whether self-served pool creation is allowed */ - selfServedAllowed: boolean; -} - -/** - * Options for updating the global default router - */ -export interface UpdateDefaultRouterOptions extends TxOptions { - /** PublicKey of the new default router program */ - routerAddress: PublicKey; -} - -/** - * Options for updating the global default RMN - */ -export interface UpdateDefaultRmnOptions extends TxOptions { - /** PublicKey of the new default RMN program */ - rmnAddress: PublicKey; -} - -/** - * Options for transferring mint authority to a multisig - */ -export interface TransferMintAuthorityToMultisigOptions extends TxOptions { - /** PublicKey of the new multisig mint authority account */ - newMultisigMintAuthority: PublicKey; -} - -/** - * Abstract interface for token pool clients - */ -export interface TokenPoolClient { - /** - * Get the program ID for this token pool - */ - getProgramId(): PublicKey; - - /** - * Get the global configuration information for the token pool program - * - * Retrieves the program-wide configuration that applies to all pools. - * - * @returns Global configuration data including version and global settings - * @throws Error if global configuration is not found or not initialized - */ - getGlobalConfigInfo(): Promise; - - /** - * Initialize the global configuration for the token pool program. - * - * This must be called once per program deployment before any pools can be initialized. - * Only callable by the program upgrade authority. - * - * @param options Optional transaction execution settings - * @returns A Promise resolving to the transaction signature string - * @throws Error if the caller is not the program upgrade authority or if the transaction fails - */ - initializeGlobalConfig(options?: { txOptions?: TxOptions }): Promise; - - /** - * Get information about the token pool - * @param mint Token mint - */ - getPoolInfo(mint: PublicKey): Promise; - - /** - * Create a token pool for a given mint - * @param mint Token mint - * @param options Creation options - */ - initializePool( - mint: PublicKey, - options: BurnMintPoolInitializeOptions - ): Promise; - - /** - * Initialize a new chain remote configuration for a token pool. - * - * This method creates a new chain configuration for the specified remoteChainSelector. - * The chain configuration must not already exist for this operation to succeed. - * - * Only the current owner can call this method. - * - * @param mint Token mint identifying the pool. - * @param destChainSelector The unique identifier (bigint) of the remote blockchain network. - * @param options Configuration options including remote token address, pool addresses, and decimals. - * @returns A Promise resolving to the transaction signature string. - * @throws Error if the pool doesn't exist, if the chain config already exists, if the caller lacks permissions, or if the transaction fails. - */ - initChainRemoteConfig( - mint: PublicKey, - destChainSelector: bigint, - options: InitChainRemoteConfigOptions - ): Promise; - - /** - * Edit an existing chain remote configuration for a token pool. - * - * This method updates an existing chain configuration for the specified remoteChainSelector. - * The chain configuration must already exist for this operation to succeed. - * - * Only the current owner can call this method. - * - * @param mint Token mint identifying the pool. - * @param destChainSelector The unique identifier (bigint) of the remote blockchain network. - * @param options Configuration options including remote token address, pool addresses, and decimals. - * @returns A Promise resolving to the transaction result with signature and optional event data. - * @throws Error if the pool doesn't exist, if the chain config doesn't exist, if the caller lacks permissions, or if the transaction fails. - */ - editChainRemoteConfig( - mint: PublicKey, - destChainSelector: bigint, - options: EditChainRemoteConfigOptions - ): Promise; - - /** - * Get an existing chain remote configuration for a token pool. - * - * This method retrieves the chain configuration for the specified remoteChainSelector. - * The chain configuration must exist for this operation to succeed. - * - * This is a read-only operation that can be called by anyone. - * - * @param mint Token mint identifying the pool. - * @param destChainSelector The unique identifier (bigint) of the remote blockchain network. - * @returns A Promise resolving to the chain configuration data. - * @throws Error if the pool doesn't exist or if the chain config doesn't exist. - */ - getChainConfig(mint: PublicKey, destChainSelector: bigint): Promise; - - /** - * Sets the rate limits for a specific remote chain configuration within a token pool. - * - * This function configures the maximum capacity and refill rate for both inbound - * (tokens received from the remote chain) and outbound (tokens sent to the - * remote chain) transfers. - * - * Implementations of this interface will handle the specifics of constructing - * and sending the transaction based on the pool type (e.g., burn-mint, lock-release) - * and the provided options. - * - * @param mint The PublicKey of the token mint identifying the pool. - * @param remoteChainSelector The unique identifier (bigint) of the remote blockchain network. - * @param options An object containing the rate limit settings (`inbound`, `outbound`) - * and optionally transaction-specific parameters (`txOptions`). - * Concrete implementations use types extending `TokenPoolSetRateLimitOptions`. - * @returns A Promise resolving to the transaction signature string upon successful execution. - * @throws Error if the pool or chain config doesn't exist, if the caller lacks permissions, - * or if the transaction fails. - */ - setRateLimit( - mint: PublicKey, - remoteChainSelector: bigint, - options: BurnMintSetRateLimitOptions // Use the more specific base options type - ): Promise; - - /** - * Check if a token pool exists - * @param mint Token mint - */ - hasPool(mint: PublicKey): Promise; - - /** - * Check if a token pool has a chain configuration - * @param mint Token mint - * @param destChainSelector Destination chain selector - */ - hasChainConfig(mint: PublicKey, destChainSelector: bigint): Promise; - - /** - * Get the account reader for this pool - */ - getAccountReader(): TokenPoolAccountReader; - - /** - * Propose transferring the admin role for a token pool to a new administrator. - * - * This is the first step in a two-step ownership transfer process. - * The current administrator calls this function to propose a new owner. - * The proposed new owner must then call `acceptAdminRole` to finalize the transfer. - * - * @param mint Token mint identifying the pool. - * @param options Configuration options including the new admin address and transaction settings. - * @returns A Promise resolving to the transaction signature string. - * @throws Error if the caller is not the current owner or if the transaction fails. - */ - transferAdminRole( - mint: PublicKey, - options: TransferAdminRoleOptions - ): Promise; - - /** - * Accept the admin role for a token pool. - * - * This is the second step in a two-step ownership transfer process. - * The proposed new administrator (set via `transferAdminRole`) calls this function - * to finalize the transfer and become the new owner. - * - * @param mint Token mint identifying the pool. - * @param options Optional transaction execution settings. - * @returns A Promise resolving to the transaction signature string. - * @throws Error if the caller is not the proposed owner or if the transaction fails. - */ - acceptAdminRole( - mint: PublicKey, - options?: AcceptAdminRoleOptions - ): Promise; - - /** - * Sets the router address for the token pool. - * - * Only the current owner can call this. - * - * @param mint Token mint identifying the pool. - * @param options Configuration options including the new router address and transaction settings. - * @returns A Promise resolving to the transaction signature string. - */ - setRouter(mint: PublicKey, options: SetRouterOptions): Promise; - - /** - * Appends additional remote pool addresses for a specific chain configuration. - * - * Use this if you need to recognize tokens sent from older versions of a pool on the remote chain. - * Only the current owner can call this. - * - * @param mint Token mint identifying the pool. - * @param options Configuration options including remote chain selector, addresses, and transaction settings. - * @returns A Promise resolving to the transaction signature string. - */ - appendRemotePoolAddresses( - mint: PublicKey, - options: AppendRemotePoolAddressesOptions - ): Promise; - - /** - * Deletes the configuration for a specific remote chain. - * - * This closes the chain config account and returns the rent to the owner. - * Only the current owner can call this. - * - * @param mint Token mint identifying the pool. - * @param options Configuration options including remote chain selector and transaction settings. - * @returns A Promise resolving to the transaction signature string. - */ - deleteChainConfig( - mint: PublicKey, - options: DeleteChainConfigOptions - ): Promise; - - /** - * Configures the sender allowlist for the token pool. - * - * Only the current owner can call this. - * - * @param mint Token mint identifying the pool. - * @param options Configuration options including addresses to add, enabled flag, and transaction settings. - * @returns A Promise resolving to the transaction signature string. - */ - configureAllowlist( - mint: PublicKey, - options: ConfigureAllowlistOptions - ): Promise; - - /** - * Removes addresses from the sender allowlist for the token pool. - * - * Only the current owner can call this. - * - * @param mint Token mint identifying the pool. - * @param options Configuration options including addresses to remove and transaction settings. - * @returns A Promise resolving to the transaction signature string. - */ - removeFromAllowlist( - mint: PublicKey, - options: RemoveFromAllowlistOptions - ): Promise; - - /** - * Initializes the state version of a pool if it's currently uninitialized (version 0). - * - * This is typically only needed for pools created before versioning was introduced. - * This method is permissionless. - * - * @param mint Token mint identifying the pool. - * @param options Optional transaction execution settings. - * @returns A Promise resolving to the transaction signature string. - */ - initializeStateVersion( - mint: PublicKey, - options?: InitializeStateVersionOptions - ): Promise; - - /** - * Updates the global self-served allowed flag for the token pool program. - * - * This controls whether pool creators can initialize pools without being the program upgrade authority. - * Only callable by the program upgrade authority. - * - * @param options Configuration options including the new self-served flag and transaction settings. - * @returns A Promise resolving to the transaction signature string. - * @throws Error if the caller is not the program upgrade authority or if the transaction fails. - */ - updateSelfServedAllowed( - options: UpdateSelfServedAllowedOptions - ): Promise; - - /** - * Updates the global default router address for the token pool program. - * - * This sets the default router that new pools will use unless explicitly overridden. - * Only callable by the program upgrade authority. - * - * @param options Configuration options including the new default router address and transaction settings. - * @returns A Promise resolving to the transaction signature string. - * @throws Error if the caller is not the program upgrade authority or if the transaction fails. - */ - updateDefaultRouter(options: UpdateDefaultRouterOptions): Promise; - - /** - * Updates the global default RMN address for the token pool program. - * - * This sets the default RMN (Risk Management Network) that new pools will use unless explicitly overridden. - * Only callable by the program upgrade authority. - * - * @param options Configuration options including the new default RMN address and transaction settings. - * @returns A Promise resolving to the transaction signature string. - * @throws Error if the caller is not the program upgrade authority or if the transaction fails. - */ - updateDefaultRmn(options: UpdateDefaultRmnOptions): Promise; - - /** - * Transfers the mint authority of a token to a multisig account. - * - * This is a critical security operation for production deployments that ensures - * the mint authority is controlled by a multisig rather than a single key. - * - * Only callable by the program upgrade authority. The new multisig must: - * - Be a valid Token Program or Token-2022 multisig account - * - Include the pool signer as one of its signers - * - Meet specific threshold requirements for security - * - * @param mint Token mint whose authority should be transferred. - * @param options Configuration containing the new multisig address and transaction settings. - * @returns A Promise resolving to the transaction signature string. - * @throws Error if the caller is not the program upgrade authority, if the multisig is invalid, or if the transaction fails. - */ - transferMintAuthorityToMultisig( - mint: PublicKey, - options: TransferMintAuthorityToMultisigOptions - ): Promise; -} diff --git a/ccip-lib/svm/tokenpools/burnmint/accounts.ts b/ccip-lib/svm/tokenpools/burnmint/accounts.ts deleted file mode 100644 index 9ee00410..00000000 --- a/ccip-lib/svm/tokenpools/burnmint/accounts.ts +++ /dev/null @@ -1,591 +0,0 @@ -import { PublicKey } from "@solana/web3.js"; -import { CCIPContext, TokenPoolChainConfigResponse } from "../../core/models"; -import { - TokenPoolAccountReader, - TokenPoolRateLimit, - TokenPoolInfo, -} from "../abstract"; -import { createLogger, Logger, LogLevel } from "../../utils/logger"; -import { createErrorEnhancer } from "../../utils/errors"; -import { - findBurnMintPoolConfigPDA, - findBurnMintPoolChainConfigPDA, - findGlobalConfigPDA, - TOKEN_POOL_GLOBAL_CONFIG_SEED, - TOKEN_POOL_STATE_SEED, - TOKEN_POOL_CHAIN_CONFIG_SEED, -} from "../../utils/pdas/tokenpool"; -import { RemoteAddress } from "../../burnmint-pool-bindings/types"; -import { StateFields, State } from "../../burnmint-pool-bindings/types/State"; -import { - ChainConfigFields, - ChainConfig, -} from "../../burnmint-pool-bindings/types/ChainConfig"; -import { - PoolConfigFields, - PoolConfig, -} from "../../burnmint-pool-bindings/types/PoolConfig"; - -/** - * Global configuration for burn-mint pools - */ -export type BurnMintGlobalConfig = PoolConfig; - -/** - * Burn-mint pool configuration - */ -export type BurnMintPoolConfig = StateFields; - -/** - * Chain configuration for burn-mint pools - */ -export type BurnMintChainConfig = ChainConfig; - -/** - * Complete information for a burn-mint token pool - */ -export interface BurnMintTokenPoolInfo extends TokenPoolInfo { - config: BurnMintPoolConfig; -} - -/** - * Account reader for burn-mint token pools - */ -export class BurnMintTokenPoolAccountReader implements TokenPoolAccountReader { - readonly programId: PublicKey; - private readonly logger: Logger; - - /** - * Creates a new BurnMintTokenPoolAccountReader - * @param context CCIP context - * @param programId Burn-mint token pool program ID - */ - constructor(readonly context: CCIPContext, programId: PublicKey) { - this.logger = - context.logger ?? - createLogger("burnmint-pool-reader", { level: LogLevel.INFO }); - - // Use provided program ID - this.programId = programId; - - this.logger.debug( - `BurnMintTokenPoolAccountReader initialized: programId=${this.programId.toString()}` - ); - } - - /** - * Fetches the global configuration for the burn-mint token pool program - * @see TokenPoolAccountReader.getGlobalConfigInfo - */ - async getGlobalConfigInfo(): Promise { - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.debug( - `Fetching global config for program: ${this.programId.toString()}` - ); - const [pda, bump] = findGlobalConfigPDA(this.programId); - this.logger.info(`šŸ“ Global Config PDA: ${pda.toString()}`); - this.logger.debug(` PDA bump: ${bump}`); - this.logger.trace( - `PDA derivation: seeds=[${TOKEN_POOL_GLOBAL_CONFIG_SEED}], program=${this.programId.toString()}` - ); - - // Get account info to first check if it exists and is owned by our program - this.logger.trace( - `Fetching account info for global config PDA: ${pda.toString()}` - ); - const accountInfo = await this.context.provider.connection.getAccountInfo( - pda - ); - - if (!accountInfo) { - this.logger.debug( - `Global config account not found at PDA: ${pda.toString()}` - ); - throw new Error( - `Global config not found for program: ${this.programId.toString()}` - ); - } - - this.logger.debug( - `Global config account found: owner=${accountInfo.owner.toString()}, dataLength=${ - accountInfo.data.length - }, lamports=${accountInfo.lamports}` - ); - this.logger.trace( - `Account data (first 32 bytes): ${Buffer.from(accountInfo.data) - .subarray(0, 32) - .toString("hex")}` - ); - - // Verify account is owned by our program - if (!accountInfo.owner.equals(this.programId)) { - this.logger.debug( - `Global config account owner mismatch: expected=${this.programId.toString()}, actual=${accountInfo.owner.toString()}` - ); - throw new Error( - `Global config account is not owned by program: ${this.programId.toString()}` - ); - } - - // Decode the account data using borsh and the PoolConfig layout - this.logger.trace( - `Decoding global config data: discriminator=${Buffer.from( - accountInfo.data - ) - .subarray(0, 8) - .toString("hex")}` - ); - const decoded = PoolConfig.layout().decode( - Buffer.from(accountInfo.data).subarray(8) - ); // Skip 8-byte discriminator - this.logger.trace( - `Raw decoded global config data: version=${decoded.version}` - ); - const globalConfig = PoolConfig.fromDecoded(decoded); - - if (!globalConfig) { - throw new Error( - `Failed to decode global config for program: ${this.programId.toString()}` - ); - } - - this.logger.debug("Successfully decoded global config:", { - version: globalConfig.version, - selfServedAllowed: globalConfig.self_served_allowed, - }); - this.logger.trace("Complete global config details:", globalConfig); - - return globalConfig; - } catch (error) { - throw enhanceError(error, { - operation: "getGlobalConfigInfo", - programId: this.programId.toString(), - }); - } - } - - /** - * Fetches a burn-mint pool config account - * @see TokenPoolAccountReader.getPoolConfig - */ - async getPoolConfig(mint: PublicKey): Promise { - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.debug( - `Fetching burn-mint pool config for mint: ${mint.toString()}` - ); - const [pda, bump] = findBurnMintPoolConfigPDA(mint, this.programId); - this.logger.info(`šŸ“ Pool Config PDA: ${pda.toString()}`); - this.logger.debug(` PDA bump: ${bump}`); - this.logger.trace( - `PDA derivation: seeds=[${TOKEN_POOL_STATE_SEED}, ${mint.toString()}], program=${this.programId.toString()}` - ); - - // Get account info to first check if it exists and is owned by our program - this.logger.trace(`Fetching account info for PDA: ${pda.toString()}`); - const accountInfo = await this.context.provider.connection.getAccountInfo( - pda - ); - - if (!accountInfo) { - this.logger.debug(`Account not found at PDA: ${pda.toString()}`); - throw new Error( - `Burn-mint pool config not found for mint: ${mint.toString()}` - ); - } - - this.logger.debug( - `Account found: owner=${accountInfo.owner.toString()}, dataLength=${ - accountInfo.data.length - }, lamports=${accountInfo.lamports}` - ); - this.logger.trace( - `Account data (first 32 bytes): ${Buffer.from(accountInfo.data) - .subarray(0, 32) - .toString("hex")}` - ); - - // Verify account is owned by our program - if (!accountInfo.owner.equals(this.programId)) { - this.logger.debug( - `Account owner mismatch: expected=${this.programId.toString()}, actual=${accountInfo.owner.toString()}` - ); - throw new Error( - `Account is not owned by program: ${this.programId.toString()}` - ); - } - - // Decode the account data using borsh and the State layout - this.logger.trace( - `Decoding account data: discriminator=${Buffer.from(accountInfo.data) - .subarray(0, 8) - .toString("hex")}` - ); - const decoded = State.layout().decode( - Buffer.from(accountInfo.data).subarray(8) - ); // Skip 8-byte discriminator - this.logger.trace(`Raw decoded data: version=${decoded.version}`); - const poolConfig = State.fromDecoded(decoded); - - if (!poolConfig) { - throw new Error( - `Failed to decode pool config for mint: ${mint.toString()}` - ); - } - - this.logger.debug("Successfully decoded pool config:", { - version: poolConfig.version, - mint: poolConfig.config.mint.toString(), - owner: poolConfig.config.owner.toString(), - decimals: poolConfig.config.decimals, - router: poolConfig.config.router.toString(), - }); - this.logger.trace("Complete pool config details:", { - version: poolConfig.version, - tokenProgram: poolConfig.config.tokenProgram.toString(), - mint: poolConfig.config.mint.toString(), - decimals: poolConfig.config.decimals, - poolSigner: poolConfig.config.poolSigner.toString(), - poolTokenAccount: poolConfig.config.poolTokenAccount.toString(), - owner: poolConfig.config.owner.toString(), - proposedOwner: poolConfig.config.proposedOwner.toString(), - rateLimitAdmin: poolConfig.config.rateLimitAdmin.toString(), - routerOnrampAuthority: - poolConfig.config.routerOnrampAuthority.toString(), - router: poolConfig.config.router.toString(), - rebalancer: poolConfig.config.rebalancer.toString(), - canAcceptLiquidity: poolConfig.config.canAcceptLiquidity, - listEnabled: poolConfig.config.listEnabled, - allowListLength: poolConfig.config.allowList.length, - rmnRemote: poolConfig.config.rmnRemote.toString(), - }); - - return poolConfig; - } catch (error) { - throw enhanceError(error, { - operation: "getPoolConfig", - mint: mint.toString(), - programId: this.programId.toString(), - }); - } - } - - /** - * Fetches a chain configuration for a burn-mint token pool - * @see TokenPoolAccountReader.getChainConfig - * @param mint Token mint address to query - * @param remoteChainSelector Remote chain selector - * @returns Chain configuration in user-friendly format - */ - async getChainConfig( - mint: PublicKey, - remoteChainSelector: bigint - ): Promise { - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.debug( - `Fetching chain config for mint: ${mint.toString()}, chain: ${remoteChainSelector.toString()}` - ); - const [pda, bump] = findBurnMintPoolChainConfigPDA( - remoteChainSelector, - mint, - this.programId - ); - this.logger.info(`šŸ“ Chain Config PDA: ${pda.toString()}`); - this.logger.debug(` PDA bump: ${bump}`); - this.logger.trace( - `PDA derivation: seeds=[${TOKEN_POOL_CHAIN_CONFIG_SEED}, ${remoteChainSelector.toString()}, ${mint.toString()}], program=${this.programId.toString()}` - ); - - // Get account info to first check if it exists and is owned by our program - const accountInfo = await this.context.provider.connection.getAccountInfo( - pda - ); - - if (!accountInfo) { - throw new Error( - `Chain config not found for mint: ${mint.toString()}, chain: ${remoteChainSelector.toString()}` - ); - } - - // Verify account is owned by our program - if (!accountInfo.owner.equals(this.programId)) { - throw new Error( - `Account for selector ${remoteChainSelector.toString()} is not owned by program: ${this.programId.toString()}` - ); - } - - // Decode the account data using borsh and the ChainConfig layout - const decoded = ChainConfig.layout().decode( - Buffer.from(accountInfo.data).subarray(8) - ); // Skip 8-byte discriminator - const chainConfigAccount = ChainConfig.fromDecoded(decoded); - - if (!chainConfigAccount) { - throw new Error( - `Failed to decode chain config for mint: ${mint.toString()}, chain: ${remoteChainSelector.toString()}` - ); - } - - this.logger.trace("Retrieved raw chain config:", { - decimals: chainConfigAccount.base.remote.decimals, - tokenAddress: - chainConfigAccount.base.remote.tokenAddress.address.toString(), - poolAddressesCount: chainConfigAccount.base.remote.poolAddresses.length, - // Rate limit info - inboundRateLimit: { - enabled: chainConfigAccount.base.inboundRateLimit.cfg.enabled, - capacity: - chainConfigAccount.base.inboundRateLimit.cfg.capacity.toString(), - }, - outboundRateLimit: { - enabled: chainConfigAccount.base.outboundRateLimit.cfg.enabled, - capacity: - chainConfigAccount.base.outboundRateLimit.cfg.capacity.toString(), - }, - }); - - // Format and log the response - const formattedConfig = this.formatChainConfig(chainConfigAccount, pda); - this.logger.trace("Formatted chain config response:", { - address: formattedConfig.address, - decimals: formattedConfig.base.decimals, - tokenAddress: formattedConfig.base.tokenAddress.address, - poolAddressesCount: formattedConfig.base.poolAddresses.length, - inboundRateLimit: { - isEnabled: formattedConfig.base.inboundRateLimit.isEnabled, - capacity: formattedConfig.base.inboundRateLimit.capacity, - rate: formattedConfig.base.inboundRateLimit.rate, - lastTxTimestamp: - formattedConfig.base.inboundRateLimit.lastTxTimestamp, - currentBucketValue: - formattedConfig.base.inboundRateLimit.currentBucketValue, - }, - outboundRateLimit: { - isEnabled: formattedConfig.base.outboundRateLimit.isEnabled, - capacity: formattedConfig.base.outboundRateLimit.capacity, - rate: formattedConfig.base.outboundRateLimit.rate, - lastTxTimestamp: - formattedConfig.base.outboundRateLimit.lastTxTimestamp, - currentBucketValue: - formattedConfig.base.outboundRateLimit.currentBucketValue, - }, - }); - - return formattedConfig; - } catch (error) { - throw enhanceError(error, { - operation: "getChainConfig", - mint: mint.toString(), - remoteChainSelector: remoteChainSelector.toString(), - programId: this.programId.toString(), - }); - } - } - - /** - * Converts a ChainConfig from Anchor bindings to a user-friendly format - * @param chainConfigAccount The chain config account from Anchor bindings - * @param accountAddress The public key of the chain config account - * @returns A user-friendly representation of the chain config - * @private Internal helper method - */ - private formatChainConfig( - chainConfigAccount: ChainConfigFields, - accountAddress: PublicKey - ): TokenPoolChainConfigResponse { - return { - address: accountAddress.toString(), - base: { - decimals: chainConfigAccount.base.remote.decimals, - poolAddresses: chainConfigAccount.base.remote.poolAddresses.map( - (addr: RemoteAddress) => ({ - address: Buffer.from(addr.address).toString("hex"), - }) - ), - tokenAddress: { - address: Buffer.from( - chainConfigAccount.base.remote.tokenAddress.address - ).toString("hex"), - }, - inboundRateLimit: { - isEnabled: chainConfigAccount.base.inboundRateLimit.cfg.enabled, - capacity: BigInt( - chainConfigAccount.base.inboundRateLimit.cfg.capacity.toString() - ), - rate: BigInt( - chainConfigAccount.base.inboundRateLimit.cfg.rate.toString() - ), - lastTxTimestamp: BigInt( - chainConfigAccount.base.inboundRateLimit.lastUpdated.toString() - ), - currentBucketValue: BigInt( - chainConfigAccount.base.inboundRateLimit.tokens.toString() - ), - }, - outboundRateLimit: { - isEnabled: chainConfigAccount.base.outboundRateLimit.cfg.enabled, - capacity: BigInt( - chainConfigAccount.base.outboundRateLimit.cfg.capacity.toString() - ), - rate: BigInt( - chainConfigAccount.base.outboundRateLimit.cfg.rate.toString() - ), - lastTxTimestamp: BigInt( - chainConfigAccount.base.outboundRateLimit.lastUpdated.toString() - ), - currentBucketValue: BigInt( - chainConfigAccount.base.outboundRateLimit.tokens.toString() - ), - }, - }, - }; - } - - /** - * Implementation of the TokenPoolAccountReader interface - * Returns rate limit configuration for a specific chain - * @see TokenPoolAccountReader.getRateLimitConfigForChain - */ - async getRateLimitConfigForChain( - mint: PublicKey, - remoteChainSelector: bigint - ): Promise { - try { - // Get the chain config for the specified selector - const chainConfig = await this.getChainConfig(mint, remoteChainSelector); - - // Return rate limits with both inbound and outbound information - // This maintains interface compatibility while adding extra information - return { - mint, - outbound: { - capacity: chainConfig.base.outboundRateLimit.capacity, - rate: chainConfig.base.outboundRateLimit.rate, - consumed: chainConfig.base.outboundRateLimit.currentBucketValue, - lastUpdated: chainConfig.base.outboundRateLimit.lastTxTimestamp, - isEnabled: chainConfig.base.outboundRateLimit.isEnabled, - }, - inbound: { - capacity: chainConfig.base.inboundRateLimit.capacity, - rate: chainConfig.base.inboundRateLimit.rate, - consumed: chainConfig.base.inboundRateLimit.currentBucketValue, - lastUpdated: chainConfig.base.inboundRateLimit.lastTxTimestamp, - isEnabled: chainConfig.base.inboundRateLimit.isEnabled, - }, - }; - } catch (error) { - this.logger.error( - `Failed to get rate limit for chain ${remoteChainSelector.toString()}: ${error}` - ); - throw error; - } - } - - /** - * Implementation of the TokenPoolAccountReader interface - * Returns rate limit configurations for multiple chains - * @see TokenPoolAccountReader.getRateLimitConfigsForChains - */ - async getRateLimitConfigsForChains( - mint: PublicKey, - remoteChainSelectors: bigint[] - ): Promise { - if (remoteChainSelectors.length === 0) { - throw new Error("Chain selectors must be provided"); - } - - try { - // Get chain configs for the specified selectors - const chainConfigs = await this.listChainConfigs( - mint, - remoteChainSelectors - ); - - // Map chain configs to rate limits - return chainConfigs.map((chainConfig) => ({ - mint, - outbound: { - capacity: chainConfig.base.outboundRateLimit.capacity, - rate: chainConfig.base.outboundRateLimit.rate, - consumed: chainConfig.base.outboundRateLimit.currentBucketValue, - lastUpdated: chainConfig.base.outboundRateLimit.lastTxTimestamp, - isEnabled: chainConfig.base.outboundRateLimit.isEnabled, - }, - inbound: { - capacity: chainConfig.base.inboundRateLimit.capacity, - rate: chainConfig.base.inboundRateLimit.rate, - consumed: chainConfig.base.inboundRateLimit.currentBucketValue, - lastUpdated: chainConfig.base.inboundRateLimit.lastTxTimestamp, - isEnabled: chainConfig.base.inboundRateLimit.isEnabled, - }, - })); - } catch (error) { - this.logger.error(`Failed to get rate limits for chains: ${error}`); - throw error; - } - } - - /** - * Helper method to list chain configurations for a token mint - * @see TokenPoolAccountReader.listChainConfigs - */ - async listChainConfigs( - mint: PublicKey, - remoteChainSelectors: bigint[] = [] - ): Promise { - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.debug(`Listing chain configs for mint: ${mint.toString()}`); - - // Validate that chain selectors are provided - if (!remoteChainSelectors || remoteChainSelectors.length === 0) { - throw new Error("Chain selectors array cannot be empty"); - } - - this.logger.debug( - `Checking ${remoteChainSelectors.length} chain selectors` - ); - - const chainConfigs: TokenPoolChainConfigResponse[] = []; - - // Fetch chain configs for each selector using getChainConfig - for (const remoteChainSelector of remoteChainSelectors) { - try { - const chainConfig = await this.getChainConfig( - mint, - remoteChainSelector - ); - chainConfigs.push(chainConfig); - this.logger.trace( - `Found chain config for mint ${mint.toString()} with selector ${remoteChainSelector.toString()}` - ); - } catch (error) { - // Log error but continue to next selector - this.logger.trace( - `Error checking chain config for selector ${remoteChainSelector.toString()}: ${error}` - ); - } - } - - this.logger.info( - `Found ${ - chainConfigs.length - } chain configs for mint: ${mint.toString()}` - ); - - return chainConfigs; - } catch (error) { - throw enhanceError(error, { - operation: "listChainConfigs", - mint: mint.toString(), - programId: this.programId.toString(), - }); - } - } -} diff --git a/ccip-lib/svm/tokenpools/burnmint/client.ts b/ccip-lib/svm/tokenpools/burnmint/client.ts deleted file mode 100644 index 3ffb29eb..00000000 --- a/ccip-lib/svm/tokenpools/burnmint/client.ts +++ /dev/null @@ -1,2542 +0,0 @@ -import { - PublicKey, - SystemProgram, - TransactionInstruction, -} from "@solana/web3.js"; -import { CCIPContext } from "../../core/models"; -import { - BurnMintPoolInitializeOptions, - BurnMintSetRateLimitOptions, - TokenPoolAccountReader, - TokenPoolClient, - TransferAdminRoleOptions, - AcceptAdminRoleOptions, - SetRouterOptions, - AppendRemotePoolAddressesOptions, - DeleteChainConfigOptions, - ConfigureAllowlistOptions, - RemoveFromAllowlistOptions, - InitializeStateVersionOptions, - InitChainRemoteConfigOptions, - EditChainRemoteConfigOptions, - RemoteChainConfigResult, - UpdateSelfServedAllowedOptions, - UpdateDefaultRouterOptions, - UpdateDefaultRmnOptions, - TransferMintAuthorityToMultisigOptions, -} from "../abstract"; -import { createLogger, Logger, LogLevel } from "../../utils/logger"; -import { createErrorEnhancer } from "../../utils/errors"; -import { padTo32Bytes } from "../../utils/conversion"; -import { - executeTransaction, - extractTxOptions, - TransactionExecutionOptions, -} from "../../utils/transaction"; -import { - BurnMintTokenPoolAccountReader, - BurnMintTokenPoolInfo, -} from "./accounts"; -import { - findBurnMintPoolConfigPDA, - findBurnMintPoolChainConfigPDA, - findProgramDataPDA, - findGlobalConfigPDA, - findPoolSignerPDA, - TOKEN_POOL_STATE_SEED, - TOKEN_POOL_CHAIN_CONFIG_SEED, - TOKEN_POOL_GLOBAL_CONFIG_SEED, -} from "../../utils/pdas/tokenpool"; -import { - initialize, - InitializeAccounts, - initGlobalConfig, - InitGlobalConfigArgs, - InitGlobalConfigAccounts, - initChainRemoteConfig, - InitChainRemoteConfigAccounts, - InitChainRemoteConfigArgs, - setChainRateLimit, - SetChainRateLimitAccounts, - SetChainRateLimitArgs, - transferOwnership, - TransferOwnershipAccounts, - TransferOwnershipArgs, - acceptOwnership, - AcceptOwnershipAccounts, - setRouter, - SetRouterArgs, - SetRouterAccounts, - initializeStateVersion, - InitializeStateVersionAccounts, - InitializeStateVersionArgs, - configureAllowList, - ConfigureAllowListArgs, - ConfigureAllowListAccounts, - removeFromAllowList, - RemoveFromAllowListArgs, - RemoveFromAllowListAccounts, - appendRemotePoolAddresses, - AppendRemotePoolAddressesArgs, - AppendRemotePoolAddressesAccounts, - deleteChainConfig, - DeleteChainConfigAccounts, - editChainRemoteConfig, - EditChainRemoteConfigArgs, - EditChainRemoteConfigAccounts, - DeleteChainConfigArgs, - updateSelfServedAllowed, - UpdateSelfServedAllowedArgs, - UpdateSelfServedAllowedAccounts, - updateDefaultRouter, - UpdateDefaultRouterArgs, - UpdateDefaultRouterAccounts, - updateDefaultRmn, - UpdateDefaultRmnArgs, - UpdateDefaultRmnAccounts, - transferMintAuthorityToMultisig, - TransferMintAuthorityToMultisigAccounts, -} from "../../burnmint-pool-bindings/instructions"; -import { - RemoteConfig, - RemoteAddress, - RateLimitConfig, -} from "../../burnmint-pool-bindings/types"; -import { BN } from "@coral-xyz/anchor"; -import { - createBurnMintPoolEventParser, - RemoteChainConfiguredEvent, - BurnMintPoolEventParser, -} from "./events"; - -/** - * Implementation of TokenPoolClient for burn-mint token pools - */ -export class BurnMintTokenPoolClient implements TokenPoolClient { - private readonly accountReader: BurnMintTokenPoolAccountReader; - private readonly logger: Logger; - private readonly programId: PublicKey; - private readonly eventParser: BurnMintPoolEventParser; - - /** - * Creates a new BurnMintTokenPoolClient - * @param context CCIP context - * @param programId Burn-mint token pool program ID - */ - constructor(readonly context: CCIPContext, programId: PublicKey) { - this.logger = - context.logger ?? - createLogger("burnmint-pool-client", { level: LogLevel.INFO }); - this.programId = programId; - this.accountReader = new BurnMintTokenPoolAccountReader( - context, - this.programId - ); - - // Create event parser (no IDL required for simplified parsing) - this.eventParser = createBurnMintPoolEventParser(programId, context); - this.logger.debug("Event parsing enabled using manual parsing"); - - this.logger.debug( - `BurnMintTokenPoolClient initialized: programId=${this.getProgramId().toString()}` - ); - } - - /** @inheritDoc */ - getProgramId(): PublicKey { - return this.programId; - } - - /** @inheritDoc */ - getAccountReader(): TokenPoolAccountReader { - return this.accountReader; - } - - /** @inheritDoc */ - async getGlobalConfigInfo(): Promise { - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.debug("Getting global config info"); - this.logger.debug(`Query details:`, { - programId: this.getProgramId().toString(), - }); - - // Use the account reader to get the global config - const globalConfig = await this.accountReader.getGlobalConfigInfo(); - this.logger.debug(`Global config retrieved successfully:`, { - version: globalConfig.version, - selfServedAllowed: globalConfig.self_served_allowed, - }); - - // Return in a format similar to getPoolInfo - return { - programId: this.getProgramId(), - config: globalConfig, - configType: "global", - }; - } catch (error) { - throw enhanceError(error, { - operation: "getGlobalConfigInfo", - }); - } - } - - /** @inheritDoc */ - async getPoolInfo(mint: PublicKey): Promise { - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.debug(`Fetching pool info for mint: ${mint.toString()}`); - this.logger.debug(`Query details:`, { - mint: mint.toString(), - programId: this.getProgramId().toString(), - }); - - // Get the pool config - const poolConfig = await this.accountReader.getPoolConfig(mint); - this.logger.debug(`Pool config retrieved successfully:`, { - version: poolConfig.version, - owner: poolConfig.config.owner.toString(), - decimals: poolConfig.config.decimals, - router: poolConfig.config.router.toString(), - }); - - // Convert to BurnMintTokenPoolInfo - return { - programId: this.getProgramId(), - config: poolConfig, - poolType: "burn-mint", - }; - } catch (error) { - throw enhanceError(error, { - operation: "getPoolInfo", - mint: mint.toString(), - }); - } - } - - /** - * Initializes the global configuration for the burn-mint token pool program. - * This must be called once per program deployment before any pools can be initialized. - * Only callable by the program upgrade authority. - */ - async initializeGlobalConfig(options?: { txOptions?: any }): Promise { - const errorContext = { - operation: "initializeGlobalConfig", - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Initializing global config for burn-mint token pool program` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Signer: ${signerPublicKey.toString()}`); - this.logger.debug(`Program ID: ${this.getProgramId().toString()}`); - - // Find the global config PDA - const [globalConfigPDA, globalConfigBump] = findGlobalConfigPDA( - this.getProgramId() - ); - this.logger.debug( - `Global config PDA: ${globalConfigPDA.toString()} (bump: ${globalConfigBump})` - ); - this.logger.trace( - `Global config PDA derivation: seeds=[${TOKEN_POOL_GLOBAL_CONFIG_SEED}], program=${this.getProgramId().toString()}` - ); - - // Find program data PDA - const [programDataPDA, programDataBump] = findProgramDataPDA( - this.getProgramId() - ); - this.logger.debug( - `Program data PDA: ${programDataPDA.toString()} (bump: ${programDataBump})` - ); - this.logger.trace( - `Program data PDA derivation: program=${this.getProgramId().toString()}` - ); - - const args: InitGlobalConfigArgs = { - routerAddress: this.context.config.ccipRouterProgramId, - rmnAddress: this.context.config.rmnRemoteProgramId, - }; - - this.logger.debug("Init global config args:", { - routerAddress: this.context.config.ccipRouterProgramId.toString(), - rmnAddress: this.context.config.rmnRemoteProgramId.toString(), - }); - - // Build the accounts for the init_global_config instruction - const accounts: InitGlobalConfigAccounts = { - config: globalConfigPDA, - authority: signerPublicKey, - systemProgram: SystemProgram.programId, - program: this.getProgramId(), - programData: programDataPDA, - }; - - // Log all accounts being used for debugging - this.logger.debug("Initialize global config accounts:", { - config: globalConfigPDA.toString(), - authority: signerPublicKey.toString(), - system_program: SystemProgram.programId.toString(), - program: this.getProgramId().toString(), - program_data: programDataPDA.toString(), - }); - - // Create the instruction using the imported builder (no args needed) - this.logger.debug("Creating init_global_config instruction..."); - const instruction = initGlobalConfig(args, accounts, this.getProgramId()); - - // Log instruction details - this.logger.debug("Initialize global config instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((key, index) => ({ - index, - pubkey: key.pubkey.toString(), - isSigner: key.isSigner, - isWritable: key.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "initializeGlobalConfig", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Global config initialized: ${signature}`); - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async initializePool( - mint: PublicKey, - options: BurnMintPoolInitializeOptions - ): Promise { - const errorContext = { - operation: "initializePool", - mint: mint.toString(), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Initializing burn-mint pool for mint: ${mint.toString()}` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Pool initialization details:`); - this.logger.debug(` Mint: ${mint.toString()}`); - this.logger.debug(` Signer: ${signerPublicKey.toString()}`); - this.logger.debug(` Program ID: ${this.getProgramId().toString()}`); - - // Find the pool config PDA (state) - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - mint, - this.getProgramId() - ); - this.logger.info(`šŸ“ Pool State PDA: ${statePDA.toString()}`); - this.logger.debug(` State PDA bump: ${stateBump}`); - this.logger.trace( - ` State PDA derivation: seeds=[${TOKEN_POOL_STATE_SEED}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Find program data PDA - const [programDataPDA, programDataBump] = findProgramDataPDA( - this.getProgramId() - ); - this.logger.debug( - ` Program data PDA: ${programDataPDA.toString()} (bump: ${programDataBump})` - ); - - // Find the global config PDA - const [globalConfigPDA, globalConfigBump] = findGlobalConfigPDA( - this.getProgramId() - ); - this.logger.debug( - ` Global config PDA: ${globalConfigPDA.toString()} (bump: ${globalConfigBump})` - ); - - // Build the accounts for the initialize instruction - const accounts: InitializeAccounts = { - state: statePDA, - mint, - authority: signerPublicKey, - systemProgram: SystemProgram.programId, - program: this.getProgramId(), - programData: programDataPDA, - config: globalConfigPDA, - }; - - // Log all accounts being used for debugging - this.logger.debug("Initialize pool accounts:", { - state: statePDA.toString(), - mint: mint.toString(), - authority: signerPublicKey.toString(), - system_program: SystemProgram.programId.toString(), - program: this.getProgramId().toString(), - program_data: programDataPDA.toString(), - config: globalConfigPDA.toString(), - }); - - // Log all args being used for debugging - this.logger.debug("Initialize pool args:", { - router: this.context.config.ccipRouterProgramId.toString(), - rmn_remote: this.context.config.rmnRemoteProgramId.toString(), - }); - - // Create the instruction using the imported builder - this.logger.debug("Creating initialize instruction..."); - const instruction = initialize(accounts, this.getProgramId()); - - // Log instruction details - this.logger.debug("Initialize instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((key, index) => ({ - index, - pubkey: key.pubkey.toString(), - isSigner: key.isSigner, - isWritable: key.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "initializePool", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Burn-mint pool initialized: ${signature}`); - - // Derive pool signer PDA for the summary - const [poolSignerPDA] = findPoolSignerPDA(mint, this.getProgramId()); - - // Log important addresses for reference - this.logger.info(`\nšŸŽÆ Pool Initialization Summary:`); - this.logger.info(` Token Mint: ${mint.toString()}`); - this.logger.info(` Pool State PDA: ${statePDA.toString()}`); - this.logger.info(` Pool Signer PDA: ${poolSignerPDA.toString()}`); - this.logger.info( - ` Program ID: ${this.getProgramId().toString()}` - ); - this.logger.info(` Transaction: ${signature}`); - - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async initChainRemoteConfig( - mint: PublicKey, - remoteChainSelector: bigint, - options: InitChainRemoteConfigOptions - ): Promise { - const errorContext = { - operation: "initChainRemoteConfig", - mint: mint.toString(), - destChainSelector: remoteChainSelector.toString(), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Initializing chain remote config for chain ${remoteChainSelector.toString()} on mint: ${mint.toString()}` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Init chain remote config details:`, { - mint: mint.toString(), - remoteChainSelector: remoteChainSelector.toString(), - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Verify pool exists (getPoolConfig will throw if not found) - const poolConfig = await this.accountReader.getPoolConfig(mint); - this.logger.debug(`Current owner: ${poolConfig.config.owner.toString()}`); - - // Check if signer is owner - if (!poolConfig.config.owner.equals(signerPublicKey)) { - throw new Error(`Signer is not the owner of the pool`); - } - - // Verify chain config does NOT exist (this is an init operation) - try { - await this.accountReader.getChainConfig(mint, remoteChainSelector); - throw new Error( - `Chain config already exists for chain ${remoteChainSelector.toString()}. Use editChainRemoteConfig instead.` - ); - } catch (error) { - if ( - error instanceof Error && - error.message.includes("already exists") - ) { - throw error; // Re-throw our specific error - } - // Expected error - chain config doesn't exist, which is what we want - this.logger.debug( - `Chain config does not exist - proceeding with initialization` - ); - } - - // Find the chain config PDA - const [chainConfigPDA, chainConfigBump] = findBurnMintPoolChainConfigPDA( - remoteChainSelector, - mint, - this.getProgramId() - ); - this.logger.debug( - `Chain config PDA: ${chainConfigPDA.toString()} (bump: ${chainConfigBump})` - ); - this.logger.trace( - `Chain config PDA derivation: seeds=[${TOKEN_POOL_CHAIN_CONFIG_SEED}, ${remoteChainSelector.toString()}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Find the state PDA - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - mint, - this.getProgramId() - ); - this.logger.debug( - `State PDA: ${statePDA.toString()} (bump: ${stateBump})` - ); - this.logger.trace( - `State PDA derivation: seeds=[${TOKEN_POOL_STATE_SEED}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // For initialization, pool addresses MUST be empty (Rust program requirement) - // Create RemoteAddresses from the provided addresses (if any) - // Pool addresses use raw bytes (typically 20 bytes for Ethereum addresses) - const remotePoolAddresses = (options.poolAddresses || []) - .filter((addr) => addr && addr.trim() !== "") // Filter out empty strings - .map((addr) => { - const buffer = Buffer.from(addr, "hex"); - // No padding required for pool addresses - use raw bytes - return new RemoteAddress({ address: buffer }); - }); - this.logger.debug( - `Converted ${remotePoolAddresses.length} pool addresses` - ); - - // Validate and transform token address - if (!options.tokenAddress) { - throw new Error("Token address must be provided"); - } - // Strip 0x prefix if present - const cleanTokenAddress = options.tokenAddress.startsWith("0x") - ? options.tokenAddress.slice(2) - : options.tokenAddress; - const rawTokenAddressBuffer = Buffer.from(cleanTokenAddress, "hex"); - // Token addresses need to be padded to 32 bytes (Ethereum-style) - const tokenAddressBuffer = padTo32Bytes(rawTokenAddressBuffer); - const remoteTokenAddress = new RemoteAddress({ - address: tokenAddressBuffer, - }); - this.logger.debug( - `Token address: ${options.tokenAddress} (cleaned: ${cleanTokenAddress}, padded to 32 bytes)` - ); - - // Validate decimals - if (options.decimals < 0 || options.decimals > 18) { - throw new Error("Invalid decimals value. Must be between 0 and 18."); - } - this.logger.debug(`Decimals: ${options.decimals}`); - - // Create RemoteConfig from options - const remoteConfig: RemoteConfig = new RemoteConfig({ - poolAddresses: remotePoolAddresses, - tokenAddress: remoteTokenAddress, - decimals: options.decimals, - }); - - // Build the accounts for the init_chain_remote_config instruction - const accounts: InitChainRemoteConfigAccounts = { - state: statePDA, - chainConfig: chainConfigPDA, - authority: signerPublicKey, - systemProgram: SystemProgram.programId, - }; - - // Log all accounts being used for debugging - this.logger.debug("Init chain remote config accounts:", { - state: statePDA.toString(), - chain_config: chainConfigPDA.toString(), - authority: signerPublicKey.toString(), - system_program: SystemProgram.programId.toString(), - }); - - // Build the args - const args: InitChainRemoteConfigArgs = { - remoteChainSelector: new BN(remoteChainSelector.toString()), - mint: mint, - cfg: remoteConfig.toEncodable(), - }; - - // Log all args being used for debugging - this.logger.debug("Init chain remote config args:", { - remote_chain_selector: remoteChainSelector.toString(), - mint: mint.toString(), - poolAddressCount: remotePoolAddresses.length, - tokenAddress: options.tokenAddress, - decimals: options.decimals, - }); - - // Create the instruction - this.logger.debug("Creating init_chain_remote_config instruction..."); - const instruction = initChainRemoteConfig( - args, - accounts, - this.getProgramId() - ); - - // Log instruction details - this.logger.debug("Init chain remote config instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((key, index) => ({ - index, - pubkey: key.pubkey.toString(), - isSigner: key.isSigner, - isWritable: key.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "initChainRemoteConfig", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Chain remote config initialized: ${signature}`); - - // Parse event data - let event: RemoteChainConfiguredEvent | undefined; - try { - event = - await this.eventParser.parseRemoteChainConfiguredFromTransaction( - this.context, - signature - ); - } catch (error) { - this.logger.warn(`Failed to parse event from transaction: ${error}`); - } - - return { signature, event }; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async getChainConfig( - mint: PublicKey, - remoteChainSelector: bigint - ): Promise { - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.debug( - `Getting chain config for mint: ${mint.toString()}, chain: ${remoteChainSelector.toString()}` - ); - - // Use the account reader to get the chain config - const chainConfig = await this.accountReader.getChainConfig( - mint, - remoteChainSelector - ); - - this.logger.debug(`Chain config retrieved successfully`); - return chainConfig; - } catch (error) { - throw enhanceError(error, { - operation: "getChainConfig", - mint: mint.toString(), - remoteChainSelector: remoteChainSelector.toString(), - }); - } - } - - /** @inheritDoc */ - async editChainRemoteConfig( - mint: PublicKey, - remoteChainSelector: bigint, - options: EditChainRemoteConfigOptions - ): Promise { - const errorContext = { - operation: "editChainRemoteConfig", - mint: mint.toString(), - destChainSelector: remoteChainSelector.toString(), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Editing chain remote config for chain ${remoteChainSelector.toString()} on mint: ${mint.toString()}` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Edit chain remote config details:`, { - mint: mint.toString(), - remoteChainSelector: remoteChainSelector.toString(), - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Verify pool exists (getPoolConfig will throw if not found) - const poolConfig = await this.accountReader.getPoolConfig(mint); - this.logger.debug(`Current owner: ${poolConfig.config.owner.toString()}`); - - // Check if signer is owner - if (!poolConfig.config.owner.equals(signerPublicKey)) { - throw new Error(`Signer is not the owner of the pool`); - } - - // Verify chain config EXISTS (this is an edit operation) - await this.accountReader.getChainConfig(mint, remoteChainSelector); - this.logger.debug( - `Chain config exists for chain: ${remoteChainSelector.toString()}` - ); - - // Find the chain config PDA - const [chainConfigPDA, chainConfigBump] = findBurnMintPoolChainConfigPDA( - remoteChainSelector, - mint, - this.getProgramId() - ); - this.logger.debug( - `Chain config PDA: ${chainConfigPDA.toString()} (bump: ${chainConfigBump})` - ); - this.logger.trace( - `Chain config PDA derivation: seeds=[${TOKEN_POOL_CHAIN_CONFIG_SEED}, ${remoteChainSelector.toString()}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Find the state PDA - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - mint, - this.getProgramId() - ); - this.logger.debug( - `State PDA: ${statePDA.toString()} (bump: ${stateBump})` - ); - this.logger.trace( - `State PDA derivation: seeds=[${TOKEN_POOL_STATE_SEED}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Validate and transform pool addresses from options - if (!options.poolAddresses || options.poolAddresses.length === 0) { - throw new Error("At least one pool address must be provided"); - } - - // Create RemoteAddresses from the provided addresses - // Pool addresses use raw bytes (typically 20 bytes for Ethereum addresses) - const remotePoolAddresses = options.poolAddresses.map((addr) => { - // Strip 0x prefix if present for pool addresses - const cleanPoolAddr = addr.startsWith("0x") ? addr.slice(2) : addr; - const buffer = Buffer.from(cleanPoolAddr, "hex"); - // No padding required for pool addresses - use raw bytes - return new RemoteAddress({ address: buffer }); - }); - this.logger.debug( - `Converted ${remotePoolAddresses.length} pool addresses` - ); - - // Validate and transform token address - if (!options.tokenAddress) { - throw new Error("Token address must be provided"); - } - // Strip 0x prefix if present - const cleanTokenAddress = options.tokenAddress.startsWith("0x") - ? options.tokenAddress.slice(2) - : options.tokenAddress; - const rawTokenAddressBuffer = Buffer.from(cleanTokenAddress, "hex"); - // Token addresses need to be padded to 32 bytes (Ethereum-style) - const tokenAddressBuffer = padTo32Bytes(rawTokenAddressBuffer); - const remoteTokenAddress = new RemoteAddress({ - address: tokenAddressBuffer, - }); - this.logger.debug( - `Token address: ${options.tokenAddress} (padded to 32 bytes)` - ); - - // Validate decimals - if (options.decimals < 0 || options.decimals > 18) { - throw new Error("Invalid decimals value. Must be between 0 and 18."); - } - this.logger.debug(`Decimals: ${options.decimals}`); - - // Create RemoteConfig from options - const remoteConfig: RemoteConfig = new RemoteConfig({ - poolAddresses: remotePoolAddresses, - tokenAddress: remoteTokenAddress, - decimals: options.decimals, - }); - - // Build the accounts for the edit_chain_remote_config instruction - const accounts: EditChainRemoteConfigAccounts = { - state: statePDA, - chainConfig: chainConfigPDA, - authority: signerPublicKey, - systemProgram: SystemProgram.programId, - }; - - // Log all accounts being used for debugging - this.logger.debug("Edit chain remote config accounts:", { - state: statePDA.toString(), - chain_config: chainConfigPDA.toString(), - authority: signerPublicKey.toString(), - system_program: SystemProgram.programId.toString(), - }); - - // Build the args - const args: EditChainRemoteConfigArgs = { - remoteChainSelector: new BN(remoteChainSelector.toString()), - mint: mint, - cfg: remoteConfig.toEncodable(), - }; - - // Log all args being used for debugging - this.logger.debug("Edit chain remote config args:", { - remoteChainSelector: remoteChainSelector.toString(), - mint: mint.toString(), - poolAddressCount: remotePoolAddresses.length, - tokenAddress: options.tokenAddress, - decimals: options.decimals, - }); - - // Create the instruction - this.logger.debug("Creating edit_chain_remote_config instruction..."); - const instruction = editChainRemoteConfig( - args, - accounts, - this.getProgramId() - ); - - // Log instruction details - this.logger.debug("Edit chain remote config instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((key, index) => ({ - index, - pubkey: key.pubkey.toString(), - isSigner: key.isSigner, - isWritable: key.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "editChainRemoteConfig", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Chain remote config edited: ${signature}`); - - // Parse event data - let event: RemoteChainConfiguredEvent | undefined; - try { - event = - await this.eventParser.parseRemoteChainConfiguredFromTransaction( - this.context, - signature - ); - } catch (error) { - this.logger.warn(`Failed to parse event from transaction: ${error}`); - } - - return { signature, event }; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async setRateLimit( - mint: PublicKey, - remoteChainSelector: bigint, - options: BurnMintSetRateLimitOptions - ): Promise { - // 1. Define error context early - const errorContext = { - operation: "setRateLimit", - mint: mint.toString(), - remoteChainSelector: remoteChainSelector.toString(), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - // 2. Standard setup: logger, signer, connection - this.logger.info( - `Setting rate limits for mint: ${mint.toString()}, chain: ${remoteChainSelector.toString()}` - ); - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Set rate limit details:`, { - mint: mint.toString(), - remoteChainSelector: remoteChainSelector.toString(), - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // 3. Validation: - // a. Verify pool state exists - const poolConfig = await this.accountReader.getPoolConfig(mint); // Throws if not found - this.logger.debug(`Current owner: ${poolConfig.config.owner.toString()}`); - this.logger.debug( - `Rate limit admin: ${ - poolConfig.config.rateLimitAdmin?.toString() || "none" - }` - ); - - // b. Verify authority (Owner or Rate Limit Admin) - const isOwner = poolConfig.config.owner.equals(signerPublicKey); - // Check if rate_limit_admin exists on the config object before comparing - const isRateAdmin = - poolConfig.config.rateLimitAdmin && - poolConfig.config.rateLimitAdmin.equals(signerPublicKey); - - this.logger.debug( - `Authorization check: isOwner=${isOwner}, isRateAdmin=${isRateAdmin}` - ); - - if (!isOwner && !isRateAdmin) { - throw new Error( - `Signer is not the owner or rate limit admin of the pool` - ); - } - - // c. Verify target chain config exists (No fallback/hardcoding) - await this.accountReader.getChainConfig(mint, remoteChainSelector); // Throws if not found - this.logger.debug( - `Chain config exists for chain: ${remoteChainSelector.toString()}` - ); - - // 4. Prepare Accounts: Use correct types - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - mint, - this.getProgramId() - ); - this.logger.debug( - `State PDA: ${statePDA.toString()} (bump: ${stateBump})` - ); - this.logger.trace( - `State PDA derivation: seeds=[${TOKEN_POOL_STATE_SEED}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - const [chainConfigPDA, chainConfigBump] = findBurnMintPoolChainConfigPDA( - remoteChainSelector, - mint, - this.getProgramId() - ); - this.logger.debug( - `Chain config PDA: ${chainConfigPDA.toString()} (bump: ${chainConfigBump})` - ); - this.logger.trace( - `Chain config PDA derivation: seeds=[${TOKEN_POOL_CHAIN_CONFIG_SEED}, ${remoteChainSelector.toString()}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - const accounts: SetChainRateLimitAccounts = { - state: statePDA, - chainConfig: chainConfigPDA, - authority: signerPublicKey, - }; - - // Log all accounts being used for debugging - this.logger.debug("Set rate limit accounts:", { - state: statePDA.toString(), - chain_config: chainConfigPDA.toString(), - authority: signerPublicKey.toString(), - }); - - // 5. Prepare Arguments: Use correct types and convert bigints - const inboundCfg = new RateLimitConfig({ - enabled: options.inbound.enabled, - capacity: new BN(options.inbound.capacity.toString()), - rate: new BN(options.inbound.rate.toString()), - }); - const outboundCfg = new RateLimitConfig({ - enabled: options.outbound.enabled, - capacity: new BN(options.outbound.capacity.toString()), - rate: new BN(options.outbound.rate.toString()), - }); - - const args: SetChainRateLimitArgs = { - remoteChainSelector: new BN(remoteChainSelector.toString()), - mint: mint, - inbound: inboundCfg.toEncodable(), - outbound: outboundCfg.toEncodable(), - }; - - // Log all args being used for debugging - this.logger.debug("Set rate limit args:", { - remote_chain_selector: remoteChainSelector.toString(), - mint: mint.toString(), - inbound: { - enabled: options.inbound.enabled, - capacity: options.inbound.capacity.toString(), - rate: options.inbound.rate.toString(), - }, - outbound: { - enabled: options.outbound.enabled, - capacity: options.outbound.capacity.toString(), - rate: options.outbound.rate.toString(), - }, - }); - - // 6. Create Instruction: Use correct builder - this.logger.debug("Creating set_chain_rate_limit instruction..."); - const instruction = setChainRateLimit( - args, - accounts, - this.getProgramId() - ); - - // Log instruction details - this.logger.debug("Set rate limit instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((key, index) => ({ - index, - pubkey: key.pubkey.toString(), - isSigner: key.isSigner, - isWritable: key.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "setRateLimit", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - // 8. Logging - this.logger.info( - `Rate limits set for chain ${remoteChainSelector.toString()}: ${signature}` - ); - return signature; - } catch (error) { - // 9. Consistent Error Handling: Enhance all caught errors - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async hasPool(mint: PublicKey): Promise { - try { - await this.accountReader.getPoolConfig(mint); - return true; - } catch (error) { - this.logger.warn(`Pool not found for mint: ${mint.toString()}`); - return false; - } - } - - /** @inheritDoc */ - async hasChainConfig( - mint: PublicKey, - remoteChainSelector: bigint - ): Promise { - try { - await this.accountReader.getChainConfig(mint, remoteChainSelector); - return true; - } catch (error) { - this.logger.warn( - `Chain config not found for mint: ${mint.toString()}, chain: ${remoteChainSelector.toString()}` - ); - return false; - } - } - - /** @inheritDoc */ - async transferAdminRole( - mint: PublicKey, - options: TransferAdminRoleOptions - ): Promise { - const errorContext = { - operation: "transferAdminRole", - mint: mint.toString(), - newAdmin: options.newAdmin.toString(), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Proposing ownership transfer for mint: ${mint.toString()} to: ${options.newAdmin.toString()}` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Admin role transfer details:`, { - mint: mint.toString(), - newAdmin: options.newAdmin.toString(), - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Verify pool exists - const poolConfig = await this.accountReader.getPoolConfig(mint); - this.logger.debug(`Current owner: ${poolConfig.config.owner.toString()}`); - this.logger.debug( - `Current proposed owner: ${ - poolConfig.config.proposedOwner?.toString() || "none" - }` - ); - - // Check if signer is owner - if (!poolConfig.config.owner.equals(signerPublicKey)) { - throw new Error(`Signer is not the owner of the pool`); - } - - // Find the state PDA - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - mint, - this.getProgramId() - ); - this.logger.debug( - `State PDA: ${statePDA.toString()} (bump: ${stateBump})` - ); - this.logger.trace( - `State PDA derivation: seeds=[${TOKEN_POOL_STATE_SEED}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Build the accounts - const accounts: TransferOwnershipAccounts = { - state: statePDA, - mint: mint, - authority: signerPublicKey, - }; - - // Log all accounts being used for debugging - this.logger.debug("Transfer admin role accounts:", { - state: statePDA.toString(), - mint: mint.toString(), - authority: signerPublicKey.toString(), - }); - - // Build the args - const args: TransferOwnershipArgs = { - proposedOwner: options.newAdmin, - }; - - // Log all args being used for debugging - this.logger.debug("Transfer admin role args:", { - proposed_owner: options.newAdmin.toString(), - }); - - // Create the instruction - this.logger.debug("Creating transfer_ownership instruction..."); - const instruction = transferOwnership( - args, - accounts, - this.getProgramId() - ); - - // Log instruction details - this.logger.debug("Transfer admin role instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((key, index) => ({ - index, - pubkey: key.pubkey.toString(), - isSigner: key.isSigner, - isWritable: key.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "transferAdminRole", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Admin role transfer proposed: ${signature}`); - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async acceptAdminRole( - mint: PublicKey, - options?: AcceptAdminRoleOptions - ): Promise { - const errorContext = { - operation: "acceptAdminRole", - mint: mint.toString(), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info(`Accepting admin role for mint: ${mint.toString()}...`); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Accept admin role details:`, { - mint: mint.toString(), - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Verify pool exists and fetch config - const poolConfig = await this.accountReader.getPoolConfig(mint); - this.logger.debug(`Current owner: ${poolConfig.config.owner.toString()}`); - this.logger.debug( - `Current proposed owner: ${ - poolConfig.config.proposedOwner?.toString() || "none" - }` - ); - - // Check if signer is the proposed owner - // Ensure proposed_owner is not null/default before comparing - if ( - !poolConfig.config.proposedOwner || - poolConfig.config.proposedOwner.equals(PublicKey.default) || // Check against default PublicKey - !poolConfig.config.proposedOwner.equals(signerPublicKey) - ) { - throw new Error( - `Signer ${signerPublicKey.toString()} is not the proposed owner (${poolConfig.config.proposedOwner?.toString()}) for this pool` - ); - } - - // Find the state PDA - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - mint, - this.getProgramId() - ); - this.logger.debug( - `State PDA: ${statePDA.toString()} (bump: ${stateBump})` - ); - this.logger.trace( - `State PDA derivation: seeds=[${TOKEN_POOL_STATE_SEED}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Build the accounts - const accounts: AcceptOwnershipAccounts = { - state: statePDA, - mint: mint, - authority: signerPublicKey, // The caller (proposed owner) is the authority here - }; - - // Log all accounts being used for debugging - this.logger.debug("Accept admin role accounts:", { - state: statePDA.toString(), - mint: mint.toString(), - authority: signerPublicKey.toString(), - }); - - // Create the instruction (accept_ownership has no args) - this.logger.debug("Creating accept_ownership instruction..."); - const instruction = acceptOwnership(accounts, this.getProgramId()); - - // Log instruction details - this.logger.debug("Accept admin role instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((key, index) => ({ - index, - pubkey: key.pubkey.toString(), - isSigner: key.isSigner, - isWritable: key.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "acceptAdminRole", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Admin role accepted: ${signature}`); - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async setRouter(mint: PublicKey, options: SetRouterOptions): Promise { - const errorContext = { - operation: "setRouter", - mint: mint.toString(), - newRouter: options.newRouter.toString(), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Setting router for mint: ${mint.toString()} to: ${options.newRouter.toString()}` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Router update details:`, { - mint: mint.toString(), - newRouter: options.newRouter.toString(), - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Verify pool exists and signer is owner - const poolConfig = await this.accountReader.getPoolConfig(mint); - this.logger.debug( - `Current router: ${poolConfig.config.router.toString()}` - ); - - if (!poolConfig.config.owner.equals(signerPublicKey)) { - throw new Error(`Signer is not the owner of the pool`); - } - - // Find the state PDA - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - mint, - this.getProgramId() - ); - this.logger.debug( - `State PDA: ${statePDA.toString()} (bump: ${stateBump})` - ); - this.logger.trace( - `State PDA derivation: seeds=[${TOKEN_POOL_STATE_SEED}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Find the program data PDA for this program - const [programDataPDA, programDataBump] = findProgramDataPDA( - this.getProgramId() - ); - this.logger.debug( - `Program data PDA: ${programDataPDA.toString()} (bump: ${programDataBump})` - ); - this.logger.trace( - `Program data PDA derivation: seeds=[${this.getProgramId().toString()}], program=BPF_LOADER_UPGRADEABLE_PROGRAM_ID` - ); - - // Build the accounts - const accounts: SetRouterAccounts = { - state: statePDA, - mint, - authority: signerPublicKey, - program: this.getProgramId(), - programData: programDataPDA, - }; - - // Log all accounts being used for debugging - this.logger.debug("Set router accounts:", { - state: statePDA.toString(), - mint: mint.toString(), - authority: signerPublicKey.toString(), - program: this.getProgramId().toString(), - programData: programDataPDA.toString(), - }); - - // Build the args - const args: SetRouterArgs = { - newRouter: options.newRouter, - }; - - // Log all args being used for debugging - this.logger.debug("Set router args:", { - newRouter: options.newRouter.toString(), - }); - - // Create the instruction - this.logger.debug("Creating set_router instruction..."); - const instruction = setRouter(args, accounts, this.getProgramId()); - - // Log instruction details - this.logger.debug("Set router instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((key, index) => ({ - index, - pubkey: key.pubkey.toString(), - isSigner: key.isSigner, - isWritable: key.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "setRouter", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Router updated: ${signature}`); - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async initializeStateVersion( - mint: PublicKey, - options?: InitializeStateVersionOptions - ): Promise { - const errorContext = { - operation: "initializeStateVersion", - mint: mint.toString(), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Initializing state version for mint: ${mint.toString()}` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Initialize state version details:`, { - mint: mint.toString(), - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Note: This operation is permissionless - no owner check needed - this.logger.debug( - `Operation is permissionless - no ownership validation required` - ); - - // Find the state PDA - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - mint, - this.getProgramId() - ); - this.logger.debug( - `State PDA: ${statePDA.toString()} (bump: ${stateBump})` - ); - this.logger.trace( - `State PDA derivation: seeds=[${TOKEN_POOL_STATE_SEED}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Build the accounts - const accounts: InitializeStateVersionAccounts = { - state: statePDA, - }; - - // Log all accounts being used for debugging - this.logger.debug("Initialize state version accounts:", { - state: statePDA.toString(), - }); - - // Create the args - const args: InitializeStateVersionArgs = { - mint: mint, - }; - - // Log all args being used for debugging - this.logger.debug("Initialize state version args:", { - mint: mint.toString(), - }); - - // Create the instruction - this.logger.debug("Creating initializeStateVersion instruction..."); - const instruction = initializeStateVersion( - args, - accounts, - this.getProgramId() - ); - - // Log instruction details - this.logger.debug("Initialize state version instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((key, index) => ({ - index, - pubkey: key.pubkey.toString(), - isSigner: key.isSigner, - isWritable: key.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "initializeStateVersion", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`State version initialized: ${signature}`); - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async configureAllowlist( - mint: PublicKey, - options: ConfigureAllowlistOptions - ): Promise { - const errorContext = { - operation: "configureAllowlist", - mint: mint.toString(), - enabled: String(options.enabled), - addCount: String(options.add.length), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Configuring allowlist for mint: ${mint.toString()}, enabled: ${ - options.enabled - }, adding ${options.add.length} addresses` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Configure allowlist details:`, { - mint: mint.toString(), - enabled: options.enabled, - addCount: options.add.length, - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Verify pool exists and signer is owner - const poolConfig = await this.accountReader.getPoolConfig(mint); - this.logger.debug(`Current owner: ${poolConfig.config.owner.toString()}`); - - if (!poolConfig.config.owner.equals(signerPublicKey)) { - throw new Error(`Signer is not the owner of the pool`); - } - - // Find the state PDA - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - mint, - this.getProgramId() - ); - this.logger.debug( - `State PDA: ${statePDA.toString()} (bump: ${stateBump})` - ); - this.logger.trace( - `State PDA derivation: seeds=[${TOKEN_POOL_STATE_SEED}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Build the accounts - const accounts: ConfigureAllowListAccounts = { - state: statePDA, - mint, - authority: signerPublicKey, - systemProgram: SystemProgram.programId, - }; - - // Log all accounts being used for debugging - this.logger.debug("Configure allowlist accounts:", { - state: statePDA.toString(), - mint: mint.toString(), - authority: signerPublicKey.toString(), - systemProgram: SystemProgram.programId.toString(), - }); - - // Build the args - const args: ConfigureAllowListArgs = { - add: options.add, - enabled: options.enabled, - }; - - // Log all args being used for debugging - this.logger.debug("Configure allowlist args:", { - enabled: options.enabled, - addAddresses: options.add.map((addr) => addr.toString()), - }); - - // Create the instruction - this.logger.debug("Creating configureAllowList instruction..."); - const instruction = configureAllowList( - args, - accounts, - this.getProgramId() - ); - - // Log instruction details - this.logger.debug("Configure allowlist instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((key, index) => ({ - index, - pubkey: key.pubkey.toString(), - isSigner: key.isSigner, - isWritable: key.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "configureAllowlist", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Allowlist configured: ${signature}`); - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async removeFromAllowlist( - mint: PublicKey, - options: RemoveFromAllowlistOptions - ): Promise { - const errorContext = { - operation: "removeFromAllowlist", - mint: mint.toString(), - removeCount: String(options.remove.length), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Removing ${ - options.remove.length - } addresses from allowlist for mint: ${mint.toString()}` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Remove from allowlist details:`, { - mint: mint.toString(), - removeCount: options.remove.length, - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Verify pool exists and signer is owner - const poolConfig = await this.accountReader.getPoolConfig(mint); - this.logger.debug(`Current owner: ${poolConfig.config.owner.toString()}`); - - if (!poolConfig.config.owner.equals(signerPublicKey)) { - throw new Error(`Signer is not the owner of the pool`); - } - - // Find the state PDA - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - mint, - this.getProgramId() - ); - this.logger.debug( - `State PDA: ${statePDA.toString()} (bump: ${stateBump})` - ); - this.logger.trace( - `State PDA derivation: seeds=[${TOKEN_POOL_STATE_SEED}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Build the accounts - const accounts: RemoveFromAllowListAccounts = { - state: statePDA, - mint, - authority: signerPublicKey, - systemProgram: SystemProgram.programId, - }; - - // Log all accounts being used for debugging - this.logger.debug("Remove from allowlist accounts:", { - state: statePDA.toString(), - mint: mint.toString(), - authority: signerPublicKey.toString(), - system_program: SystemProgram.programId.toString(), - }); - - // Build the args - const args: RemoveFromAllowListArgs = { - remove: options.remove, - }; - - // Log all args being used for debugging - this.logger.debug("Remove from allowlist args:", { - removeAddresses: options.remove.map((addr) => addr.toString()), - }); - - // Create the instruction - this.logger.debug("Creating removeFromAllowList instruction..."); - const instruction = removeFromAllowList( - args, - accounts, - this.getProgramId() - ); - - // Log instruction details - this.logger.debug("Remove from allowlist instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((key, index) => ({ - index, - pubkey: key.pubkey.toString(), - isSigner: key.isSigner, - isWritable: key.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "removeFromAllowlist", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Removed from allowlist: ${signature}`); - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async appendRemotePoolAddresses( - mint: PublicKey, - options: AppendRemotePoolAddressesOptions - ): Promise { - const errorContext = { - operation: "appendRemotePoolAddresses", - mint: mint.toString(), - remoteChainSelector: options.remoteChainSelector.toString(), - addressCount: String(options.addresses.length), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Appending ${ - options.addresses.length - } remote pool addresses for mint: ${mint.toString()}, chain: ${options.remoteChainSelector.toString()}` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Append remote pool addresses details:`, { - mint: mint.toString(), - remoteChainSelector: options.remoteChainSelector.toString(), - addressCount: options.addresses.length, - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Verify pool exists and signer is owner - const poolConfig = await this.accountReader.getPoolConfig(mint); - this.logger.debug(`Current owner: ${poolConfig.config.owner.toString()}`); - - if (!poolConfig.config.owner.equals(signerPublicKey)) { - throw new Error(`Signer is not the owner of the pool`); - } - - // Verify chain configuration exists - await this.accountReader.getChainConfig( - mint, - options.remoteChainSelector - ); - this.logger.debug( - `Chain config exists for chain: ${options.remoteChainSelector.toString()}` - ); - - // Find the state PDA - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - mint, - this.getProgramId() - ); - this.logger.debug( - `State PDA: ${statePDA.toString()} (bump: ${stateBump})` - ); - this.logger.trace( - `State PDA derivation: seeds=[${TOKEN_POOL_STATE_SEED}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Find the chain config PDA - const [chainConfigPDA, chainConfigBump] = findBurnMintPoolChainConfigPDA( - options.remoteChainSelector, - mint, - this.getProgramId() - ); - this.logger.debug( - `Chain config PDA: ${chainConfigPDA.toString()} (bump: ${chainConfigBump})` - ); - this.logger.trace( - `Chain config PDA derivation: seeds=[${TOKEN_POOL_CHAIN_CONFIG_SEED}, ${options.remoteChainSelector.toString()}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Convert hex string addresses to RemoteAddress objects (raw bytes, no enforced length) - const remoteAddresses = options.addresses.map((addr) => { - const clean = addr.startsWith("0x") ? addr.slice(2) : addr; - const buffer = Buffer.from(clean, "hex"); - return new RemoteAddress({ address: buffer }); - }); - this.logger.debug( - `Converted ${remoteAddresses.length} hex addresses to RemoteAddress objects` - ); - - // Build the accounts - const accounts: AppendRemotePoolAddressesAccounts = { - state: statePDA, - chainConfig: chainConfigPDA, - authority: signerPublicKey, - systemProgram: SystemProgram.programId, - }; - - // Log all accounts being used for debugging - this.logger.debug("Append remote pool addresses accounts:", { - state: statePDA.toString(), - chain_config: chainConfigPDA.toString(), - authority: signerPublicKey.toString(), - system_program: SystemProgram.programId.toString(), - }); - - // Build the args - const args: AppendRemotePoolAddressesArgs = { - remoteChainSelector: new BN(options.remoteChainSelector.toString()), - addresses: remoteAddresses, - mint: mint, - }; - - // Log all args being used for debugging - this.logger.debug("Append remote pool addresses args:", { - remote_chain_selector: options.remoteChainSelector.toString(), - addressCount: remoteAddresses.length, - _mint: mint.toString(), - }); - - // Create the instruction - this.logger.debug("Creating append_remote_pool_addresses instruction..."); - const instruction = appendRemotePoolAddresses( - args, - accounts, - this.getProgramId() - ); - - // Log instruction details - this.logger.debug("Append remote pool addresses instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((key, index) => ({ - index, - pubkey: key.pubkey.toString(), - isSigner: key.isSigner, - isWritable: key.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "appendRemotePoolAddresses", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Remote pool addresses appended: ${signature}`); - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async deleteChainConfig( - mint: PublicKey, - options: DeleteChainConfigOptions - ): Promise { - const errorContext = { - operation: "deleteChainConfig", - mint: mint.toString(), - remoteChainSelector: options.remoteChainSelector.toString(), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Deleting chain config for mint: ${mint.toString()}, chain: ${options.remoteChainSelector.toString()}` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Delete chain config details:`, { - mint: mint.toString(), - remoteChainSelector: options.remoteChainSelector.toString(), - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Verify pool exists and signer is owner - const poolConfig = await this.accountReader.getPoolConfig(mint); - this.logger.debug(`Current owner: ${poolConfig.config.owner.toString()}`); - - if (!poolConfig.config.owner.equals(signerPublicKey)) { - throw new Error(`Signer is not the owner of the pool`); - } - - // Verify chain configuration exists - await this.accountReader.getChainConfig( - mint, - options.remoteChainSelector - ); - this.logger.debug( - `Chain config exists for chain: ${options.remoteChainSelector.toString()}` - ); - - // Find the state PDA - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - mint, - this.getProgramId() - ); - this.logger.debug( - `State PDA: ${statePDA.toString()} (bump: ${stateBump})` - ); - this.logger.trace( - `State PDA derivation: seeds=[${TOKEN_POOL_STATE_SEED}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Find the chain config PDA - const [chainConfigPDA, chainConfigBump] = findBurnMintPoolChainConfigPDA( - options.remoteChainSelector, - mint, - this.getProgramId() - ); - this.logger.debug( - `Chain config PDA: ${chainConfigPDA.toString()} (bump: ${chainConfigBump})` - ); - this.logger.trace( - `Chain config PDA derivation: seeds=[${TOKEN_POOL_CHAIN_CONFIG_SEED}, ${options.remoteChainSelector.toString()}, ${mint.toString()}], program=${this.getProgramId().toString()}` - ); - - // Build the accounts - const accounts: DeleteChainConfigAccounts = { - state: statePDA, - chainConfig: chainConfigPDA, - authority: signerPublicKey, - }; - - // Log all accounts being used for debugging - this.logger.debug("Delete chain config accounts:", { - state: statePDA.toString(), - chain_config: chainConfigPDA.toString(), - authority: signerPublicKey.toString(), - }); - - // Create the instruction with args - const args: DeleteChainConfigArgs = { - remoteChainSelector: new BN(options.remoteChainSelector.toString()), - mint, - }; - - // Log all args being used for debugging - this.logger.debug("Delete chain config args:", { - remote_chain_selector: options.remoteChainSelector.toString(), - mint: mint.toString(), - }); - - this.logger.debug("Creating delete_chain_config instruction..."); - const instruction = deleteChainConfig( - args, - accounts, - this.getProgramId() - ); - - // Log instruction details - this.logger.debug("Delete chain config instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - this.logger.trace("Instruction accounts:", { - keys: instruction.keys.map((key, index) => ({ - index, - pubkey: key.pubkey.toString(), - isSigner: key.isSigner, - isWritable: key.isWritable, - })), - }); - this.logger.trace( - `Instruction data (hex): ${instruction.data.toString("hex")}` - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "deleteChainConfig", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Chain config deleted: ${signature}`); - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async updateSelfServedAllowed( - options: UpdateSelfServedAllowedOptions - ): Promise { - const errorContext = { - operation: "updateSelfServedAllowed", - selfServedAllowed: String(options.selfServedAllowed), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Updating global self-served allowed flag to: ${options.selfServedAllowed}` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Update self-served allowed details:`, { - selfServedAllowed: options.selfServedAllowed, - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Find the global config PDA - const [globalConfigPDA, globalConfigBump] = findGlobalConfigPDA( - this.getProgramId() - ); - this.logger.debug( - `Global config PDA: ${globalConfigPDA.toString()} (bump: ${globalConfigBump})` - ); - - // Find the program data PDA - const [programDataPDA, programDataBump] = findProgramDataPDA( - this.getProgramId() - ); - this.logger.debug( - `Program data PDA: ${programDataPDA.toString()} (bump: ${programDataBump})` - ); - - // Build the accounts - const accounts: UpdateSelfServedAllowedAccounts = { - config: globalConfigPDA, - authority: signerPublicKey, - program: this.getProgramId(), - programData: programDataPDA, - }; - - // Log all accounts being used for debugging - this.logger.debug("Update self-served allowed accounts:", { - config: globalConfigPDA.toString(), - authority: signerPublicKey.toString(), - program: this.getProgramId().toString(), - programData: programDataPDA.toString(), - }); - - // Build the args - const args: UpdateSelfServedAllowedArgs = { - selfServedAllowed: options.selfServedAllowed, - }; - - // Log all args being used for debugging - this.logger.debug("Update self-served allowed args:", { - selfServedAllowed: options.selfServedAllowed, - }); - - // Create the instruction - this.logger.debug("Creating updateSelfServedAllowed instruction..."); - const instruction = updateSelfServedAllowed( - args, - accounts, - this.getProgramId() - ); - - // Log instruction details - this.logger.debug("Update self-served allowed instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "updateSelfServedAllowed", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Global self-served allowed updated: ${signature}`); - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async updateDefaultRouter( - options: UpdateDefaultRouterOptions - ): Promise { - const errorContext = { - operation: "updateDefaultRouter", - routerAddress: options.routerAddress.toString(), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Updating global default router to: ${options.routerAddress.toString()}` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Update default router details:`, { - routerAddress: options.routerAddress.toString(), - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Find the global config PDA - const [globalConfigPDA, globalConfigBump] = findGlobalConfigPDA( - this.getProgramId() - ); - this.logger.debug( - `Global config PDA: ${globalConfigPDA.toString()} (bump: ${globalConfigBump})` - ); - - // Find the program data PDA - const [programDataPDA, programDataBump] = findProgramDataPDA( - this.getProgramId() - ); - this.logger.debug( - `Program data PDA: ${programDataPDA.toString()} (bump: ${programDataBump})` - ); - - // Build the accounts - const accounts: UpdateDefaultRouterAccounts = { - config: globalConfigPDA, - authority: signerPublicKey, - program: this.getProgramId(), - programData: programDataPDA, - }; - - // Log all accounts being used for debugging - this.logger.debug("Update default router accounts:", { - config: globalConfigPDA.toString(), - authority: signerPublicKey.toString(), - program: this.getProgramId().toString(), - programData: programDataPDA.toString(), - }); - - // Build the args - const args: UpdateDefaultRouterArgs = { - routerAddress: options.routerAddress, - }; - - // Log all args being used for debugging - this.logger.debug("Update default router args:", { - routerAddress: options.routerAddress.toString(), - }); - - // Create the instruction - this.logger.debug("Creating updateDefaultRouter instruction..."); - const instruction = updateDefaultRouter( - args, - accounts, - this.getProgramId() - ); - - // Log instruction details - this.logger.debug("Update default router instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "updateDefaultRouter", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Global default router updated: ${signature}`); - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async updateDefaultRmn(options: UpdateDefaultRmnOptions): Promise { - const errorContext = { - operation: "updateDefaultRmn", - rmnAddress: options.rmnAddress.toString(), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Updating global default RMN to: ${options.rmnAddress.toString()}` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Update default RMN details:`, { - rmnAddress: options.rmnAddress.toString(), - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Find the global config PDA - const [globalConfigPDA, globalConfigBump] = findGlobalConfigPDA( - this.getProgramId() - ); - this.logger.debug( - `Global config PDA: ${globalConfigPDA.toString()} (bump: ${globalConfigBump})` - ); - - // Find the program data PDA - const [programDataPDA, programDataBump] = findProgramDataPDA( - this.getProgramId() - ); - this.logger.debug( - `Program data PDA: ${programDataPDA.toString()} (bump: ${programDataBump})` - ); - - // Build the accounts - const accounts: UpdateDefaultRmnAccounts = { - config: globalConfigPDA, - authority: signerPublicKey, - program: this.getProgramId(), - programData: programDataPDA, - }; - - // Log all accounts being used for debugging - this.logger.debug("Update default RMN accounts:", { - config: globalConfigPDA.toString(), - authority: signerPublicKey.toString(), - program: this.getProgramId().toString(), - programData: programDataPDA.toString(), - }); - - // Build the args - const args: UpdateDefaultRmnArgs = { - rmnAddress: options.rmnAddress, - }; - - // Log all args being used for debugging - this.logger.debug("Update default RMN args:", { - rmnAddress: options.rmnAddress.toString(), - }); - - // Create the instruction - this.logger.debug("Creating updateDefaultRmn instruction..."); - const instruction = updateDefaultRmn(args, accounts, this.getProgramId()); - - // Log instruction details - this.logger.debug("Update default RMN instruction created:", { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - }); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "updateDefaultRmn", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Global default RMN updated: ${signature}`); - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } - - /** @inheritDoc */ - async transferMintAuthorityToMultisig( - mint: PublicKey, - options: TransferMintAuthorityToMultisigOptions - ): Promise { - const errorContext = { - operation: "transferMintAuthorityToMultisig", - mint: mint.toString(), - newMultisigMintAuthority: options.newMultisigMintAuthority.toString(), - }; - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.info( - `Transferring mint authority for mint: ${mint.toString()} to multisig: ${options.newMultisigMintAuthority.toString()}` - ); - - const signerPublicKey = this.context.provider.getAddress(); - this.logger.debug(`Transfer mint authority details:`, { - mint: mint.toString(), - newMultisigMintAuthority: options.newMultisigMintAuthority.toString(), - signer: signerPublicKey.toString(), - programId: this.getProgramId().toString(), - }); - - // Verify pool exists (will be needed for pool signer derivation) - const poolConfig = await this.accountReader.getPoolConfig(mint); - this.logger.debug( - `Pool exists with owner: ${poolConfig.config.owner.toString()}` - ); - - // Find the state PDA - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - mint, - this.getProgramId() - ); - this.logger.debug( - `State PDA: ${statePDA.toString()} (bump: ${stateBump})` - ); - - // Find the pool signer PDA - const [poolSignerPDA, poolSignerBump] = findPoolSignerPDA( - mint, - this.getProgramId() - ); - this.logger.debug( - `Pool signer PDA: ${poolSignerPDA.toString()} (bump: ${poolSignerBump})` - ); - - // Find the program data PDA - const [programDataPDA, programDataBump] = findProgramDataPDA( - this.getProgramId() - ); - this.logger.debug( - `Program data PDA: ${programDataPDA.toString()} (bump: ${programDataBump})` - ); - - // Get the token program from the mint account - const mintAccount = await this.context.provider.connection.getAccountInfo( - mint - ); - if (!mintAccount) { - throw new Error(`Mint account not found: ${mint.toString()}`); - } - const tokenProgram = mintAccount.owner; - this.logger.debug(`Token program: ${tokenProgram.toString()}`); - - // Build the accounts - const accounts: TransferMintAuthorityToMultisigAccounts = { - state: statePDA, - mint, - tokenProgram, - poolSigner: poolSignerPDA, - authority: signerPublicKey, - newMultisigMintAuthority: options.newMultisigMintAuthority, - program: this.getProgramId(), - programData: programDataPDA, - }; - - // Log all accounts being used for debugging - this.logger.debug("Transfer mint authority to multisig accounts:", { - state: statePDA.toString(), - mint: mint.toString(), - tokenProgram: tokenProgram.toString(), - poolSigner: poolSignerPDA.toString(), - authority: signerPublicKey.toString(), - newMultisigMintAuthority: options.newMultisigMintAuthority.toString(), - program: this.getProgramId().toString(), - programData: programDataPDA.toString(), - }); - - // Create the instruction (this function has no args, only accounts) - this.logger.debug( - "Creating transferMintAuthorityToMultisig instruction..." - ); - const instruction = transferMintAuthorityToMultisig( - accounts, - this.getProgramId() - ); - - // Log instruction details - this.logger.debug( - "Transfer mint authority to multisig instruction created:", - { - programId: this.getProgramId().toString(), - dataLength: instruction.data.length, - keyCount: instruction.keys.length, - } - ); - - // Execute the transaction using the shared utility - const executionOptions: TransactionExecutionOptions = { - ...extractTxOptions(options), - errorContext, - operationName: "transferMintAuthorityToMultisig", - }; - - const signature = await executeTransaction( - this.context, - [instruction], - executionOptions - ); - - this.logger.info(`Mint authority transferred to multisig: ${signature}`); - return signature; - } catch (error) { - throw enhanceError(error, errorContext); - } - } -} diff --git a/ccip-lib/svm/tokenpools/burnmint/events.ts b/ccip-lib/svm/tokenpools/burnmint/events.ts deleted file mode 100644 index 4be6226c..00000000 --- a/ccip-lib/svm/tokenpools/burnmint/events.ts +++ /dev/null @@ -1,230 +0,0 @@ -import { PublicKey } from "@solana/web3.js"; -import { CCIPContext } from "../../core/models"; -import { createLogger, Logger } from "../../utils/logger"; -import { createErrorEnhancer } from "../../utils/errors"; -import { - RemoteAddress, - RateLimitConfig, - RemoteAddressFields, - RateLimitConfigFields, -} from "../../burnmint-pool-bindings/types"; - -/** - * Event data for RemoteChainConfigured event using existing bindings types - */ -export interface RemoteChainConfiguredEvent { - chainSelector: bigint; - mint: PublicKey; - token: RemoteAddressFields; - previousToken: RemoteAddressFields; - poolAddresses: RemoteAddressFields[]; - previousPoolAddresses: RemoteAddressFields[]; -} - -/** - * Event data for RateLimitConfigured event using existing bindings types - */ -export interface RateLimitConfiguredEvent { - chainSelector: bigint; - mint: PublicKey; - outboundRateLimit: RateLimitConfigFields; - inboundRateLimit: RateLimitConfigFields; -} - -/** - * Event data for GlobalConfigUpdated event - */ -export interface GlobalConfigUpdatedEvent { - selfServedAllowed: boolean; -} - -/** - * Union type for all burnmint pool events - */ -export type BurnMintPoolEvent = - | { type: "RemoteChainConfigured"; data: RemoteChainConfiguredEvent } - | { type: "RateLimitConfigured"; data: RateLimitConfiguredEvent } - | { type: "GlobalConfigUpdated"; data: GlobalConfigUpdatedEvent }; - -/** - * Event discriminators (hardcoded - would ideally come from IDL generation) - */ -const EVENT_DISCRIMINATORS = { - RemoteChainConfigured: Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), // TODO: Get actual discriminator - RateLimitConfigured: Buffer.from([8, 7, 6, 5, 4, 3, 2, 1]), // TODO: Get actual discriminator - GlobalConfigUpdated: Buffer.from([9, 8, 7, 6, 5, 4, 3, 2]), // TODO: Get actual discriminator -} as const; - -/** - * Simple manual event parser for burnmint pool events - * Uses existing bindings types instead of IDL-based parsing - */ -export class BurnMintPoolEventParser { - private readonly logger: Logger; - - constructor(private readonly programId: PublicKey, context?: CCIPContext) { - this.logger = context?.logger ?? createLogger("burnmint-pool-events"); - } - - /** - * Parses events from transaction logs using manual parsing - * @param logMessages Transaction log messages - * @returns Array of parsed events - */ - parseEvents(logMessages: string[]): BurnMintPoolEvent[] { - const enhanceError = createErrorEnhancer(this.logger); - - try { - const parsedEvents: BurnMintPoolEvent[] = []; - - // Look for "Program data: " logs from our program - const programDataLogs = logMessages.filter( - (log) => - log.includes("Program data: ") && - log.includes(this.programId.toString()) - ); - - for (const log of programDataLogs) { - try { - const event = this.parseEventFromLog(log); - if (event) { - parsedEvents.push(event); - } - } catch (error) { - this.logger.trace(`Failed to parse log as event: ${log}`, error); - } - } - - this.logger.debug( - `Parsed ${parsedEvents.length} events from transaction logs` - ); - return parsedEvents; - } catch (error) { - throw enhanceError(error, { - operation: "parseEvents", - programId: this.programId.toString(), - }); - } - } - - /** - * Parses events from a transaction signature - * @param context CCIP context with connection - * @param txSignature Transaction signature - * @returns Array of parsed events - */ - async parseEventsFromTransaction( - context: CCIPContext, - txSignature: string - ): Promise { - const enhanceError = createErrorEnhancer(this.logger); - - try { - this.logger.debug(`Fetching transaction details for: ${txSignature}`); - - const tx = await context.provider.connection.getTransaction(txSignature, { - commitment: "confirmed", - maxSupportedTransactionVersion: 0, - }); - - if (!tx || !tx.meta || !tx.meta.logMessages) { - this.logger.warn(`No transaction logs found for ${txSignature}`); - return []; - } - - return this.parseEvents(tx.meta.logMessages); - } catch (error) { - throw enhanceError(error, { - operation: "parseEventsFromTransaction", - txSignature, - programId: this.programId.toString(), - }); - } - } - - /** - * Parses a specific RemoteChainConfigured event from transaction logs - * @param logMessages Transaction log messages - * @returns Parsed RemoteChainConfigured event or null - */ - parseRemoteChainConfiguredEvent( - logMessages: string[] - ): RemoteChainConfiguredEvent | null { - const events = this.parseEvents(logMessages); - const configEvent = events.find((e) => e.type === "RemoteChainConfigured"); - return configEvent?.type === "RemoteChainConfigured" - ? configEvent.data - : null; - } - - /** - * Parses events from a transaction and returns RemoteChainConfigured event - * @param context CCIP context - * @param txSignature Transaction signature - * @returns RemoteChainConfigured event data or null - */ - async parseRemoteChainConfiguredFromTransaction( - context: CCIPContext, - txSignature: string - ): Promise { - const events = await this.parseEventsFromTransaction(context, txSignature); - const configEvent = events.find((e) => e.type === "RemoteChainConfigured"); - return configEvent?.type === "RemoteChainConfigured" - ? configEvent.data - : null; - } - - /** - * Parse a single event from a program data log - * @param log Program data log message - * @returns Parsed event or null - * @private - */ - private parseEventFromLog(log: string): BurnMintPoolEvent | null { - try { - // Extract base64 data from "Program data: " log - const parts = log.split("Program data: "); - if (parts.length < 2) return null; - - const base64Data = parts[1].trim(); - const buffer = Buffer.from(base64Data, "base64"); - - if (buffer.length < 8) return null; // Need at least discriminator - - const discriminator = buffer.subarray(0, 8); - - // Check discriminator to determine event type - // NOTE: These discriminators need to be determined from the actual program - // For now, we'll implement a simple fallback that logs the discriminator - this.logger.trace( - `Event discriminator: ${discriminator.toString("hex")}` - ); - - // TODO: Implement proper discriminator matching once we have the actual values - // For now, return null and log the discriminator for investigation - this.logger.debug( - `Found potential event with discriminator: ${discriminator.toString( - "hex" - )}` - ); - - return null; - } catch (error) { - this.logger.trace(`Failed to parse event from log: ${error}`); - return null; - } - } -} - -/** - * Creates a BurnMintPoolEventParser instance - * @param programId Program ID - * @param context Optional CCIP context - * @returns Event parser instance - */ -export function createBurnMintPoolEventParser( - programId: PublicKey, - context?: CCIPContext -): BurnMintPoolEventParser { - return new BurnMintPoolEventParser(programId, context); -} diff --git a/ccip-lib/svm/tokenpools/burnmint/index.ts b/ccip-lib/svm/tokenpools/burnmint/index.ts deleted file mode 100644 index b8d156ad..00000000 --- a/ccip-lib/svm/tokenpools/burnmint/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Burn-Mint Token Pool Implementation - * - * This module provides a concrete implementation of the token pool client - * for burn-mint type pools, where tokens are burned on the source chain - * and minted on the destination chain. - */ - -// Export the client implementation -export { BurnMintTokenPoolClient } from "./client"; -export { BurnMintTokenPoolAccountReader } from "./accounts"; - -// Export event parsing utilities -export * from "./events"; diff --git a/ccip-lib/svm/tokenpools/factory.ts b/ccip-lib/svm/tokenpools/factory.ts deleted file mode 100644 index d76634d9..00000000 --- a/ccip-lib/svm/tokenpools/factory.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { PublicKey } from "@solana/web3.js"; -import { CCIPContext } from "../core/models"; -import { TokenPoolClient } from "./abstract"; -import { BurnMintTokenPoolClient } from "./burnmint"; -import { CCIPError } from "../utils/errors"; -import { createErrorEnhancer } from "../utils/errors"; -import { createLogger, LogLevel } from "../utils/logger"; - -/** - * Supported token pool types - */ -export enum TokenPoolType { - /** Burn and mint token pool (burn on source, mint on destination) */ - BURN_MINT = "burn_mint", - // Future pool types will be added here -} - -/** - * Map of program IDs for different token pool types - */ -export interface TokenPoolProgramIds { - /** Program ID for burn-mint token pool */ - burnMint: PublicKey; - // Future pool types will be added here -} - -/** - * Factory for creating token pool clients - */ -export class TokenPoolFactory { - /** - * Create a token pool client of the specified type - * @param type Pool type to create - * @param context CCIP context - * @param programIds Map of program IDs for different token pool types - * @returns TokenPoolClient instance - */ - static create( - type: TokenPoolType, - context: CCIPContext, - programIds: TokenPoolProgramIds - ): TokenPoolClient { - switch (type) { - case TokenPoolType.BURN_MINT: - return new BurnMintTokenPoolClient(context, programIds.burnMint); - default: - throw new CCIPError(`Unsupported token pool type: ${type}`, { type }); - } - } - - /** - * Detect the token pool type for a specific mint - * This method examines on-chain accounts to determine the pool type - * - * @param mint Token mint to check - * @param context CCIP context - * @param programIds Map of program IDs for different token pool types - * @returns Detected token pool type - * @throws If no pool type can be detected - */ - static async detectPoolType( - mint: PublicKey, - context: CCIPContext, - programIds: TokenPoolProgramIds - ): Promise { - const connection = context.provider.connection; - // Create a default logger if one isn't provided in the context - const logger = - context.logger ?? - createLogger("token-pool-factory", { level: LogLevel.INFO }); - const enhanceError = createErrorEnhancer(logger); - - // Check if burn-mint pool exists for this mint - try { - // Try to create a burn-mint client and check if pool exists - const burnMintClient = new BurnMintTokenPoolClient( - context, - programIds.burnMint - ); - - logger?.debug(`Checking for burn-mint pool for mint: ${mint.toString()}`); - const hasBurnMintPool = await burnMintClient.hasPool(mint); - - if (hasBurnMintPool) { - logger?.debug(`Detected burn-mint pool for mint: ${mint.toString()}`); - return TokenPoolType.BURN_MINT; - } - } catch (error) { - logger?.debug( - `Error while checking burn-mint pool: ${ - error instanceof Error ? error.message : String(error) - }`, - { error, mint: mint.toString() } - ); - } - - // Add future pool type detection here - // This is where additional pool types would be detected in order of priority - // Each type should be wrapped in its own try-catch block so a failure in one - // doesn't prevent checking other types - - logger.debug("No burn-mint pool found, checking for other pool types..."); - - // Example of how to add support for a new pool type: - /* - try { - const newPoolTypeClient = new NewPoolTypeClient(context, programIds.newPoolType); - logger.debug(`Checking for new pool type for mint: ${mint.toString()}`); - const hasNewPoolType = await newPoolTypeClient.hasPool(mint); - - if (hasNewPoolType) { - logger?.debug(`Detected new pool type for mint: ${mint.toString()}`); - return TokenPoolType.NEW_POOL_TYPE; - } - } catch (error) { - logger?.debug( - `Error while checking new pool type: ${error instanceof Error ? error.message : String(error)}`, - { error, mint: mint.toString() } - ); - } - */ - - // For future development, consider implementing a registry of pool type - // detectors that can be iterated through, rather than hardcoding each check - - logger.info( - `No supported token pool type found for mint: ${mint.toString()}` - ); - - // If we get here, no pool type was detected - throw enhanceError( - new CCIPError("No token pool found", { mint: mint.toString() }), - { - operation: "detectPoolType", - mint: mint.toString(), - checked: [TokenPoolType.BURN_MINT], - } - ); - } -} diff --git a/ccip-lib/svm/tokenpools/index.ts b/ccip-lib/svm/tokenpools/index.ts deleted file mode 100644 index 62c0178e..00000000 --- a/ccip-lib/svm/tokenpools/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Token Pool module for CCIP Solana - * - * This module provides abstractions and implementations for different - * token pool types that can be used with CCIP. - */ - -// Export core abstractions -export * from "./abstract"; -export * from "./factory"; - -// Export specific implementations -export * from "./burnmint"; diff --git a/ccip-lib/svm/utils/pdas/index.ts b/ccip-lib/svm/utils/pdas/index.ts index c30382df..fa71f22a 100644 --- a/ccip-lib/svm/utils/pdas/index.ts +++ b/ccip-lib/svm/utils/pdas/index.ts @@ -9,4 +9,3 @@ export * from "./feeQuoter"; export * from "./rmnRemote"; export * from "./common"; export * from "./receiver"; -export * from "./tokenpool"; diff --git a/ccip-lib/svm/utils/pdas/tokenpool.ts b/ccip-lib/svm/utils/pdas/tokenpool.ts deleted file mode 100644 index 1ab505c0..00000000 --- a/ccip-lib/svm/utils/pdas/tokenpool.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { PublicKey } from "@solana/web3.js"; -import { uint64ToLE } from "./common"; - -/** - * Token Pool PDA utilities - */ - -// Token Pool seed constants (must match Rust base-token-pool constants) -export const TOKEN_POOL_STATE_SEED = "ccip_tokenpool_config"; -export const TOKEN_POOL_CHAIN_CONFIG_SEED = "ccip_tokenpool_chainconfig"; -export const TOKEN_POOL_POOL_SIGNER_SEED = "ccip_tokenpool_signer"; -export const TOKEN_POOL_RATE_LIMIT_STATE_SEED = "rate_limit_state"; -export const TOKEN_POOL_CHAIN_RATE_LIMIT_SEED = "chain_rate_limit"; -export const TOKEN_POOL_BURN_TRACKING_SEED = "burn_tracking"; -export const TOKEN_POOL_MINT_TRACKING_SEED = "mint_tracking"; -export const TOKEN_POOL_GLOBAL_CONFIG_SEED = "config"; - -// Solana system program IDs -// Use the official BPF Loader Upgradeable Program ID -// This is hardcoded because @solana/web3.js does not export it directly -export const BPF_LOADER_UPGRADEABLE_PROGRAM_ID = new PublicKey( - "BPFLoaderUpgradeab1e11111111111111111111111" -); - -/** - * Finds the State PDA for the burn-mint pool (main configuration) - * @param mint Token mint - * @param programId Burn-mint pool program ID - * @returns [PDA, bump] - */ -export function findBurnMintPoolConfigPDA( - mint: PublicKey, - programId: PublicKey -): [PublicKey, number] { - return PublicKey.findProgramAddressSync( - [Buffer.from(TOKEN_POOL_STATE_SEED), mint.toBuffer()], - programId - ); -} - -/** - * Finds the Chain Config PDA for a chain selector and token mint - * @param chainSelector Chain selector - * @param tokenMint Token mint - * @param programId Burn-mint pool program ID - * @returns [PDA, bump] - */ -export function findBurnMintPoolChainConfigPDA( - chainSelector: bigint, - tokenMint: PublicKey, - programId: PublicKey -): [PublicKey, number] { - return PublicKey.findProgramAddressSync( - [ - Buffer.from(TOKEN_POOL_CHAIN_CONFIG_SEED), - uint64ToLE(chainSelector), - tokenMint.toBuffer(), - ], - programId - ); -} - -/** - * Finds the Program Data PDA for the burn-mint pool program - * @param programId Burn-mint pool program ID - * @returns [PDA, bump] - */ -export function findProgramDataPDA(programId: PublicKey): [PublicKey, number] { - return PublicKey.findProgramAddressSync( - [programId.toBuffer()], - BPF_LOADER_UPGRADEABLE_PROGRAM_ID - ); -} - -/** - * Finds the Global Config PDA for the burn-mint pool program - * This is used for global program configuration - * @param programId Burn-mint pool program ID - * @returns [PDA, bump] - */ -export function findGlobalConfigPDA(programId: PublicKey): [PublicKey, number] { - return PublicKey.findProgramAddressSync( - [Buffer.from(TOKEN_POOL_GLOBAL_CONFIG_SEED)], - programId - ); -} - -/** - * Finds the Rate Limit State PDA for a token mint - * This is used for global rate limiting - * @param tokenMint Token mint - * @param programId Burn-mint pool program ID - * @returns [PDA, bump] - */ -export function findRateLimitStatePDA( - tokenMint: PublicKey, - programId: PublicKey -): [PublicKey, number] { - return PublicKey.findProgramAddressSync( - [Buffer.from(TOKEN_POOL_RATE_LIMIT_STATE_SEED), tokenMint.toBuffer()], - programId - ); -} - -/** - * Finds the Chain Rate Limit PDA for a chain selector and token mint - * This is used for per-chain rate limiting - * @param chainSelector Chain selector - * @param tokenMint Token mint - * @param programId Burn-mint pool program ID - * @returns [PDA, bump] - */ -export function findChainRateLimitPDA( - chainSelector: bigint, - tokenMint: PublicKey, - programId: PublicKey -): [PublicKey, number] { - return PublicKey.findProgramAddressSync( - [ - Buffer.from(TOKEN_POOL_CHAIN_RATE_LIMIT_SEED), - uint64ToLE(chainSelector), - tokenMint.toBuffer(), - ], - programId - ); -} - -/** - * Finds the Pool Signer PDA for a mint - * Used as the authority for token accounts - * @param mint Token mint - * @param programId Burn-mint pool program ID - * @returns [PDA, bump] - */ -export function findPoolSignerPDA( - mint: PublicKey, - programId: PublicKey -): [PublicKey, number] { - return PublicKey.findProgramAddressSync( - [Buffer.from(TOKEN_POOL_POOL_SIGNER_SEED), mint.toBuffer()], - programId - ); -} - -/** - * Finds the Burn Tracking PDA for a message ID - * @param messageId Message ID as byte array - * @param programId Burn-mint pool program ID - * @returns [PDA, bump] - */ -export function findBurnTrackingPDA( - messageId: Uint8Array, - programId: PublicKey -): [PublicKey, number] { - return PublicKey.findProgramAddressSync( - [Buffer.from(TOKEN_POOL_BURN_TRACKING_SEED), Buffer.from(messageId)], - programId - ); -} - -/** - * Finds the Mint Tracking PDA for a message ID - * @param messageId Message ID as byte array - * @param programId Burn-mint pool program ID - * @returns [PDA, bump] - */ -export function findMintTrackingPDA( - messageId: Uint8Array, - programId: PublicKey -): [PublicKey, number] { - return PublicKey.findProgramAddressSync( - [Buffer.from(TOKEN_POOL_MINT_TRACKING_SEED), Buffer.from(messageId)], - programId - ); -} diff --git a/ccip-lib/svm/utils/token-creation.ts b/ccip-lib/svm/utils/token-creation.ts deleted file mode 100644 index 6ba95713..00000000 --- a/ccip-lib/svm/utils/token-creation.ts +++ /dev/null @@ -1,565 +0,0 @@ -/** - * Token Creation Utilities for SPL Token and Token-2022 with Metadata - * - * This module provides utilities for creating and managing SPL Token and Token-2022 tokens - * with Metaplex metadata support, following the established patterns of the CCIP library. - */ - -import { PublicKey, Connection, Keypair } from "@solana/web3.js"; -import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from "@solana/spl-token"; -import { - Umi, - generateSigner, - keypairIdentity, - percentAmount, - publicKey as umiPublicKey, - PublicKey as UmiPublicKey, - Signer, -} from "@metaplex-foundation/umi"; -import { base58 } from "@metaplex-foundation/umi/serializers"; -import { createUmi as createUmiInstance } from "@metaplex-foundation/umi-bundle-defaults"; -import { - mplTokenMetadata, - createV1, - mintV1, - TokenStandard, -} from "@metaplex-foundation/mpl-token-metadata"; -import { - findAssociatedTokenPda, - mplToolbox, - createAssociatedToken, -} from "@metaplex-foundation/mpl-toolbox"; -import { createLogger, LogLevel } from "./logger"; -import { detectTokenProgram } from "./token"; - -/** - * Supported token programs - */ -export enum TokenProgram { - /** Legacy SPL Token Program */ - SPL_TOKEN = "spl-token", - /** Token-2022 Program with Extensions */ - TOKEN_2022 = "token-2022", -} - -/** - * Token metadata structure following Metaplex standards - */ -export interface TokenMetadata { - name: string; - symbol: string; - description: string; - image?: string; - externalUrl?: string; - attributes?: Array<{ - trait_type: string; - value: string | number; - }>; -} - -/** - * Base configuration for token creation - */ -export interface BaseTokenConfig { - /** Token name (max 32 chars) */ - name: string; - /** Token symbol (max 10 chars) */ - symbol: string; - /** Metadata URI pointing to JSON metadata */ - uri: string; - /** Number of decimal places (0-9) */ - decimals: number; - /** Initial supply to mint (optional, defaults to 0) */ - initialSupply?: bigint; - /** Seller fee basis points (0-10000, optional, defaults to 0) */ - sellerFeeBasisPoints?: number; - /** Token program to use */ - tokenProgram: TokenProgram; -} - -/** - * Configuration for creating an SPL token - */ -export interface SplTokenConfig extends Omit { - tokenProgram: TokenProgram.SPL_TOKEN; -} - -/** - * Configuration for creating a Token-2022 token - */ -export interface Token2022Config extends Omit { - tokenProgram: TokenProgram.TOKEN_2022; -} - -/** - * Union type for all token configurations - */ -export type TokenConfig = SplTokenConfig | Token2022Config; - -/** - * Result of token creation operation - */ -export interface TokenCreationResult { - /** The mint address of the created token */ - mint: PublicKey; - /** Transaction signature */ - signature: string; - /** Associated token account address (if initial supply > 0) */ - tokenAccount?: PublicKey; - /** Metaplex Umi mint signer for additional operations */ - mintSigner: Signer; -} - -/** - * Result of token minting operation - */ -export interface MintResult { - /** Transaction signature */ - signature: string; - /** Amount minted */ - amount: bigint; - /** Token account address */ - tokenAccount: PublicKey; - /** New token balance */ - newBalance: string; -} - -/** - * Options for token operations - */ -export interface TokenOperationOptions { - /** Skip transaction preflight checks */ - skipPreflight?: boolean; - /** Transaction commitment level */ - commitment?: "processed" | "confirmed" | "finalized"; - /** Logging level for operations */ - logLevel?: LogLevel; -} - -/** - * Core utilities for Token-2022 operations - */ -export class TokenCreationUtils { - private umi: Umi; - private connection: Connection; - private logger: any; - - constructor( - connection: Connection, - keypair: Keypair, - logLevel: LogLevel = LogLevel.INFO - ) { - this.connection = connection; - this.logger = createLogger("token-creation-utils", { level: logLevel }); - - this.logger.debug("Initializing TokenCreationUtils", { - rpcEndpoint: connection.rpcEndpoint, - authority: keypair.publicKey.toString(), - }); - - // Create Umi instance with the provided connection and keypair - this.umi = createUmiInstance(connection.rpcEndpoint) - .use(mplTokenMetadata()) - .use(mplToolbox()) - .use( - keypairIdentity({ - publicKey: umiPublicKey(keypair.publicKey.toBase58()), - secretKey: keypair.secretKey, - }) - ); - - this.logger.trace("Umi instance created with plugins", { - identity: this.umi.identity.publicKey, - }); - } - - /** - * Create a new token with metadata (supports both SPL Token and Token-2022) - */ - async createTokenWithMetadata( - config: TokenConfig, - options: TokenOperationOptions = {} - ): Promise { - this.logger.info(`Starting ${config.tokenProgram} creation with metadata`, { - name: config.name, - symbol: config.symbol, - decimals: config.decimals, - uri: config.uri, - initialSupply: config.initialSupply?.toString(), - sellerFeeBasisPoints: config.sellerFeeBasisPoints, - tokenProgram: config.tokenProgram, - }); - - // Validate configuration - this.validateTokenConfig(config); - this.logger.debug("Token configuration validated successfully"); - - // Generate mint signer - const mint = generateSigner(this.umi); - - // Get the appropriate token program ID - const tokenProgramId = - config.tokenProgram === TokenProgram.TOKEN_2022 - ? TOKEN_2022_PROGRAM_ID - : TOKEN_PROGRAM_ID; - const tokenProgram = umiPublicKey(tokenProgramId.toString()); - - this.logger.debug("Generated mint keypair", { - mint: mint.publicKey, - tokenProgram: tokenProgram, - }); - - try { - // Create the token with metadata - this.logger.debug("Building createV1 transaction", { - authority: this.umi.identity.publicKey, - tokenStandard: "Fungible", - }); - - const createTx = createV1(this.umi, { - mint, - authority: this.umi.identity, - name: config.name, - symbol: config.symbol, - uri: config.uri, - sellerFeeBasisPoints: percentAmount(config.sellerFeeBasisPoints || 0), - decimals: config.decimals, - splTokenProgram: tokenProgram, - tokenStandard: TokenStandard.Fungible, - }); - - this.logger.debug("Sending token creation transaction", { - commitment: options.commitment || "finalized", - skipPreflight: options.skipPreflight || false, - }); - - const signature = await createTx.sendAndConfirm(this.umi, { - confirm: { commitment: options.commitment || "finalized" }, - send: { skipPreflight: options.skipPreflight || false }, - }); - - this.logger.info(`${config.tokenProgram} token created successfully`, { - mint: mint.publicKey, - signature: base58.deserialize(signature.signature)[0], - }); - - const result: TokenCreationResult = { - mint: new PublicKey(mint.publicKey), - signature: base58.deserialize(signature.signature)[0], - mintSigner: mint, - }; - - // If initial supply is specified, mint tokens to creator - if (config.initialSupply && config.initialSupply > 0) { - this.logger.debug("Minting initial supply", { - amount: config.initialSupply.toString(), - recipient: this.umi.identity.publicKey, - }); - - const mintResult = await this.mintToAssociatedAccount( - new PublicKey(mint.publicKey), - config.initialSupply, - this.umi.identity.publicKey, - tokenProgramId, - options - ); - result.tokenAccount = mintResult.tokenAccount; - - this.logger.info("Initial supply minted", { - tokenAccount: result.tokenAccount?.toString(), - amount: config.initialSupply.toString(), - }); - } - - return result; - } catch (error) { - this.logger.error("Failed to create Token-2022", { - error: error instanceof Error ? error.message : String(error), - config, - mint: mint.publicKey, - }); - throw new Error( - `Failed to create ${config.tokenProgram} token: ${ - error instanceof Error ? error.message : String(error) - }` - ); - } - } - - /** - * Mint tokens to an associated token account - */ - async mintToAssociatedAccount( - mint: PublicKey, - amount: bigint, - recipient?: PublicKey | UmiPublicKey, - tokenProgramId?: PublicKey, - options: TokenOperationOptions = {} - ): Promise { - // If no token program specified, detect it from the mint - const resolvedTokenProgramId = tokenProgramId || await detectTokenProgram(mint, this.connection, this.logger); - - const tokenProgram = umiPublicKey(resolvedTokenProgramId.toString()); - const mintPubkey = umiPublicKey(mint.toString()); - const recipientKey = recipient - ? typeof recipient === "string" || "toBase58" in recipient - ? umiPublicKey(recipient.toString()) - : recipient - : this.umi.identity.publicKey; - - this.logger.info("Starting token mint operation", { - mint: mint.toString(), - amount: amount.toString(), - recipient: recipientKey.toString(), - }); - - try { - // Find or create the associated token account - this.logger.debug("Finding or creating ATA", { - mint: mint.toString(), - owner: recipientKey.toString(), - }); - - const tokenAccount = await this.findOrCreateATA( - mint, - recipientKey, - tokenProgramId, - options - ); - - this.logger.debug("ATA resolved for minting", { - tokenAccount: tokenAccount.toString(), - }); - - // Mint tokens - this.logger.debug("Building mintV1 transaction", { - authority: this.umi.identity.publicKey, - amount: amount.toString(), - tokenStandard: "Fungible", - }); - - const mintTx = mintV1(this.umi, { - mint: mintPubkey, - authority: this.umi.identity, - amount: amount, - token: umiPublicKey(tokenAccount.toString()), - tokenOwner: recipientKey, - tokenStandard: TokenStandard.Fungible, - splTokenProgram: tokenProgram, - }); - - this.logger.debug("Sending mint transaction", { - commitment: options.commitment || "finalized", - skipPreflight: options.skipPreflight || false, - }); - - const signature = await mintTx.sendAndConfirm(this.umi, { - confirm: { commitment: options.commitment || "finalized" }, - send: { skipPreflight: options.skipPreflight || false }, - }); - - this.logger.debug("Mint transaction confirmed", { - signature: signature.signature.toString(), - }); - - // Get updated balance - this.logger.trace("Fetching updated token balance"); - const balance = await this.connection.getTokenAccountBalance( - tokenAccount - ); - - this.logger.info("Tokens minted successfully", { - signature: base58.deserialize(signature.signature)[0], - amount: amount.toString(), - tokenAccount: tokenAccount.toString(), - newBalance: balance.value.amount, - }); - - return { - signature: base58.deserialize(signature.signature)[0], - amount, - tokenAccount, - newBalance: balance.value.amount, - }; - } catch (error) { - this.logger.error("Failed to mint tokens", { - error: error instanceof Error ? error.message : String(error), - mint: mint.toString(), - amount: amount.toString(), - recipient: recipientKey.toString(), - }); - throw new Error( - `Failed to mint tokens: ${ - error instanceof Error ? error.message : String(error) - }` - ); - } - } - - /** - * Find or create an associated token account - */ - async findOrCreateATA( - mint: PublicKey, - owner: PublicKey | UmiPublicKey, - tokenProgramId?: PublicKey, - options: TokenOperationOptions = {} - ): Promise { - // If no token program specified, detect it from the mint - const resolvedTokenProgramId = tokenProgramId || await detectTokenProgram(mint, this.connection, this.logger); - - const tokenProgram = umiPublicKey(resolvedTokenProgramId.toString()); - const mintPubkey = umiPublicKey(mint.toString()); - const ownerKey = - typeof owner === "string" || "toBase58" in owner - ? umiPublicKey(owner.toString()) - : owner; - - this.logger.debug("Finding or creating ATA", { - mint: mint.toString(), - owner: ownerKey.toString(), - tokenProgram: tokenProgram.toString(), - }); - - try { - // Find the associated token account PDA - const [tokenAccount] = findAssociatedTokenPda(this.umi, { - mint: mintPubkey, - owner: ownerKey, - tokenProgramId: tokenProgram, - }); - - this.logger.trace("Calculated ATA PDA", { - tokenAccount: tokenAccount.toString(), - }); - - // Check if the account exists - this.logger.trace("Checking if ATA exists"); - const accountInfo = await this.connection.getAccountInfo( - new PublicKey(tokenAccount) - ); - - if (!accountInfo) { - this.logger.debug("ATA does not exist, creating new account", { - tokenAccount: tokenAccount.toString(), - }); - - // Create the associated token account - const createTx = createAssociatedToken(this.umi, { - mint: mintPubkey, - owner: ownerKey, - ata: tokenAccount, - tokenProgram: tokenProgram, - }); - - this.logger.debug("Sending ATA creation transaction", { - commitment: options.commitment || "finalized", - skipPreflight: options.skipPreflight || false, - }); - - const signature = await createTx.sendAndConfirm(this.umi, { - confirm: { commitment: options.commitment || "finalized" }, - send: { skipPreflight: options.skipPreflight || false }, - }); - - this.logger.info("ATA created successfully", { - tokenAccount: tokenAccount.toString(), - signature: base58.deserialize(signature.signature)[0], - }); - } else { - this.logger.debug("ATA already exists", { - tokenAccount: tokenAccount.toString(), - }); - } - - return new PublicKey(tokenAccount); - } catch (error) { - this.logger.error("Failed to find or create ATA", { - error: error instanceof Error ? error.message : String(error), - mint: mint.toString(), - owner: ownerKey.toString(), - }); - throw new Error( - `Failed to find or create ATA: ${ - error instanceof Error ? error.message : String(error) - }` - ); - } - } - - /** - * Get token account balance - */ - async getTokenBalance(tokenAccount: PublicKey): Promise { - this.logger.trace("Fetching token account balance", { - tokenAccount: tokenAccount.toString(), - }); - - try { - const balance = await this.connection.getTokenAccountBalance( - tokenAccount - ); - - this.logger.trace("Token balance retrieved", { - tokenAccount: tokenAccount.toString(), - amount: balance.value.amount, - decimals: balance.value.decimals, - }); - - return BigInt(balance.value.amount); - } catch (error) { - this.logger.error("Failed to get token balance", { - error: error instanceof Error ? error.message : String(error), - tokenAccount: tokenAccount.toString(), - }); - throw new Error( - `Failed to get token balance: ${ - error instanceof Error ? error.message : String(error) - }` - ); - } - } - - /** - * Validate token configuration - */ - private validateTokenConfig(config: TokenConfig): void { - this.logger.trace("Validating token configuration", { config }); - - if (!config.name || config.name.length > 32) { - this.logger.error("Invalid token name", { - name: config.name, - length: config.name?.length, - }); - throw new Error("Token name must be between 1 and 32 characters"); - } - if (!config.symbol || config.symbol.length > 10) { - this.logger.error("Invalid token symbol", { - symbol: config.symbol, - length: config.symbol?.length, - }); - throw new Error("Token symbol must be between 1 and 10 characters"); - } - if (config.decimals < 0 || config.decimals > 9) { - this.logger.error("Invalid token decimals", { - decimals: config.decimals, - }); - throw new Error("Token decimals must be between 0 and 9"); - } - if (!config.uri) { - this.logger.error("Missing metadata URI"); - throw new Error("Metadata URI is required"); - } - if ( - config.sellerFeeBasisPoints && - (config.sellerFeeBasisPoints < 0 || config.sellerFeeBasisPoints > 10000) - ) { - this.logger.error("Invalid seller fee basis points", { - sellerFeeBasisPoints: config.sellerFeeBasisPoints, - }); - throw new Error("Seller fee basis points must be between 0 and 10000"); - } - - this.logger.trace("Token configuration validation passed"); - } -} diff --git a/ccip-lib/svm/utils/transaction.ts b/ccip-lib/svm/utils/transaction.ts index 260f360e..7da87e0d 100644 --- a/ccip-lib/svm/utils/transaction.ts +++ b/ccip-lib/svm/utils/transaction.ts @@ -1,14 +1,23 @@ import { Commitment, - Connection, Transaction, TransactionInstruction, } from "@solana/web3.js"; import { CCIPContext } from "../core/models"; -import { TxOptions } from "../tokenpools/abstract"; import { createErrorEnhancer } from "./errors"; import { Logger } from "./logger"; +/** + * Options for controlling Solana transaction execution. + */ +export interface TxOptions { + skipPreflight?: boolean; + preflightCommitment?: Commitment; + maxRetries?: number; + commitment?: Commitment; + confirmationCommitment?: Commitment; +} + /** * Extended options for transaction execution that includes error context */ diff --git a/ccip-scripts/README.md b/ccip-scripts/README.md index dd5b68d1..28eb0a14 100644 --- a/ccip-scripts/README.md +++ b/ccip-scripts/README.md @@ -29,9 +29,7 @@ ccip-scripts/ │ └── utils/ # EVM utility functions └── svm/ # Solana Virtual Machine scripts ā”œā”€ā”€ router/ # Cross-chain transfers and messaging - ā”œā”€ā”€ token/ # Token operations (creation, delegation) - ā”œā”€ā”€ pool/ # Token pool management - ā”œā”€ā”€ admin/ # Token admin registry operations + ā”œā”€ā”€ token/ # Token delegation and fee preparation ā”œā”€ā”€ receiver/ # CCIP message receivers └── utils/ # SVM utility functions ``` @@ -73,12 +71,10 @@ console.log("Router program ID:", svmConfig.routerProgramId); ### For Solana (SVM) Development 1. **Setup**: Install dependencies and fund wallet with SOL -2. **Create Tokens**: - - **SPL Token (Legacy)**: `yarn svm:token:create` - Maximum compatibility - - **Token-2022**: `yarn svm:token:create-2022` - Advanced features & future-proof -3. **Token Administration**: `yarn svm:admin:propose-administrator` → `yarn svm:admin:accept-admin-role` -4. **Token Pools**: `yarn svm:pool:init-global-config` → `yarn svm:pool:initialize` → `yarn svm:pool:create-token-account` -5. **CCIP Preparation**: `yarn svm:token:wrap` → `yarn svm:token:delegate` +2. **CCIP Preparation**: `yarn svm:token:wrap` → `yarn svm:token:delegate` → `yarn svm:token:check` +3. **Send messages**: `yarn svm:token-transfer` / `yarn svm:arbitrary-messaging` / `yarn svm:data-and-tokens` + +> **Cross-chain token (CCT) pool setup** moved to [ccip-solana-bs58-generator](https://github.com/smartcontractkit/ccip-solana-bs58-generator). ### For Ethereum (EVM) Development @@ -101,41 +97,11 @@ console.log("Router program ID:", svmConfig.routerProgramId); #### Token Operations -| Script | Purpose | -| ---------------------------- | --------------------------------------- | -| `yarn svm:token:create` | Create SPL Token (legacy) with metadata | -| `yarn svm:token:create-2022` | Create Token-2022 with metadata | -| `yarn svm:token:mint` | Mint tokens to specified accounts | -| `yarn svm:token:wrap` | Wrap SOL to wSOL for CCIP fees | -| `yarn svm:token:delegate` | Delegate token authority to CCIP router | -| `yarn svm:token:check` | Verify token delegations and balances | - -#### Token Pool Management - -| Script | Purpose | -| ---------------------------------------- | ---------------------------------------------- | -| `yarn svm:pool:init-global-config` | Initialize global config (once per deployment) | -| `yarn svm:pool:initialize` | Initialize token pool (once per token) | -| `yarn svm:pool:create-token-account` | Create pool token account (ATA) for transfers | -| `yarn svm:pool:get-info` | Get detailed pool configuration | -| `yarn svm:pool:set-router` | Set CCIP router for pool | -| `yarn svm:pool:get-pool-signer` | Get pool signer PDA address | -| `yarn svm:pool:init-chain-remote-config` | Initialize remote chain configuration | -| `yarn svm:pool:edit-chain-remote-config` | Edit remote chain configuration | -| `yarn svm:pool:get-chain-config` | Read remote chain configuration | -| `yarn svm:pool:transfer-mint-authority-to-multisig` | Transfer mint authority to multisig | -| `yarn svm:pool:update-self-served-allowed` | Update self-served flag for pool | - -#### Token Admin Registry - -| Script | Purpose | -| -------------------------------------- | -------------------------------------------- | -| `yarn svm:admin:propose-administrator` | Propose token administrator (mint authority) | -| `yarn svm:admin:accept-admin-role` | Accept administrator role (two-step process) | -| `yarn svm:admin:create-alt` | Create Address Lookup Table for pool | -| `yarn svm:admin:extend-alt` | Extend existing Address Lookup Table | -| `yarn svm:admin:set-pool` | Register ALT with token (administrator) | -| `yarn svm:admin:inspect-token` | Inspect token CCIP configuration | +| Script | Purpose | +| ------------------------- | --------------------------------------- | +| `yarn svm:token:wrap` | Wrap SOL to wSOL for CCIP fees | +| `yarn svm:token:delegate` | Delegate token authority to CCIP router | +| `yarn svm:token:check` | Verify token delegations and balances | #### CCIP Receivers @@ -157,6 +123,7 @@ console.log("Router program ID:", svmConfig.routerProgramId); | `yarn evm:transfer` | Transfer tokens from Ethereum to another chain | | `yarn evm:arbitrary-messaging` | Send arbitrary messages through CCIP | | `yarn evm:data-and-tokens` | Send both data and tokens in single transaction | +| `yarn evm:check-fee` | Estimate CCIP fees without sending transactions | #### Token Operations diff --git a/ccip-scripts/evm/README.md b/ccip-scripts/evm/README.md index 2a524cd3..0c75a6c4 100644 --- a/ccip-scripts/evm/README.md +++ b/ccip-scripts/evm/README.md @@ -141,6 +141,36 @@ yarn evm:data-and-tokens \ --token-receiver YourSolanaWalletAddress ``` +#### 4. Fee Estimation + +Estimate CCIP fees without sending a transaction. No private key required. + +```bash +yarn evm:check-fee +``` + +**Supported Options:** + +- `--source-chain ` - Source EVM chain (default: ethereum-sepolia) +- `--destination-chain ` - Destination chain (default: solana-devnet) +- `--token
` / `--amount ` - Simulate a token transfer +- `--data ` - Simulate a data-only message +- `--fee-token ` - Fee payment token (native, link, wrapped) +- `--log-level ` - Logging verbosity (0-5) + +**Examples:** + +```bash +# Default BnM transfer fee estimate (Sepolia → Solana Devnet) +yarn evm:check-fee + +# Custom token amount +yarn evm:check-fee --token 0x779877A7B0D9E8603169DdbD7836e478b4624789 --amount 1000000000000000000 + +# Data-only message fee estimate +yarn evm:check-fee --data "Hello Solana" +``` + ### Token Scripts #### Token Faucet (Drip) diff --git a/ccip-scripts/svm/README.md b/ccip-scripts/svm/README.md index 0216ce2e..24fb21b5 100644 --- a/ccip-scripts/svm/README.md +++ b/ccip-scripts/svm/README.md @@ -1,6 +1,6 @@ # Solana CCIP Scripts - Technical Documentation -This is the comprehensive technical guide for all Solana Virtual Machine (SVM) CCIP scripts. Each script includes detailed usage instructions, options, examples, and troubleshooting guidance. +This is the technical guide for Solana CCIP messaging, transfer, delegation, and receiver scripts. Each script includes detailed usage instructions, options, examples, and troubleshooting guidance. > šŸ“– **This is the detailed technical reference for SVM operations** > For overview and quick start: [Main README](../README.md) @@ -24,91 +24,11 @@ yarn install ## Available Scripts -### 1. Token Management Scripts +> **Cross-chain token (CCT) setup** (token pools, admin registry, ALT management) has moved to [ccip-solana-bs58-generator](https://github.com/smartcontractkit/ccip-solana-bs58-generator). This guide covers messaging, transfers, delegation, and receiver scripts only. -**āš ļø IMPORTANT:** Running the token delegation script is a prerequisite for CCIP cross-chain transfers. You must delegate authority to the CCIP router before you can send tokens or pay fees with tokens other than native SOL. +### 1. Token Preparation Scripts -#### 1.1. Create SPL Token (Legacy) - -The `create-token-metaplex.ts` script creates a new SPL Token (legacy token program) with Metaplex metadata support. This creates tokens using the original token program for compatibility with older applications. - -```bash -# Create SPL Token with default settings -yarn svm:token:create - -# Create SPL Token with custom name and symbol -yarn svm:token:create -- --name "My Token" --symbol "MTK" - -# Create SPL Token with custom metadata and supply -yarn svm:token:create -- --name "My Token" --symbol "MTK" --uri "https://example.com/metadata.json" --decimals 6 --initial-supply 5000000 - -# With debug logging -yarn svm:token:create -- --log-level DEBUG -``` - -**Key Features:** - -- Uses the legacy SPL Token Program (`TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) -- Compatible with all existing SPL token infrastructure -- Metaplex metadata support for rich token information -- Configurable decimals, supply, and metadata URI -- CLI argument parsing with sensible defaults - -#### 1.2. Create Token-2022 - -The `create-token-2022.ts` script creates a new Token-2022 token with Metaplex metadata support. Token-2022 is the newer token standard that provides enhanced functionality including native metadata support. - -```bash -# Create Token-2022 with default settings -yarn svm:token:create-2022 - -# Create Token-2022 with custom name and symbol -yarn svm:token:create-2022 -- --name "My Token" --symbol "MTK" - -# Create Token-2022 with custom metadata and supply -yarn svm:token:create-2022 -- --name "My Token" --symbol "MTK" --uri "https://example.com/metadata.json" --decimals 6 --initial-supply 5000000 - -# With debug logging -yarn svm:token:create-2022 -- --log-level DEBUG -``` - -**Key Features:** - -- Uses the Token-2022 Program (`TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`) -- Enhanced functionality with extensions support -- Native metadata support through Token Extensions -- Advanced features like transfer fees, interest-bearing tokens, etc. -- Forward-compatible with future token standard improvements - -**Common Options for Both Scripts:** - -- `--name `: Token name (max 32 characters, default: "AEM") -- `--symbol `: Token symbol (max 10 characters, default: "CCIP-AEM") -- `--uri `: Metadata URI (default: sample URI - override recommended) -- `--decimals `: Number of decimal places (0-9, default: 9) -- `--initial-supply `: Initial token supply to mint (default: 1,000,000,000,000) -- `--fee-basis-points `: Seller fee basis points (0-10000, default: 0) -- `--keypair `: Path to wallet keypair file -- `--log-level `: Log level (TRACE, DEBUG, INFO, WARN, ERROR, SILENT) -- `--skip-preflight`: Skip transaction preflight checks -- `--help, -h`: Show usage information - -**Which Token Standard Should You Choose?** - -- **SPL Token (Legacy)** (`yarn svm:token:create`): - - - āœ… Maximum compatibility with existing applications - - āœ… Smaller transaction sizes - - āœ… Lower computational requirements - - āŒ Limited extension capabilities - -- **Token-2022** (`yarn svm:token:create-2022`): - - āœ… Advanced features and extensions - - āœ… Native metadata support - - āœ… Future-proof for new functionality - - āŒ Requires Token-2022 program support in applications - -#### 1.3. Wrap SOL to wSOL +#### 1.1. Wrap SOL to wSOL The `wrap-sol.ts` script allows you to wrap native SOL into wrapped SOL (wSOL) tokens. @@ -129,7 +49,7 @@ The script: - Wraps the specified amount (1 SOL by default) into wSOL - Displays before and after balances -#### 1.4. Delegate Token Authority +#### 1.2. Delegate Token Authority The `delegate-token-authority.ts` script delegates token spending authority to the CCIP router's Program Derived Addresses (PDAs). @@ -154,9 +74,9 @@ This script: If you skip this step, your transfers will fail with permission errors. -#### 1.5. Check Token Approvals +#### 1.3. Check Token Approvals -The `check-token-approvals.ts` script checks the current delegation status of your token accounts. +The `check-token-approval.ts` script checks the current delegation status of your token accounts. ```bash # Use default keypair @@ -183,1073 +103,11 @@ So111111... | aVmjJoty... | 2000009520 | 2bsR7jPW... | 18446744073709551615 D3HCrigx... | 8U9xkMZU... | 0 | 2bsR7jPW... | 18446744073709551615 ``` -### 2. Token Pool Management - -**āš ļø IMPORTANT:** Token pool operations must follow a specific order: - -1. **Initialize Global Config** (once per program deployment) - Only by program upgrade authority -2. **Initialize Token Pool** (once per token) - By upgrade authority or mint authority -3. **Pool Management** (as needed) - Owner operations like setting router, transferring ownership - -#### 2.1. Initialize Global Config - -The `initialize-global-config.ts` script initializes the global configuration for a burn-mint token pool program. This **MUST** be run once per program deployment before any individual pools can be created. - -```bash -# Initialize global config (must be run by program upgrade authority) -yarn svm:pool:init-global-config \ - --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh - -# With debug logging -yarn svm:pool:init-global-config \ - --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh \ - --log-level DEBUG -``` - -##### Required Options - -- `--burn-mint-pool-program `: Burn-mint token pool program ID - -##### Optional Options - -- `--keypair `: Path to wallet keypair file (must be program upgrade authority) -- `--log-level `: Log level (TRACE, DEBUG, INFO, WARN, ERROR, SILENT) -- `--skip-preflight`: Skip transaction preflight checks - -##### Important Notes - -- **Authority Required**: Only the program upgrade authority can run this script -- **One-Time Operation**: This only needs to be run ONCE per program deployment -- **Prerequisite**: This must succeed before any token pools can be initialized -- **Scope**: Creates program-wide configuration, not token-specific settings - -#### 2.2. Initialize Token Pool - -The `initialize-pool.ts` script initializes a burn-mint token pool for CCIP cross-chain token transfers. - -```bash -# Initialize a token pool -yarn svm:pool:initialize \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh - -# With debug logging -yarn svm:pool:initialize \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh \ - --log-level DEBUG -``` - -#### Required Options - -- `--token-mint
`: Token mint address to create pool for -- `--burn-mint-pool-program `: Burn-mint token pool program ID - -#### Optional Options - -- `--keypair `: Path to wallet keypair file -- `--log-level `: Log level (TRACE, DEBUG, INFO, WARN, ERROR, SILENT) -- `--skip-preflight`: Skip transaction preflight checks - -This script: - -- Checks if a pool already exists for the token mint -- Initializes the burn-mint token pool with the CCIP router and RMN remote -- Sets the wallet as the pool administrator -- Verifies the pool was created successfully - -**Prerequisites:** - -1. **Global config must be initialized first** (use `yarn svm:pool:init-global-config`) -2. Token mint must already exist (use `yarn svm:token:create` to create one) -3. Wallet must have sufficient SOL balance for transaction fees (minimum 0.01 SOL) -4. Burn-mint pool program must be deployed and accessible - -#### 2.3. Create Pool Token Account - -The `create-pool-token-account.ts` script creates the Associated Token Account (ATA) for the pool signer PDA. This account is **required** for the pool to hold tokens during cross-chain operations and must be created after pool initialization. - -**āš ļø CRITICAL:** This script resolves the common "AccountNotInitialized" error that occurs during cross-chain token transfers. The pool token account must exist before attempting any CCIP transfers. - -```bash -# Create pool token account (ATA) -yarn svm:pool:create-token-account \ - --token-mint 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY \ - --burn-mint-pool-program 4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz - -# With debug logging -yarn svm:pool:create-token-account \ - --token-mint 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY \ - --burn-mint-pool-program 4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz \ - --log-level DEBUG -``` - -##### Required Options - -- `--token-mint
`: Token mint address for the pool -- `--burn-mint-pool-program `: Burn-mint token pool program ID - -##### Optional Options - -- `--keypair `: Path to wallet keypair file -- `--log-level `: Log level (TRACE, DEBUG, INFO, WARN, ERROR, SILENT) -- `--skip-preflight`: Skip transaction preflight checks - -##### What This Script Does - -The script performs the following operations: - -1. **Pool Verification**: Confirms the token pool exists and retrieves configuration -2. **PDA Calculation**: Uses library function `findPoolSignerPDA` to derive the pool signer address -3. **ATA Derivation**: Calculates the Associated Token Account address for the pool signer -4. **Existence Check**: Verifies if the ATA already exists to avoid duplicate creation -5. **Account Creation**: Creates the ATA with correct ownership (pool signer PDA) -6. **Verification**: Confirms the account was created successfully - -##### Example Output - -``` -CCIP Pool Token Account Creation - -Loading keypair from /Users/user/.config/solana/id.json... -Wallet public key: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB -Wallet balance: 11.372 SOL -Token Mint: 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY -Burn-Mint Pool Program: 4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz - -Verifying pool exists... -Getting pool information... -Current pool token account: DC4nBwHb6z5gAFJmi4Hkhn1TqaVDmhunqktSro16dAod -Pool signer PDA: 5aWw5TTbPDZvcwyy1fR6JLXS9RbG2hDPpzDtrbiEsaN8 -Expected pool token account (ATA): DC4nBwHb6z5gAFJmi4Hkhn1TqaVDmhunqktSro16dAod - -Creating pool token account (ATA)... -āœ… Pool token account created successfully! -Transaction signature: iMHGzhF9JSnSdBK1mcurSUi1m38pyiitmGNMgzqfBMhPifgj4S72Tke8j3AsKWtVeNFariU1RpaM1NLo7JB8NUc -Solana Explorer: https://explorer.solana.com/tx/iMHGzhF9...?cluster=devnet - -šŸŽ‰ Pool Token Account Setup Complete! - āœ… ATA Address: DC4nBwHb6z5gAFJmi4Hkhn1TqaVDmhunqktSro16dAod - āœ… Owner: 5aWw5TTbPDZvcwyy1fR6JLXS9RbG2hDPpzDtrbiEsaN8 (Pool Signer PDA) - āœ… Ready for cross-chain token operations -``` - -**Prerequisites:** - -- Pool must be initialized first (run `yarn svm:pool:initialize`) -- Wallet must have sufficient SOL balance for transaction fees (minimum 0.01 SOL) -- Token mint must exist and be valid -- Burn-mint pool program must be accessible - -**Technical Details:** - -- āœ… **Uses Library Functions**: Integrates with `findPoolSignerPDA` from ccip-lib for consistency -- āœ… **Automatic Detection**: Auto-detects token program ID (Token Program vs Token-2022) -- āœ… **Idempotent Operation**: Safely skips creation if account already exists -- āœ… **Proper Ownership**: Creates ATA owned by the pool signer PDA -- āœ… **Transaction Verification**: Confirms successful account creation - -**Common Error Resolution:** - -This script specifically resolves: - -- `AccountNotInitialized` errors during token transfers -- `pool_token_account` related transaction failures -- Missing ATA for pool signer PDA - -**After Running This Script:** - -- Cross-chain token transfers will work without "AccountNotInitialized" errors -- The pool can hold tokens during CCIP operations -- Ready to proceed with `yarn svm:token-transfer` - -#### 2.4. Get Pool Information - -The `get-pool-info.ts` script provides comprehensive information about an existing burn-mint token pool. This displays all configuration details, ownership information, and security settings. - -```bash -# Get detailed pool information -yarn svm:pool:get-info \ - --token-mint 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY \ - --burn-mint-pool-program 4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz - -# With debug logging -yarn svm:pool:get-info \ - --token-mint 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY \ - --burn-mint-pool-program 4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz \ - --log-level DEBUG -``` - -##### Required Options - -- `--token-mint
`: Token mint address to get information for -- `--burn-mint-pool-program `: Burn-mint token pool program ID - -##### Optional Options - -- `--keypair `: Path to wallet keypair file -- `--log-level `: Log level (TRACE, DEBUG, INFO, WARN, ERROR, SILENT) - -##### What This Script Shows - -The script provides comprehensive pool information organized into sections: - -1. **Basic Information**: Pool type, version, token mint, decimals -2. **Ownership & Permissions**: Current owner, proposed owner, rate limit admin -3. **Token Configuration**: Token program, pool signer PDA, pool token account -4. **CCIP Integration**: Router addresses, onramp authority, RMN remote -5. **Security & Controls**: Allowlist status and entries -6. **Address Summary**: Quick reference for all important addresses - -##### Example Output - -``` -================================================================================ -šŸŠ BURN-MINT TOKEN POOL INFORMATION -================================================================================ - -šŸ“‹ BASIC INFORMATION ----------------------------------------- -Pool Type: burn-mint -Version: 1 -Token Mint: 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY -Decimals: 6 - -šŸ‘„ OWNERSHIP & PERMISSIONS ----------------------------------------- -Current Owner: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB -Proposed Owner: 11111111111111111111111111111111 (default/unset) -Rate Limit Admin: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB - -šŸ”’ SECURITY & CONTROLS ----------------------------------------- -Allowlist: āŒ Disabled - -šŸ’” NEXT STEPS ----------------------------------------- -• Configure remote chains for cross-chain transfers -• Set up rate limits for security -• Configure allowlists if needed -• Transfer ownership if this is a temporary deployer -``` - -**Prerequisites:** - -- Pool must be initialized (run `yarn svm:pool:initialize` first) -- Token mint and program ID must be valid - -**Use Cases:** - -- Verify pool initialization was successful -- Check current ownership and configuration -- Audit security settings before production use -- Get addresses for integration with other tools -- Debug pool-related issues - -#### 2.5. Set Pool Router - -The `set-router.ts` script sets the configured CCIP router for an existing burn-mint token pool. This is an owner-only operation that ensures the pool uses the correct router for cross-chain operations. - -The router address is automatically loaded from the configuration, ensuring consistency with other CCIP scripts and reducing configuration errors. - -```bash -# Set the configured CCIP router for the pool -yarn svm:pool:set-router \ - --token-mint 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY \ - --burn-mint-pool-program 4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz - -# With debug logging -yarn svm:pool:set-router \ - --token-mint 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY \ - --burn-mint-pool-program 4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz \ - --log-level DEBUG -``` - -##### Required Options - -- `--token-mint
`: Token mint address of the pool -- `--burn-mint-pool-program `: Burn-mint token pool program ID - -##### Optional Options - -- `--keypair `: Path to wallet keypair file -- `--log-level `: Log level (TRACE, DEBUG, INFO, WARN, ERROR, SILENT) -- `--skip-preflight`: Skip transaction preflight checks - -##### What This Script Does - -The script performs the following operations: - -1. **Configuration Loading**: Loads the CCIP router address from the centralized configuration -2. **Validation**: Checks that the pool exists and displays current configuration -3. **Ownership Check**: Verifies that the wallet is the pool owner -4. **Duplicate Prevention**: Skips operation if router is already set to the configured router -5. **Router Update**: Executes the router change transaction -6. **Verification**: Confirms the router was successfully updated - -##### Example Output - -``` -CCIP Token Pool Set Router - -Loading keypair from /Users/user/.config/solana/id.json... -Wallet public key: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB -Wallet balance: 1.234 SOL -Token Mint: 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY -Burn-Mint Pool Program: 4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz -CCIP Router (from config): Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C - -Checking if pool exists... -Fetching current pool configuration... -Current router: HrN5BmWXq4CKQVPxZVVqVq8AJpkZvZBsVD23bF4kPq7z -Pool owner: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB - -Setting router to configured CCIP router... -Router updated successfully! -Transaction signature: 3pVb8ifuASvwB3ziqGhYtNrtoYkcqmwJVQQygaAcAP9bY94KRbu5F7173tediMcrLHUKmwu6Ust3NvnAujPTvkSk -Solana Explorer: https://explorer.solana.com/tx/3pVb8ifuASvwB3ziqGhYtNrtoYkcqmwJVQQygaAcAP9bY94KRbu5F7173tediMcrLHUKmwu6Ust3NvnAujPTvkSk?cluster=devnet - -Verifying router update... -āœ… Router update verified successfully! -Updated router: Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C - -šŸ’” View details: yarn svm:pool:get-info --token-mint 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY --burn-mint-pool-program 4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz -``` - -**Prerequisites:** - -- Pool must be initialized (run `yarn svm:pool:initialize` first) -- Wallet must be the pool owner -- Wallet must have sufficient SOL balance for transaction fees (minimum 0.01 SOL) - -**Important Security Notes:** - -- āš ļø **Owner Only**: Only the pool owner can change the router -- āš ļø **Configuration Driven**: Router address is loaded from the centralized configuration -- āš ļø **Consistency**: Ensures the same router is used across all CCIP operations -- āš ļø **Verification**: Always verify the router change was successful -- āš ļø **Testing**: Test router changes on devnet before mainnet - -**Use Cases:** - -- Set the pool router to match the current CCIP configuration -- Fix router configuration issues after pool initialization -- Update router during protocol upgrades -- Ensure consistency with other CCIP operations - -**Common Scenarios:** - -- `āœ… Router is already set to the configured CCIP router`: No change needed -- `Signer is not the owner of the pool`: Only the pool owner can set a router -- `Pool does not exist`: Initialize the pool first using `yarn svm:pool:initialize` - -**After Setting Router:** - -- Use `yarn svm:pool:get-info` to verify the change -- Test cross-chain operations to ensure router works correctly -- Router should now match the address used by other CCIP scripts - -#### 2.6. Get Pool Signer Address - -The `get-pool-signer.ts` script retrieves the Program Derived Address (PDA) for a token pool's signer account. This is a **read-only utility** that doesn't require transactions or fees. - -```bash -# Get pool signer PDA for a token -yarn svm:pool:get-pool-signer \ - --token-mint 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY \ - --burn-mint-pool-program 4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz - -# With debug logging -yarn svm:pool:get-pool-signer \ - --token-mint 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY \ - --burn-mint-pool-program 4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz \ - --log-level DEBUG -``` - -##### Required Options - -- `--token-mint
`: Token mint address -- `--burn-mint-pool-program `: Burn-mint token pool program ID - -##### Optional Options - -- `--log-level `: Log level (TRACE, DEBUG, INFO, WARN, ERROR, SILENT) - -##### What This Script Shows - -The script calculates and displays the pool signer PDA address, which is used for: - -- Token pool operations and authority -- Cross-chain transfer authorization -- Integration with other CCIP components - -**Note:** This is a read-only calculation that doesn't require a wallet, keypair, or network connection. - -**Use Cases:** - -- Get PDA addresses for integration with other tools -- Verify pool signer addresses during development -- Debug pool configuration issues -- Calculate addresses for off-chain applications - -#### 2.7. Initialize Chain Remote Configuration - -The `init-chain-remote-config.ts` script initializes a chain remote configuration for a burn-mint token pool, enabling cross-chain token transfers to a specific remote chain. - -```bash -# Initialize chain remote configuration -yarn svm:pool:init-chain-remote-config \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh \ - --remote-chain ethereum-sepolia \ - --pool-addresses "0x742d35Cc6634C0532925a3b8D5c42A2cDd1e4b6d" \ - --token-address "0xA0b86991c431e59b4b59dac67ba9b82c31a30d15c" \ - --decimals 6 - -# With debug logging -yarn svm:pool:init-chain-remote-config \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh \ - --remote-chain ethereum-sepolia \ - --pool-addresses "0x742d35Cc6634C0532925a3b8D5c42A2cDd1e4b6d" \ - --token-address "0xA0b86991c431e59b4b59dac67ba9b82c31a30d15c" \ - --decimals 6 \ - --log-level DEBUG -``` - -##### Required Options - -- `--token-mint
`: Token mint address of existing pool -- `--burn-mint-pool-program `: Burn-mint token pool program ID -- `--remote-chain `: Remote chain to configure (e.g., ethereum-sepolia, base-sepolia) -- `--pool-addresses `: Comma-separated pool addresses on remote chain (hex format) -- `--token-address
`: Token address on remote chain (hex format) -- `--decimals `: Token decimals on remote chain - -##### Optional Options - -- `--keypair `: Path to wallet keypair file -- `--log-level `: Log level (TRACE, DEBUG, INFO, WARN, ERROR, SILENT) -- `--skip-preflight`: Skip transaction preflight checks - -This script creates a new chain configuration for the specified remote chain. The chain configuration must not already exist for this operation to succeed. - -**Prerequisites:** - -- Pool must be initialized (run `yarn svm:pool:initialize` first) -- Wallet must be the pool administrator -- Wallet must have sufficient SOL balance for transaction fees (minimum 0.01 SOL) - -#### 2.8. Edit Chain Remote Configuration - -The `edit-chain-remote-config.ts` script edits an existing chain remote configuration for a burn-mint token pool, updating the configuration for cross-chain token transfers to a specific remote chain. - -```bash -# Edit existing chain remote configuration -yarn svm:pool:edit-chain-remote-config \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh \ - --remote-chain ethereum-sepolia \ - --pool-addresses "0x742d35Cc6634C0532925a3b8D5c42A2cDd1e4b6d,0x123..." \ - --token-address "0xA0b86991c431e59b4b59dac67ba9b82c31a30d15c" \ - --decimals 6 -``` - -Uses the same options as `init-chain-remote-config` but updates an existing configuration instead of creating a new one. The chain configuration must already exist for this operation to succeed. - -#### 2.9. Get Chain Configuration - -The `get-chain-config.ts` script retrieves and displays the chain remote configuration for a burn-mint token pool. This is a **read-only operation** that does not require a wallet or keypair. - -```bash -# Get chain configuration (read-only) -yarn svm:pool:get-chain-config \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh \ - --remote-chain ethereum-sepolia - -# With debug logging -yarn svm:pool:get-chain-config \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh \ - --remote-chain ethereum-sepolia \ - --log-level DEBUG -``` - -##### Required Options - -- `--token-mint
`: Token mint address of existing pool -- `--burn-mint-pool-program `: Burn-mint token pool program ID -- `--remote-chain `: Remote chain to query - -##### What This Script Shows - -- Remote chain decimals and token address -- Pool addresses on the remote chain -- Inbound and outbound rate limit configurations -- Current rate limit usage and timestamps - -**Note:** This is a read-only operation that doesn't require a wallet, keypair, or transaction fees. - -### 3. Token Admin Registry Management - -The Token Admin Registry is a critical component of CCIP that manages administrative permissions for tokens. It allows tokens to register administrators who can control pool settings and cross-chain configurations. - -**āš ļø IMPORTANT:** Token admin registry operations follow a **multi-step process**: - -1. **Propose Administrator** - Token mint authority proposes a new administrator -2. **Accept Admin Role** - Proposed administrator accepts the role to complete the transfer -3. **Create ALT** - Administrator creates Address Lookup Table with required addresses -4. **Set Pool** - Administrator registers the ALT with the token to enable CCIP operations - -#### 3.1. Propose Administrator - -The `propose-administrator.ts` script proposes a new administrator for a token's admin registry. Only the token mint authority can execute this operation. - -The router address is automatically loaded from the configuration, ensuring consistency with other CCIP scripts and reducing configuration errors. - -```bash -# Propose yourself as administrator (most common case) -yarn svm:admin:propose-administrator \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU - -# Propose someone else as administrator -yarn svm:admin:propose-administrator \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --new-admin 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T - -# With debug logging -yarn svm:admin:propose-administrator \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --log-level DEBUG -``` - -##### Required Options - -- `--token-mint
`: Token mint address - -##### Optional Options - -- `--new-admin
`: Address of the proposed new administrator (defaults to current signer) -- `--keypair `: Path to wallet keypair file -- `--log-level `: Log level (TRACE, DEBUG, INFO, WARN, ERROR, SILENT) -- `--skip-preflight`: Skip transaction preflight checks - -##### What This Script Does - -The script performs the following operations: - -1. **Default Behavior**: If `--new-admin` is not provided, uses the current signer as the proposed administrator -2. **Registry Check**: Checks if a registry already exists and shows current state -3. **Duplicate Prevention**: Skips operation if the proposed admin is already current or pending -4. **Proposal Creation**: Creates or updates the admin registry with the proposed administrator -5. **Verification**: Confirms the proposal was recorded correctly -6. **Next Steps**: Provides guidance for completing the two-step process - -##### Example Output - -``` -CCIP Token Admin Registry Propose Administrator - -Loading keypair from /Users/user/.config/solana/id.json... -Wallet public key: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB -Wallet balance: 1.234 SOL -Token Mint: 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU -New Administrator: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB - ā„¹ļø Using current signer as new admin (default behavior) -CCIP Router (from config): Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C - -Checking current token admin registry... -No existing token admin registry found -This will create a new registry with the proposed administrator - -Proposing new administrator... -Administrator proposed successfully! -Transaction signature: 3pVb8ifuASvwB3ziqGhYtNrtoYkcqmwJVQQygaAcAP9bY94KRbu5F7173tediMcrLHUKmwu6Ust3NvnAujPTvkSk -Solana Explorer: https://explorer.solana.com/tx/3pVb8ifuASvwB3ziqGhYtNrtoYkcqmwJVQQygaAcAP9bY94KRbu5F7173tediMcrLHUKmwu6Ust3NvnAujPTvkSk?cluster=devnet - -Verifying administrator proposal... -āœ… Administrator proposal verified successfully! -Pending administrator: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB -Current administrator: 11111111111111111111111111111111 - -šŸ“‹ Next Steps: - 1. You (EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB) need to accept the admin role - 2. Use: yarn svm:admin:accept-admin-role --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU - 3. You can use the same keypair to accept the role -``` - -**Prerequisites:** - -- Token mint must already exist (use `yarn svm:token:create` to create one) -- Wallet must be the token mint authority -- Wallet must have sufficient SOL balance for transaction fees (minimum 0.01 SOL) - -**Important Security Notes:** - -- āš ļø **Mint Authority Only**: Only the token mint authority can propose administrators -- āš ļø **Configuration Driven**: Router address is loaded from the centralized configuration -- āš ļø **Two-Step Process**: This is step 1 - the proposed admin must accept the role -- āš ļø **Self-Proposal**: Most commonly used to propose yourself as the administrator -- āš ļø **Verification**: Always verify the proposal was recorded correctly - -**Use Cases:** - -- Set up initial token administration after creating a token -- Transfer administrative control to a different address -- Create admin registry for tokens that will be used in CCIP pools - -**Common Scenarios:** - -- `āœ… The specified address is already the current administrator`: No change needed -- `āœ… The specified address is already the pending administrator`: The proposed admin needs to accept -- `No existing token admin registry found`: This will create a new registry - -**After Proposing Administrator:** - -- The proposed administrator must run `yarn svm:admin:accept-admin-role` to complete the transfer -- Use the registry management features to configure pools and cross-chain settings -- Verify the proposal was successful using registry query tools - -#### 3.2. Accept Admin Role - -The `accept-admin-role.ts` script accepts the administrator role for a token's admin registry. Only the proposed administrator can execute this operation. - -This is step 2 of the two-step administrator transfer process. The current signer must be the pending administrator that was previously proposed. - -```bash -# Accept administrator role (you must be the pending administrator) -yarn svm:admin:accept-admin-role \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU - -# With debug logging -yarn svm:admin:accept-admin-role \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --log-level DEBUG -``` - -##### Required Options - -- `--token-mint
`: Token mint address - -##### Optional Options - -- `--keypair `: Path to wallet keypair file -- `--log-level `: Log level (TRACE, DEBUG, INFO, WARN, ERROR, SILENT) -- `--skip-preflight`: Skip transaction preflight checks - -##### What This Script Does - -The script performs the following operations: - -1. **Validation**: Checks that a token admin registry exists for the token -2. **Authority Check**: Verifies that the signer is the pending administrator -3. **State Check**: Ensures the role transfer is valid and needed -4. **Role Acceptance**: Executes the admin role acceptance transaction -5. **Verification**: Confirms the role transfer was completed successfully -6. **Next Steps**: Provides guidance for using the new administrator permissions - -##### Example Output - -``` -CCIP Token Admin Registry Accept Admin Role - -Loading keypair from /Users/user/.config/solana/id.json... -Wallet public key: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB -Wallet balance: 1.234 SOL -Token Mint: 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU -Signer (Proposed Admin): EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB -CCIP Router (from config): Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C - -Checking current token admin registry... -Current administrator: 11111111111111111111111111111111 -Current pending administrator: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB -Lookup table: 11111111111111111111111111111111 - -Accepting administrator role... -Administrator role accepted successfully! -Transaction signature: 4mEXMxVoLt6YK8SbujJnqbQpGjL3KXTrzv8VKWzShrN5NiSvLnF7M7vw5BBkUbrwFPtYWVSjYPUYyRGaXfqKBAod -Solana Explorer: https://explorer.solana.com/tx/4mEXMxVoLt6YK8SbujJnqbQpGjL3KXTrzv8VKWzShrN5NiSvLnF7M7vw5BBkUbrwFPtYWVSjYPUYyRGaXfqKBAod?cluster=devnet - -Verifying administrator role acceptance... -āœ… Administrator role transfer verified successfully! -New administrator: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB -Pending administrator: 11111111111111111111111111111111 (should be default/cleared) - -šŸŽ‰ Administrator Role Transfer Complete! - āœ… You are now the administrator for token 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU - āœ… You can now manage pools and cross-chain configurations - āœ… Use token pool scripts to set up CCIP functionality - -šŸ“‹ Next Steps: - • Set up token pools if needed - • Configure cross-chain settings - • Register pools with the token admin registry -``` - -**Prerequisites:** - -- An administrator must have been proposed first (run `yarn svm:admin:propose-administrator`) -- Wallet must be the pending administrator for the token -- Wallet must have sufficient SOL balance for transaction fees (minimum 0.01 SOL) - -**Important Security Notes:** - -- āš ļø **Pending Admin Only**: Only the pending administrator can accept the role -- āš ļø **Configuration Driven**: Router address is loaded from the centralized configuration -- āš ļø **Final Step**: This completes the two-step administrator transfer process -- āš ļø **Verification**: Always verify the role transfer was completed successfully -- āš ļø **Registry Required**: A token admin registry must exist before accepting - -**Use Cases:** - -- Complete the administrator role transfer after being proposed -- Take control of token administration for CCIP functionality -- Finalize the setup process for cross-chain token management - -**Common Scenarios:** - -- `āœ… You are already the current administrator`: No change needed -- `Signer is not the pending administrator`: Only the pending admin can accept -- `No token admin registry found`: The admin must be proposed first - -**After Accepting Administrator Role:** - -- You are now the administrator and can manage the token's CCIP settings -- Set up token pools using `yarn svm:pool:initialize` -- Configure cross-chain settings and rate limits -- Register pools with the token admin registry using `setPool` operations - -#### 3.3. Create Address Lookup Table (ALT) - -The `create-alt.ts` script creates an Address Lookup Table for a token pool with all necessary addresses required for CCIP token operations. The ALT is essential for efficient cross-chain transactions as it reduces transaction size by allowing address references instead of full public keys. - -```bash -# Create ALT for a token pool (most common case) -yarn svm:admin:create-alt \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --pool-program BurnMintTokenPoolProgram111111111111111111 - -# Create ALT with additional custom addresses -yarn svm:admin:create-alt \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --pool-program BurnMintTokenPoolProgram111111111111111111 \ - --additional-addresses "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA,11111111111111111111111111111112" - -# With debug logging for troubleshooting -yarn svm:admin:create-alt \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --pool-program BurnMintTokenPoolProgram111111111111111111 \ - --log-level DEBUG -``` - -##### Required Options - -- `--token-mint
`: Token mint address -- `--pool-program
`: Pool program ID (e.g., burn-mint pool program) - -##### Optional Options - -- `--additional-addresses `: Comma-separated list of additional addresses to include in the ALT -- `--keypair `: Path to wallet keypair file -- `--log-level `: Log level (TRACE, DEBUG, INFO, WARN, ERROR, SILENT) -- `--skip-preflight`: Skip transaction preflight checks - -##### What This Script Does - -The script performs the following operations: - -1. **Validation**: Checks required arguments and wallet balance -2. **Configuration Loading**: Loads fee quoter and router program IDs from configuration -3. **Token Program Detection**: Automatically detects the token program from on-chain mint data -4. **ALT Creation**: Creates an Address Lookup Table with all required addresses in a single transaction -5. **Address Population**: Includes all 10 base addresses needed for token pool operations -6. **Additional Addresses**: Optionally includes custom addresses specified via --additional-addresses -7. **Verification**: Logs all addresses with descriptions for verification -8. **Next Steps**: Provides exact commands for registering the ALT with setPool - -##### ALT Address Contents - -The created ALT contains the following addresses in the exact order required by the CCIP router program: - -**Base CCIP Addresses (always included):** -- **Index 0**: Lookup table itself -- **Index 1**: Token admin registry PDA -- **Index 2**: Pool program ID -- **Index 3**: Pool configuration PDA -- **Index 4**: Pool token account (ATA) -- **Index 5**: Pool signer PDA -- **Index 6**: Token program ID (auto-detected from on-chain data) -- **Index 7**: Token mint -- **Index 8**: Fee billing token config PDA -- **Index 9**: CCIP router pool signer PDA - -**Additional Custom Addresses (optional):** -- **Index 10+**: Custom addresses specified via --additional-addresses (appended in order) - -The ALT can contain up to 256 total addresses, allowing for up to 246 additional custom addresses after the 10 base CCIP addresses. - -##### Example Output - -``` -CCIP Token Pool Address Lookup Table Creation - -Loading keypair from /Users/user/.config/solana/id.json... -Wallet public key: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB -Wallet balance: 1.234 SOL -Token Mint: 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU -Pool Program: BurnMintTokenPoolProgram111111111111111111 -Token Program: Auto-detected from on-chain mint data -Fee Quoter Program: FeeQuoterProgram11111111111111111111111111 -Router Program: Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C - -Creating Address Lookup Table... -Address Lookup Table created successfully! -ALT Address: 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T -Transaction signature: 3pVb8ifuASvwB3ziqGhYtNrtoYkcqmwJVQQygaAcAP9bY94KRbu5F7173tediMcrLHUKmwu6Ust3NvnAujPTvkSk -Solana Explorer: https://explorer.solana.com/tx/3pVb8ifuASvwB3ziqGhYtNrtoYkcqmwJVQQygaAcAP9bY94KRbu5F7173tediMcrLHUKmwu6Ust3NvnAujPTvkSk?cluster=devnet - -ALT contains 12 addresses: - [0]: 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T (Lookup table itself) - [1]: BUGuuhPsHpk8YZrL2GctsCtXGneL1gmT5zYb7eMHZDWf (Token admin registry) - [2]: BurnMintTokenPoolProgram111111111111111111 (Pool program) - [3]: H4nMZjCXbLjkMdq3HbDCX7UVVJzFCM3qoGGHgJWJk5Q2 (Pool configuration) - [4]: 9dZ1KxqT5yvEp8k5F2G3HbDCX7UVVJzFCM3qoGGHgJWJ (Pool token account) - [5]: 7cA8gBHG5yvEp8k5F2G3HbDCX7UVVJzFCM3qoGGHgJWJ (Pool signer) - [6]: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb (Token program) - [7]: 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU (Token mint) - [8]: FqConfigAddress1111111111111111111111111111 (Fee token config) - [9]: RouterPoolSignerAddress11111111111111111111 (CCIP router pool signer) - [10]: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA (Custom address 1) - [11]: 11111111111111111111111111111112 (Custom address 2) - -šŸŽ‰ ALT Creation Complete! - āœ… Address Lookup Table: 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T - āœ… Contains 10 base CCIP addresses for token pool operations - āœ… Plus 2 additional custom addresses - āœ… Total addresses: 12 - āœ… Ready to be registered with setPool - -šŸ“‹ Next Steps: - 1. Ensure you are the administrator for token 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU - 2. Register this ALT with the token using setPool: - yarn svm:admin:set-pool \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --lookup-table 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T \ - --writable-indices 3,4,5 - 3. The token will then be ready for CCIP cross-chain operations -``` - -**Prerequisites:** - -- Token mint must already exist (use `yarn svm:token:create` to create one) -- Wallet must have sufficient SOL balance for transaction fees (minimum 0.01 SOL) -- Pool program ID must be known (usually the burn-mint pool program) - -**Important Technical Notes:** - -- āš ļø **Single Transaction**: All addresses (base + additional) are created in one atomic transaction -- āš ļø **Address Order**: ALT addresses are in the exact order required by the CCIP router program -- āš ļø **Configuration Driven**: Fee quoter and router program IDs are loaded from configuration -- āš ļø **Token Program**: Automatically detected from on-chain mint data (no manual specification needed) -- āš ļø **Writable Indices**: Typically [3, 4, 7] for burn-mint tokens (pool_config, pool_token_account, token_mint) -- āš ļø **Address Count**: Always contains exactly 10 base addresses + optional additional addresses -- āš ļø **Capacity Limits**: Maximum 256 total addresses (246 additional after base 10) - -**Use Cases:** - -- Prepare for token pool registration after becoming administrator -- Create infrastructure needed for CCIP cross-chain operations -- Set up efficient transaction processing for token transfers -- Include additional custom addresses (like multisig addresses) without needing separate extension operations -- Create comprehensive ALTs for complex applications in a single transaction - -**After Creating ALT:** - -- Use the provided setPool command to register the ALT with the token -- The token will then be enabled for cross-chain operations -- ALT will be used automatically by CCIP send transactions - -#### 3.4. Set Pool (Register ALT) - -The `set-pool.ts` script registers an Address Lookup Table (ALT) with a token's admin registry, enabling the token for CCIP cross-chain operations. Only the token administrator can execute this operation. - -This is the final step in the token admin registry setup process. The ALT must be created first using the create-alt script. - -```bash -# Register ALT with token (most common case) -yarn svm:admin:set-pool \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --lookup-table 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T \ - --writable-indices 3,4,7 - -# With debug logging -yarn svm:admin:set-pool \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --lookup-table 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T \ - --writable-indices 3,4,7 \ - --log-level DEBUG -``` - -##### Required Options - -- `--token-mint
`: Token mint address -- `--lookup-table
`: Address Lookup Table address (from create-alt script) -- `--writable-indices `: Comma-separated writable indices (e.g., "3,4,7" for burn-mint tokens) - -##### Optional Options - -- `--keypair `: Path to wallet keypair file -- `--log-level `: Log level (TRACE, DEBUG, INFO, WARN, ERROR, SILENT) -- `--skip-preflight`: Skip transaction preflight checks - -##### What This Script Does - -The script performs the following operations: - -1. **Validation**: Checks required arguments and wallet balance -2. **Authority Verification**: Ensures signer is the token administrator -3. **ALT Verification**: Confirms the lookup table exists and has sufficient addresses -4. **Duplicate Prevention**: Skips operation if ALT is already registered with the token -5. **Pool Registration**: Registers the ALT with the token admin registry -6. **Verification**: Confirms the registration was completed successfully -7. **Next Steps**: Provides guidance for using the token in CCIP operations - -##### Example Output - -``` -CCIP Token Admin Registry Set Pool - -Loading keypair from /Users/user/.config/solana/id.json... -Wallet public key: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB -Wallet balance: 1.234 SOL -Token Mint: 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU -Lookup Table: 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T -Writable Indices: [3, 4, 7] - -Checking current token admin registry... -Current administrator: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB -Current pending administrator: 11111111111111111111111111111111 -Current lookup table: 11111111111111111111111111111111 - -Verifying lookup table exists... -Lookup table verified with 10 addresses - -Setting pool (registering ALT with token)... -Pool set successfully! -Transaction signature: 5xKpVb8ifuASvwB3ziqGhYtNrtoYkcqmwJVQQygaAcAP9bY94KRbu5F7173tediMcrLHUKmwu6Ust3NvnAujPTvkSk -Solana Explorer: https://explorer.solana.com/tx/5xKpVb8ifuASvwB3ziqGhYtNrtoYkcqmwJVQQygaAcAP9bY94KRbu5F7173tediMcrLHUKmwu6Ust3NvnAujPTvkSk?cluster=devnet - -Verifying pool registration... -āœ… Pool registration verified successfully! -Registered lookup table: 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T -Writable indices: [3, 4, 7] - -šŸŽ‰ Pool Registration Complete! - āœ… Token: 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU - āœ… ALT: 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T - āœ… Ready for CCIP cross-chain operations - -šŸ“‹ Next Steps: - • The token is now enabled for CCIP transfers - • Test cross-chain operations using the CCIP router scripts - • Use yarn svm:token-transfer to send tokens cross-chain - • Monitor transactions on CCIP Explorer -``` - -**Prerequisites:** - -- Administrator role must be accepted first (run the propose/accept admin scripts) -- ALT must be created first (run `yarn svm:admin:create-alt`) -- Wallet must be the token administrator -- Wallet must have sufficient SOL balance for transaction fees (minimum 0.01 SOL) - -**Important Security Notes:** - -- āš ļø **Administrator Only**: Only the token administrator can register ALTs -- āš ļø **ALT Validation**: Script validates the ALT exists and has required addresses -- āš ļø **Configuration Driven**: Router address is loaded from the centralized configuration -- āš ļø **Verification**: Always verify the pool registration was completed successfully -- āš ļø **Final Step**: This completes the token admin registry setup process - -**Use Cases:** - -- Enable a token for CCIP cross-chain operations -- Register ALT after administrator setup and ALT creation -- Update or change the ALT associated with a token - -**Common Scenarios:** - -- `āœ… Lookup table is already set to the specified address`: No change needed -- `Signer is not the administrator of this token`: Only the administrator can set pools -- `No token admin registry found`: Complete the administrator setup first -- `Lookup table not found`: Create the ALT first using create-alt script - -**After Setting Pool:** - -- The token is now fully enabled for CCIP cross-chain operations -- Test token transfers using `yarn svm:token-transfer` -- The ALT will be used automatically for efficient transaction processing -- Monitor transaction status on CCIP Explorer - -**Complete Process Summary:** - -1. **Create Token**: `yarn svm:token:create` -2. **Propose Admin**: `yarn svm:admin:propose-administrator` -3. **Accept Admin**: `yarn svm:admin:accept-admin-role` -4. **Create ALT**: `yarn svm:admin:create-alt` -5. **Set Pool**: `yarn svm:admin:set-pool` ← You are here -6. **Ready for CCIP**: Use `yarn svm:token-transfer` for cross-chain operations - -#### 3.5. Inspect Token Configuration - -The `inspect-token.ts` script inspects existing CCIP-enabled tokens to analyze their configuration. This is a **read-only diagnostic tool** that helps validate and compare token configurations with existing tokens to ensure correct setup. - -```bash -# Inspect a known CCIP-enabled token -yarn svm:admin:inspect-token \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU - -# With debug logging for detailed analysis -yarn svm:admin:inspect-token \ - --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \ - --log-level DEBUG -``` - -##### Required Options - -- `--token-mint
`: Token mint address to inspect - -##### Optional Options - -- `--keypair `: Path to wallet keypair file -- `--log-level `: Log level (TRACE, DEBUG, INFO, WARN, ERROR, SILENT) - -##### What This Script Shows - -The script provides comprehensive analysis organized into sections: - -1. **Token Admin Registry**: Administrator, pending administrator, lookup table -2. **ALT Configuration**: All 10 addresses with their purposes and write permissions -3. **Writable Indices Analysis**: Compares current vs. expected configuration [3, 4, 7] for burn-mint tokens -4. **Validation Checks**: Token mint matching, minimum address requirements -5. **Configuration Summary**: Overall correctness assessment - -**Note:** This is a read-only operation that doesn't require wallet permissions or transaction fees. - -**Use Cases:** - -- Validate configuration of existing CCIP tokens -- Compare writable indices with reference implementations -- Debug token setup issues -- Understand ALT structure for new token configurations -- Verify token admin registry settings - -### 4. CCIP Receiver Management +### 2. CCIP Receiver Management The receiver scripts allow you to deploy and manage CCIP receiver programs that can process incoming cross-chain messages. These are essential for building applications that receive data or tokens from other chains. -#### 4.1. Deploy Receiver Program +#### 2.1. Deploy Receiver Program The `deploy.ts` script deploys a new CCIP receiver program to handle incoming cross-chain messages. @@ -1267,7 +125,7 @@ This script: - Sets up the program for incoming CCIP messages - Returns the program ID for use in initialization -#### 4.2. Initialize Receiver +#### 2.2. Initialize Receiver The `initialize.ts` script initializes a receiver program to start accepting incoming CCIP messages. @@ -1285,7 +143,7 @@ This script: - Configures the receiver for CCIP message processing - Prepares storage for incoming message data -#### 4.3. Get Latest Message +#### 2.3. Get Latest Message The `get-latest-message.ts` script retrieves the latest received cross-chain message from the receiver. @@ -1303,7 +161,7 @@ This script: - Displays message content and metadata - Shows sender information and chain details -#### 4.4. Close Receiver Storage +#### 2.4. Close Receiver Storage The `close-storage.ts` script closes receiver storage accounts to reclaim rent fees. @@ -1327,7 +185,7 @@ This script: - Receiver program must be deployed before initialization - Initialization must complete before processing messages -### 5. Get CCIP Fee Estimations +### 3. Get CCIP Fee Estimations The `get-ccip-fee.ts` script provides fee estimations for cross-chain message delivery using CCIP. @@ -1390,16 +248,15 @@ yarn svm:fee -- --skip-preflight The script uses Wrapped SOL (wSOL) for fee estimations. This is configured in the script to ensure consistent fee calculation with the Solana CCIP implementation. -### 6. Send CCIP Cross-Chain Messages +### 4. Send CCIP Cross-Chain Messages -The `ccip-send.ts` script sends tokens from Solana to Ethereum using Chainlink's CCIP router. +The router scripts in `ccip-scripts/svm/router/` send messages from Solana to EVM chains using Chainlink's CCIP router. **āš ļø PREREQUISITES:** -1. For non-native fee tokens (LINK, wSOL): Run `yarn svm:token:delegate` first -2. For token transfers: Run `yarn svm:token:delegate` first -3. Ensure you have sufficient SOL for transaction fees -4. Ensure you have sufficient tokens to transfer +1. Run `yarn svm:token:delegate` before token transfers or non-native fee tokens (LINK, wSOL) +2. Ensure you have sufficient SOL for transaction fees +3. Ensure you have sufficient tokens to transfer #### Usage diff --git a/ccip-scripts/svm/admin/accept-admin-role.ts b/ccip-scripts/svm/admin/accept-admin-role.ts deleted file mode 100644 index a4902ee8..00000000 --- a/ccip-scripts/svm/admin/accept-admin-role.ts +++ /dev/null @@ -1,235 +0,0 @@ -/** - * Token Admin Registry Accept Admin Role Script (CLI Framework Version) - * - * This script accepts the administrator role for a token's admin registry. - * Only the proposed administrator can execute this operation. - * - * This is step 2 of the two-step administrator transfer process. The current - * signer must be the pending administrator that was previously proposed. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenRegistryClient } from "../../../ccip-lib/svm/core/client/tokenregistry"; -import { ChainId, getCCIPSVMConfig, resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { loadKeypair, getKeypairPath } from "../utils"; -import { LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for admin role acceptance - */ -const MIN_SOL_REQUIRED = 0.01; // Minimum SOL needed for transaction fees - -/** - * Options specific to the accept-admin-role command - */ -interface AcceptAdminRoleOptions extends BaseCommandOptions { - tokenMint: string; -} - -/** - * Token Admin Registry Accept Admin Role Command - */ -class AcceptAdminRoleCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "accept-admin-role", - description: "āœ… CCIP Token Admin Registry Role Acceptor\n\nAccepts the administrator role for a token's admin registry. Only the proposed administrator can execute this operation.", - examples: [ - "# Accept administrator role (you must be the pending administrator)", - "yarn svm:admin:accept-admin-role \\", - " --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", - "", - "# With debug logging", - "yarn svm:admin:accept-admin-role \\", - " --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \\", - " --log-level DEBUG" - ], - notes: [ - "Only the pending administrator can accept the admin role", - "This is step 2 of a 2-step process - the admin must be proposed first", - "Router program ID is automatically loaded from CCIP configuration", - "Role acceptance requires SOL for transaction fees", - "Use 'yarn svm:admin:propose-administrator' for step 1 of the process", - "Once accepted, you become the administrator and can manage the token's CCIP settings" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - } - ]; - } - - protected async execute(): Promise { - this.logger.info("CCIP Token Admin Registry - Accept Admin Role"); - this.logger.info("======================================================"); - - // Resolve network configuration based on options - const config = resolveNetworkConfig(this.options); - - // Get keypair path and load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Router Program: ${config.routerProgramId.toString()}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - - // Convert token mint string to PublicKey - let tokenMint: PublicKey; - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch (error) { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° CHECKING WALLET BALANCE"); - this.logger.info("======================================================"); - - const solBalance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalanceInSol = solBalance / LAMPORTS_PER_SOL; - - this.logger.info(`SOL Balance: ${solBalanceInSol.toFixed(9)} SOL (${solBalance} lamports)`); - - if (solBalanceInSol < MIN_SOL_REQUIRED) { - throw new Error( - `Insufficient SOL balance. Need at least ${MIN_SOL_REQUIRED} SOL for transaction fees, but you have ${solBalanceInSol.toFixed(9)} SOL.` - ); - } - - this.logger.info(`āœ… Sufficient balance for transaction fees (minimum: ${MIN_SOL_REQUIRED} SOL)`); - - // Create Token Registry client - this.logger.info(""); - this.logger.info("šŸ”— CONNECTING TO TOKEN REGISTRY"); - this.logger.info("======================================================"); - - const tokenRegistryClient = TokenRegistryClient.create( - config.connection, - walletKeypair, - config.routerProgramId.toString(), - {}, - { logLevel: this.options.logLevel } - ); - - // Get current token admin registry - this.logger.info("šŸ“‹ Fetching current token admin registry..."); - - const registry = await tokenRegistryClient.getTokenAdminRegistry(tokenMint); - - if (!registry) { - throw new Error(`No token admin registry found for token ${tokenMint.toString()}. The token must be registered first.`); - } - - this.logger.info("āœ… Token admin registry found!"); - this.logger.info(`Current Administrator: ${registry.administrator.toString()}`); - this.logger.info(`Pending Administrator: ${registry.pendingAdministrator.toString()}`); - - // Verify that the current wallet is the pending administrator - if (!registry.pendingAdministrator.equals(walletKeypair.publicKey)) { - throw new Error( - `Access denied: You are not the pending administrator for this token.\n` + - `Pending Administrator: ${registry.pendingAdministrator.toString()}\n` + - `Your Wallet: ${walletKeypair.publicKey.toString()}\n\n` + - `Only the pending administrator can accept the admin role.` - ); - } - - this.logger.info(`āœ… Verified: You are the pending administrator`); - - // Check if already the current administrator - if (registry.administrator.equals(walletKeypair.publicKey)) { - this.logger.info("ā„¹ļø You are already the current administrator for this token."); - this.logger.info("No action needed - role acceptance not required."); - return; - } - - // Accept the admin role - this.logger.info(""); - this.logger.info("šŸŽÆ ACCEPTING ADMINISTRATOR ROLE"); - this.logger.info("======================================================"); - - this.logger.info("Preparing to accept administrator role..."); - this.logger.info(`Token: ${tokenMint.toString()}`); - this.logger.info(`New Administrator (you): ${walletKeypair.publicKey.toString()}`); - this.logger.info(`Previous Administrator: ${registry.administrator.toString()}`); - - try { - const signature = await tokenRegistryClient.acceptAdminRole({ - tokenMint, - }); - - this.logger.info(""); - this.logger.info("āœ… ROLE ACCEPTANCE SUCCESSFUL!"); - this.logger.info("======================================================"); - this.logger.info(`Transaction Signature: ${signature}`); - this.logger.info(`Explorer URL: ${getExplorerUrl(config.id, signature)}`); - - this.logger.info(""); - this.logger.info("šŸ“‹ UPDATED REGISTRY INFORMATION"); - this.logger.info("======================================================"); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`New Administrator: ${walletKeypair.publicKey.toString()}`); - this.logger.info(`Previous Administrator: ${registry.administrator.toString()}`); - - this.logger.info(""); - this.logger.info("šŸŽ‰ SUCCESS!"); - this.logger.info("You are now the administrator for this token's CCIP registry."); - this.logger.info("You can now manage the token's CCIP settings and transfer administration to others."); - - this.logger.info(""); - this.logger.info("šŸ“ NEXT STEPS:"); - this.logger.info("• Use 'yarn svm:admin:set-pool' to configure token pools"); - this.logger.info("• Use 'yarn svm:admin:propose-administrator' to transfer admin rights"); - this.logger.info("• Monitor the token's CCIP operations through the explorer"); - - } catch (error) { - this.logger.error(""); - this.logger.error("āŒ FAILED TO ACCEPT ADMINISTRATOR ROLE"); - this.logger.error("======================================================"); - - if (error instanceof Error) { - this.logger.error(`Error: ${error.message}`); - - // Provide specific guidance for common errors - if (error.message.includes("unauthorized")) { - this.logger.error(""); - this.logger.error("šŸ’” TROUBLESHOOTING:"); - this.logger.error("• Ensure you are the pending administrator"); - this.logger.error("• Check that the admin role was properly proposed first"); - this.logger.error("• Verify your wallet keypair is correct"); - } else if (error.message.includes("insufficient")) { - this.logger.error(""); - this.logger.error("šŸ’” TROUBLESHOOTING:"); - this.logger.error("• Ensure you have enough SOL for transaction fees"); - this.logger.error("• Try with a higher gas fee"); - } - } else { - this.logger.error(`Unexpected error: ${String(error)}`); - } - - throw error; - } - } -} - -// Create and run the command -const command = new AcceptAdminRoleCommand(); -command.run().catch((error) => { - // Error handling is already done in the framework - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/admin/create-alt.ts b/ccip-scripts/svm/admin/create-alt.ts deleted file mode 100644 index 5caf28a7..00000000 --- a/ccip-scripts/svm/admin/create-alt.ts +++ /dev/null @@ -1,310 +0,0 @@ -/** - * CCIP Token Pool Address Lookup Table (ALT) Creation Script (CLI Framework Version) - * - * This script creates an Address Lookup Table for a token pool with all necessary addresses - * required for CCIP token operations. The ALT is essential for efficient cross-chain - * transactions as it reduces transaction size by allowing address references instead of - * full public keys. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { ChainId, getCCIPSVMConfig, resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { loadKeypair, getKeypairPath } from "../utils"; -import { LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { TokenRegistryClient } from "../../../ccip-lib/svm/core/client/tokenregistry"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for ALT creation operations - */ -const ALT_CREATION_CONFIG = { - minSolRequired: 0.01, - defaultLogLevel: LogLevel.INFO, - altAddressCount: 10, -}; - -/** - * Options specific to the create-alt command - */ -interface CreateAltOptions extends BaseCommandOptions { - tokenMint: string; - poolProgram: string; - additionalAddresses?: string; -} - -/** - * ALT Address descriptions for logging - */ -const ALT_ADDRESS_DESCRIPTIONS = [ - "Lookup table itself", - "Token admin registry", - "Pool program", - "Pool configuration", - "Pool token account", - "Pool signer", - "Token program", - "Token mint", - "Fee token config", - "CCIP router pool signer", -]; - -/** - * CCIP Token Pool Address Lookup Table Creation Command - */ -class CreateAltCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "create-alt", - description: "šŸ”§ CCIP Token Pool ALT Creator\\n\\nCreates an Address Lookup Table for a token pool with all necessary addresses required for CCIP token operations. The ALT reduces transaction size by allowing address references instead of full public keys.", - examples: [ - "# Create ALT with burn-mint pool (most common case)", - "yarn svm:admin:create-alt --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --pool-program BurnMintTokenPoolProgram111111111111111111", - "", - "# With debug logging for troubleshooting", - "yarn svm:admin:create-alt --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --pool-program BurnMintTokenPoolProgram111111111111111111 --log-level DEBUG" - ], - notes: [ - "ALT creation requires SOL for transaction fees", - "Fee quoter program ID is automatically loaded from CCIP configuration", - "Router program ID is automatically loaded from CCIP configuration", - `The created ALT contains all ${ALT_CREATION_CONFIG.altAddressCount} addresses needed for token pool operations`, - "Additional custom addresses can be specified with --additional-addresses (comma-separated)", - "All addresses (base + additional) are created in a single transaction", - "ALT capacity is limited to 256 total addresses (246 max additional after base 10)", - "After creation, use 'yarn svm:admin:set-pool' to register the ALT", - "Writable indices are typically [3, 4, 7] for pool_config, pool_token_account, pool_signer", - "ALT addresses are ordered exactly as required by the CCIP router program", - "Additional addresses are appended after the base CCIP addresses", - `Minimum ${ALT_CREATION_CONFIG.minSolRequired} SOL required for transaction fees` - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "pool-program", - required: true, - type: "string", - description: "Pool program ID (e.g., burn-mint pool program)", - example: "BurnMintTokenPoolProgram111111111111111111" - }, - { - name: "additional-addresses", - required: false, - type: "string", - description: "Comma-separated list of additional addresses to include in the ALT", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU,TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - } - ]; - } - - /** - * Validate ALT creation configuration - */ - private validateConfig(): { additionalAddresses: PublicKey[] } { - const errors: string[] = []; - - // Validate token mint address - try { - new PublicKey(this.options.tokenMint); - } catch { - errors.push("Invalid token mint address format"); - } - - // Validate pool program address - try { - new PublicKey(this.options.poolProgram); - } catch { - errors.push("Invalid pool program address format"); - } - - // Parse and validate additional addresses - let additionalAddresses: PublicKey[] = []; - if (this.options.additionalAddresses) { - try { - const addressStrings = this.options.additionalAddresses - .split(",") - .map((addr) => addr.trim()) - .filter((addr) => addr.length > 0); - - additionalAddresses = addressStrings.map((addr) => { - try { - return new PublicKey(addr); - } catch { - errors.push(`Invalid additional address format: ${addr}`); - throw new Error("Invalid address format"); - } - }); - - // Check for capacity constraints (ALT max is 256, we use 10 for default addresses) - const maxAdditional = 256 - ALT_CREATION_CONFIG.altAddressCount; - if (additionalAddresses.length > maxAdditional) { - errors.push(`Too many additional addresses. Maximum allowed: ${maxAdditional}, provided: ${additionalAddresses.length}`); - } - } catch { - errors.push("Failed to parse additional addresses"); - } - } - - if (errors.length > 0) { - throw new Error( - `Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}` - ); - } - - return { additionalAddresses }; - } - - protected async execute(): Promise { - this.logger.info("CCIP Token Pool Address Lookup Table Creation"); - this.logger.info("==================================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("==================================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalanceDisplay = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalanceDisplay.toFixed(9)} SOL)`); - - if (solBalanceDisplay < ALT_CREATION_CONFIG.minSolRequired) { - throw new Error( - `Insufficient SOL balance. Need at least ${ALT_CREATION_CONFIG.minSolRequired} SOL for transaction fees. ` + - `Current balance: ${solBalanceDisplay.toFixed(9)} SOL` - ); - } - - // Validate configuration and parse additional addresses - const { additionalAddresses } = this.validateConfig(); - - // Parse addresses - const tokenMint = new PublicKey(this.options.tokenMint); - const poolProgramId = new PublicKey(this.options.poolProgram); - const feeQuoterProgramId = config.feeQuoterProgramId; - const routerProgramId = config.routerProgramId; - - this.logger.info(""); - this.logger.info("āš™ļø ALT CONFIGURATION"); - this.logger.info("==================================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Pool Program: ${poolProgramId.toString()}`); - this.logger.info(`Fee Quoter Program: ${feeQuoterProgramId.toString()}`); - this.logger.info(`Router Program: ${routerProgramId.toString()}`); - this.logger.info(`Token Program: Auto-detected from on-chain mint data`); - - if (additionalAddresses.length > 0) { - this.logger.info(`Additional Addresses: ${additionalAddresses.length} addresses to be added`); - } - - this.logger.debug(""); - this.logger.debug("šŸ” CONFIGURATION DETAILS"); - this.logger.debug("==================================================="); - this.logger.debug(`Network: ${config.id}`); - this.logger.debug(`Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(`Commitment level: ${config.connection.commitment}`); - this.logger.debug(`Skip preflight: ${this.options.skipPreflight}`); - this.logger.debug(`Log level: ${this.options.logLevel}`); - - // Create SDK token registry client - const sdkClient = TokenRegistryClient.create( - config.connection, - walletKeypair, - routerProgramId.toString(), - {}, - { logLevel: this.options.logLevel } - ); - - // Create the ALT with all addresses in one transaction - this.logger.info(""); - this.logger.info("šŸ—ļø CREATING ADDRESS LOOKUP TABLE"); - this.logger.info("==================================================="); - const result = await sdkClient.createTokenPoolLookupTable({ - tokenMint, - poolProgramId, - feeQuoterProgramId, - additionalAddresses: additionalAddresses.length > 0 ? additionalAddresses : undefined, - }); - - // Display results - this.logger.info(""); - this.logger.info("āœ… ALT CREATED SUCCESSFULLY"); - this.logger.info("==================================================="); - this.logger.info(`ALT Address: ${result.lookupTableAddress.toString()}`); - this.logger.info(`Transaction Signature: ${result.signature}`); - this.logger.info(`Total Addresses Count: ${result.addresses.length}`); - if (additionalAddresses.length > 0) { - this.logger.info(`Base CCIP Addresses: ${ALT_CREATION_CONFIG.altAddressCount}`); - this.logger.info(`Additional Custom Addresses: ${additionalAddresses.length}`); - } - - // Log ALT contents for verification - this.logger.info(""); - this.logger.info("šŸ“‹ ALT CONTENTS"); - this.logger.info("==================================================="); - - result.addresses.forEach((addr, index) => { - if (index < ALT_CREATION_CONFIG.altAddressCount) { - // Base CCIP address - const description = ALT_ADDRESS_DESCRIPTIONS[index] || "Base CCIP account"; - this.logger.info(`[${index}]: ${addr.toString()} (${description})`); - } else { - // Additional custom address - const customIndex = index - ALT_CREATION_CONFIG.altAddressCount + 1; - this.logger.info(`[${index}]: ${addr.toString()} (Custom address ${customIndex})`); - } - }); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("==================================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, result.signature)}`); - - this.logger.info(""); - this.logger.info("šŸŽ‰ ALT Creation Complete!"); - this.logger.info(`āœ… Address Lookup Table: ${result.lookupTableAddress.toString()}`); - this.logger.info(`āœ… Contains ${ALT_CREATION_CONFIG.altAddressCount} base CCIP addresses`); - if (additionalAddresses.length > 0) { - this.logger.info(`āœ… Plus ${additionalAddresses.length} additional custom addresses`); - } - this.logger.info(`āœ… Total addresses: ${result.addresses.length}`); - this.logger.info(`āœ… Ready to be registered with setPool`); - - this.logger.info(""); - this.logger.info("šŸ“‹ NEXT STEPS"); - this.logger.info("==================================================="); - this.logger.info(`1. Ensure you are the administrator for token ${tokenMint.toString()}`); - this.logger.info(`2. Register this ALT with the token using setPool:`); - this.logger.info(` yarn svm:admin:set-pool \\\\`); - this.logger.info(` --token-mint ${tokenMint.toString()} \\\\`); - this.logger.info(` --lookup-table ${result.lookupTableAddress.toString()} \\\\`); - this.logger.info(` --writable-indices 3,4,7`); - this.logger.info(`3. The token will then be ready for CCIP cross-chain operations`); - } -} - -// Create and run the command -const command = new CreateAltCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/admin/extend-alt.ts b/ccip-scripts/svm/admin/extend-alt.ts deleted file mode 100644 index 0692d432..00000000 --- a/ccip-scripts/svm/admin/extend-alt.ts +++ /dev/null @@ -1,390 +0,0 @@ -/** - * CCIP Address Lookup Table (ALT) Extension Script (CLI Framework Version) - * - * This script extends an existing Address Lookup Table by appending new addresses. - * This is useful when you need to add additional accounts to an ALT after it has - * been created, allowing for more flexible transaction composition. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { ChainId, getCCIPSVMConfig, resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { loadKeypair, getKeypairPath } from "../utils"; -import { LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { createErrorEnhancer } from "../../../ccip-lib/svm/utils/errors"; -import { TokenRegistryClient } from "../../../ccip-lib/svm/core/client/tokenregistry"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for ALT extension operations - */ -const ALT_EXTENSION_CONFIG = { - minSolRequired: 0.01, - maxAddressesPerTx: 30, - maxAltCapacity: 256, - batchDelayMs: 2000, - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the extend-alt command - */ -interface ExtendAltOptions extends BaseCommandOptions { - lookupTableAddress: string; - addresses: string; -} - -/** - * CCIP Address Lookup Table Extension Command - */ -class ExtendAltCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "extend-alt", - description: "šŸ”§ CCIP Address Lookup Table Extender\\n\\nExtends an existing Address Lookup Table by appending new addresses. This allows for more flexible transaction composition after initial ALT creation.", - examples: [ - "# Add single address to ALT", - "yarn svm:admin:extend-alt --lookup-table-address Cc46Wp1mtci3Jm9EcH35JcDQS3rLKBWzy9mV1Kkjjw7M --addresses \"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\"", - "", - "# Add multiple addresses to ALT", - "yarn svm:admin:extend-alt --lookup-table-address Cc46Wp1mtci3Jm9EcH35JcDQS3rLKBWzy9mV1Kkjjw7M --addresses \"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU,TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA\"", - "", - "# With debug logging", - "yarn svm:admin:extend-alt --lookup-table-address Cc46Wp1mtci3Jm9EcH35JcDQS3rLKBWzy9mV1Kkjjw7M --addresses \"4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU\" --log-level DEBUG" - ], - notes: [ - "ALT extension requires SOL for transaction fees", - "You must be the authority of the ALT you want to extend", - `ALTs have a maximum capacity of ${ALT_EXTENSION_CONFIG.maxAltCapacity} addresses`, - `Large address lists are automatically batched (~${ALT_EXTENSION_CONFIG.maxAddressesPerTx} addresses per tx)`, - "Extended ALTs need 1 slot to \"warm up\" before new addresses can be used", - "New addresses are appended to the end of the existing address list", - "Use comma-separated format for multiple addresses (no spaces around commas)", - "ALT must not be frozen to allow extensions", - `Minimum ${ALT_EXTENSION_CONFIG.minSolRequired} SOL required for transaction fees` - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "lookup-table-address", - required: true, - type: "string", - description: "Address of the existing ALT to extend", - example: "Cc46Wp1mtci3Jm9EcH35JcDQS3rLKBWzy9mV1Kkjjw7M" - }, - { - name: "addresses", - required: true, - type: "string", - description: "Comma-separated list of addresses to add to the ALT", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU,TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" - } - ]; - } - - /** - * Validate ALT extension configuration - */ - private validateConfig(): { lookupTableAddress: PublicKey; addressList: PublicKey[] } { - const errors: string[] = []; - - // Validate lookup table address - let lookupTableAddress: PublicKey; - try { - lookupTableAddress = new PublicKey(this.options.lookupTableAddress); - } catch { - errors.push("Invalid lookup table address format"); - throw new Error(`Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}`); - } - - // Parse and validate addresses - let addressList: PublicKey[] = []; - try { - const addressStrings = this.options.addresses - .split(",") - .map((addr) => addr.trim()) - .filter((addr) => addr.length > 0); - - if (addressStrings.length === 0) { - errors.push("At least one address must be provided"); - } - - addressList = addressStrings.map((addr) => { - try { - return new PublicKey(addr); - } catch { - errors.push(`Invalid address format: ${addr}`); - throw new Error("Invalid address format"); - } - }); - } catch { - errors.push("Failed to parse addresses"); - } - - if (errors.length > 0) { - throw new Error( - `Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}` - ); - } - - return { lookupTableAddress, addressList }; - } - - /** - * Verify ALT exists and check authority - */ - private async verifyAltAccess( - lookupTableAddress: PublicKey, - walletPublicKey: PublicKey, - config: any - ): Promise<{ currentAddressCount: number; authority: PublicKey }> { - this.logger.info("Verifying ALT exists and checking authority..."); - - const altAccount = await config.connection.getAddressLookupTable(lookupTableAddress); - - if (!altAccount.value) { - throw new Error(`Address Lookup Table not found: ${lookupTableAddress.toString()}`); - } - - const currentAuthority = altAccount.value.state.authority; - if (!currentAuthority) { - throw new Error(`ALT has no authority (frozen): ${lookupTableAddress.toString()}`); - } - - if (!currentAuthority.equals(walletPublicKey)) { - throw new Error( - `You are not the authority of this ALT. Authority: ${currentAuthority.toString()}, Your key: ${walletPublicKey.toString()}` - ); - } - - const currentAddressCount = altAccount.value.state.addresses.length; - - this.logger.info(`āœ… ALT verified. Current authority: ${currentAuthority.toString()}`); - this.logger.info(`āœ… Current ALT contains ${currentAddressCount} addresses`); - - return { currentAddressCount, authority: currentAuthority }; - } - - /** - * Check ALT capacity constraints - */ - private checkCapacity(currentAddressCount: number, newAddressCount: number): void { - const totalAfterExtend = currentAddressCount + newAddressCount; - - if (totalAfterExtend > ALT_EXTENSION_CONFIG.maxAltCapacity) { - throw new Error( - `ALT capacity exceeded. Current: ${currentAddressCount}, Adding: ${newAddressCount}, Total would be: ${totalAfterExtend}, Max: ${ALT_EXTENSION_CONFIG.maxAltCapacity}` - ); - } - - this.logger.info( - `ALT capacity check passed: ${currentAddressCount} + ${newAddressCount} = ${totalAfterExtend} / ${ALT_EXTENSION_CONFIG.maxAltCapacity}` - ); - } - - /** - * Process address batches for extension - */ - private async processAddressBatches( - lookupTableAddress: PublicKey, - addressList: PublicKey[], - currentAddressCount: number, - tokenRegistryClient: any, - config: any - ): Promise { - // Create batches - const addressBatches: PublicKey[][] = []; - for (let i = 0; i < addressList.length; i += ALT_EXTENSION_CONFIG.maxAddressesPerTx) { - addressBatches.push(addressList.slice(i, i + ALT_EXTENSION_CONFIG.maxAddressesPerTx)); - } - - this.logger.info(`Will process ${addressBatches.length} batch(es) of addresses`); - - // Process each batch - const signatures: string[] = []; - const errorContext = { - operation: "extendALT", - lookupTableAddress: lookupTableAddress.toString(), - }; - const enhanceError = createErrorEnhancer(this.logger); - - for (let batchIndex = 0; batchIndex < addressBatches.length; batchIndex++) { - const batch = addressBatches[batchIndex]; - this.logger.info( - `Processing batch ${batchIndex + 1}/${addressBatches.length} with ${batch.length} addresses...` - ); - - try { - const result = await tokenRegistryClient.extendTokenPoolLookupTable({ - lookupTableAddress, - newAddresses: batch, - }); - - signatures.push(result.signature); - this.logger.info(`Batch ${batchIndex + 1} completed successfully! Transaction: ${result.signature}`); - this.logger.info(`Explorer: ${getExplorerUrl(config.id, result.signature)}`); - - // Wait between batches to avoid overwhelming the network - if (batchIndex < addressBatches.length - 1) { - this.logger.info(`Waiting ${ALT_EXTENSION_CONFIG.batchDelayMs / 1000} seconds before next batch...`); - await new Promise((resolve) => setTimeout(resolve, ALT_EXTENSION_CONFIG.batchDelayMs)); - } - } catch (error) { - this.logger.error(`Batch ${batchIndex + 1} failed:`, error); - throw enhanceError(error, { - ...errorContext, - batch: (batchIndex + 1).toString(), - batchSize: batch.length.toString(), - }); - } - } - - return signatures; - } - - protected async execute(): Promise { - this.logger.info("CCIP Address Lookup Table Extension"); - this.logger.info("==============================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - const walletPublicKey = walletKeypair.publicKey; - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletPublicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("==============================================="); - const balance = await config.connection.getBalance(walletPublicKey); - const solBalanceDisplay = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalanceDisplay.toFixed(9)} SOL)`); - - if (solBalanceDisplay < ALT_EXTENSION_CONFIG.minSolRequired) { - throw new Error( - `Insufficient SOL balance. Need at least ${ALT_EXTENSION_CONFIG.minSolRequired} SOL for transaction fees. ` + - `Current balance: ${solBalanceDisplay.toFixed(9)} SOL` - ); - } - - // Validate configuration and parse addresses - const { lookupTableAddress, addressList } = this.validateConfig(); - - this.logger.info(""); - this.logger.info("āš™ļø EXTENSION CONFIGURATION"); - this.logger.info("==============================================="); - this.logger.info(`ALT Address: ${lookupTableAddress.toString()}`); - this.logger.info(`Adding ${addressList.length} addresses to ALT`); - - this.logger.debug(""); - this.logger.debug("šŸ” CONFIGURATION DETAILS"); - this.logger.debug("==============================================="); - this.logger.debug(`Network: ${config.id}`); - this.logger.debug(`Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(`Commitment level: ${config.connection.commitment}`); - this.logger.debug(`Skip preflight: ${this.options.skipPreflight}`); - this.logger.debug(`Log level: ${this.options.logLevel}`); - - // Create token registry client - const tokenRegistryClient = TokenRegistryClient.create( - config.connection, - walletKeypair, - config.routerProgramId.toString(), - {}, - { logLevel: this.options.logLevel } - ); - - // Verify ALT access and get current state - this.logger.info(""); - this.logger.info("šŸ” ALT VERIFICATION"); - this.logger.info("==============================================="); - const { currentAddressCount } = await this.verifyAltAccess( - lookupTableAddress, - walletPublicKey, - config - ); - - // Check capacity constraints - this.checkCapacity(currentAddressCount, addressList.length); - - // Log the addresses being added - this.logger.info(""); - this.logger.info("šŸ“‹ ADDRESSES TO ADD"); - this.logger.info("==============================================="); - addressList.forEach((addr, index) => { - this.logger.info(`[${currentAddressCount + index}]: ${addr.toString()}`); - }); - - // Process the extension in batches - this.logger.info(""); - this.logger.info("šŸ—ļø EXTENDING ADDRESS LOOKUP TABLE"); - this.logger.info("==============================================="); - const signatures = await this.processAddressBatches( - lookupTableAddress, - addressList, - currentAddressCount, - tokenRegistryClient, - config - ); - - // Final verification - this.logger.info(""); - this.logger.info("šŸ” FINAL VERIFICATION"); - this.logger.info("==============================================="); - const updatedAltAccount = await config.connection.getAddressLookupTable(lookupTableAddress); - const totalAfterExtend = currentAddressCount + addressList.length; - - if (updatedAltAccount.value) { - const finalAddressCount = updatedAltAccount.value.state.addresses.length; - this.logger.info(`āœ… ALT extension verified! Final address count: ${finalAddressCount}`); - - if (finalAddressCount === totalAfterExtend) { - this.logger.info("āœ… All addresses added successfully!"); - } else { - this.logger.warn( - `āš ļø Address count mismatch. Expected: ${totalAfterExtend}, Actual: ${finalAddressCount}` - ); - } - } - - // Display results - this.logger.info(""); - this.logger.info("āœ… ALT EXTENSION COMPLETED"); - this.logger.info("==============================================="); - this.logger.info(`ALT Address: ${lookupTableAddress.toString()}`); - this.logger.info(`Added ${addressList.length} new addresses`); - this.logger.info(`Processed in ${signatures.length} transaction(s)`); - - // Display explorer URLs - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("==============================================="); - signatures.forEach((sig, index) => { - this.logger.info(`Batch ${index + 1}: ${getExplorerUrl(config.id, sig)}`); - }); - - this.logger.info(""); - this.logger.info("šŸŽ‰ ALT Extension Complete!"); - this.logger.info(`āœ… ALT Address: ${lookupTableAddress.toString()}`); - this.logger.info(`āœ… Added ${addressList.length} new addresses`); - this.logger.info(`āœ… Processed in ${signatures.length} transaction(s)`); - - this.logger.info(""); - this.logger.info("ā„¹ļø Note: Extended ALTs need 1 slot to \"warm up\" before new addresses can be used"); - } -} - -// Create and run the command -const command = new ExtendAltCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/admin/inspect-token.ts b/ccip-scripts/svm/admin/inspect-token.ts deleted file mode 100644 index 4a4022c4..00000000 --- a/ccip-scripts/svm/admin/inspect-token.ts +++ /dev/null @@ -1,412 +0,0 @@ -/** - * CCIP Token Configuration Inspector (CLI Framework Version) - * - * This script inspects existing CCIP-enabled tokens to analyze their configuration. - * It reads the token admin registry, fetches the ALT data, decodes writable indices, - * and compares with expected configurations. - */ - -import { PublicKey } from "@solana/web3.js"; -import { BN } from "@coral-xyz/anchor"; -import { resolveNetworkConfig } from "../../config"; -import { loadKeypair, getKeypairPath } from "../utils"; -import { LogLevel, createLogger, Logger } from "../../../ccip-lib/svm"; -import { TokenRegistryClient } from "../../../ccip-lib/svm/core/client/tokenregistry"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Options specific to the inspect-token command - */ -interface InspectTokenOptions extends BaseCommandOptions { - tokenMint: string; -} - -/** - * Decode writable indices bitmap to readable format - */ -function decodeWritableIndices( - writableIndexes: BN[], - logger?: Logger -): number[] { - // Log raw writable indexes for debugging - if (logger) { - logger.debug("Raw writable indexes before decoding:"); - writableIndexes.forEach((bn, index) => { - logger.debug( - ` [${index}]: ${bn.toString()} (hex: 0x${bn.toString(16)})` - ); - }); - } - - const writableList: number[] = []; - - // Process both 128-bit values in the array - for (let bnIndex = 0; bnIndex < writableIndexes.length; bnIndex++) { - const bitmap = writableIndexes[bnIndex]; - - // Check each bit position - for (let bitPos = 0; bitPos < 128; bitPos++) { - // Calculate the actual index based on the rust implementation - const actualIndex = bnIndex === 0 ? bitPos : 128 + bitPos; - - // Create a mask to check if this bit is set - const mask = new BN(1).shln(bnIndex === 0 ? 127 - bitPos : 255 - bitPos); - - // Check if the bit is set - if (!bitmap.and(mask).isZero()) { - writableList.push(actualIndex); - } - } - } - - return writableList.sort((a, b) => a - b); -} - -/** - * Get ALT address descriptions for better understanding - */ -function getALTAddressDescriptions(): string[] { - return [ - "Lookup table itself", - "Token admin registry PDA", - "Pool program ID", - "Pool configuration PDA", - "Pool token account (ATA)", - "Pool signer PDA", - "Token program ID", - "Token mint", - "Fee billing token config PDA", - "CCIP router pool signer PDA", - ]; -} - -/** - * Inspect Token Command - */ -class InspectTokenCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "inspect-token", - description: "šŸ” CCIP Token Configuration Inspector\n\nInspects existing CCIP-enabled tokens to analyze their configuration. Reads the token admin registry, fetches ALT data, decodes writable indices, and compares with expected configurations.", - examples: [ - "# Inspect a CCIP-enabled token", - "yarn svm:admin:inspect-token --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", - "", - "# With debug logging for detailed analysis", - "yarn svm:admin:inspect-token --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --log-level DEBUG" - ], - notes: [ - "This is a read-only operation that doesn't modify any state", - "Helps confirm correct writable indices configuration [3, 4, 7] for burn-mint tokens", - "Shows all ALT addresses with their purposes and write permissions", - "Compares with expected CCIP burn-mint configuration", - "Validates configuration of existing CCIP tokens", - "Useful for debugging token setup issues", - "Provides reference for new token configurations" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address to inspect", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - } - ]; - } - - /** - * Analyze ALT configuration and compare with expected values - */ - private analyzeALTConfiguration( - addresses: PublicKey[], - writableIndices: number[], - tokenMint: PublicKey - ) { - const descriptions = getALTAddressDescriptions(); - const expectedWritable = [3, 4, 7]; // Expected writable indices for burn-mint tokens - - this.logger.info(""); - this.logger.info("šŸ“‹ ALT CONFIGURATION ANALYSIS"); - this.logger.info( - "================================================================================" - ); - - // Display all addresses with writable status - this.logger.info(`ALT contains ${addresses.length} addresses:`); - for (let i = 0; i < addresses.length; i++) { - const isWritable = writableIndices.includes(i); - const status = isWritable ? "šŸ”“ WRITABLE" : "šŸ”’ read-ONLY"; - const description = descriptions[i] || "Additional account"; - - this.logger.info( - ` [${i}]: ${addresses[i].toString()} (${description}) - ${status}` - ); - } - - this.logger.info(""); - this.logger.info("šŸ” WRITABLE INDICES ANALYSIS"); - this.logger.info("----------------------------------------"); - this.logger.info(`Current writable indices: [${writableIndices.join(", ")}]`); - this.logger.info(`Expected writable indices: [${expectedWritable.join(", ")}]`); - - // Compare with expected configuration - const isCorrectConfig = - JSON.stringify(writableIndices.sort()) === - JSON.stringify(expectedWritable.sort()); - - if (isCorrectConfig) { - this.logger.info( - "āœ… Writable indices match expected configuration [3, 4, 7] for burn-mint tokens" - ); - } else { - this.logger.warn( - "āš ļø Writable indices differ from expected configuration [3, 4, 7] for burn-mint tokens" - ); - - // Show differences - const missing = expectedWritable.filter( - (idx) => !writableIndices.includes(idx) - ); - const extra = writableIndices.filter( - (idx) => !expectedWritable.includes(idx) - ); - - if (missing.length > 0) { - this.logger.warn(` Missing writable indices: [${missing.join(", ")}]`); - } - if (extra.length > 0) { - this.logger.warn(` Extra writable indices: [${extra.join(", ")}]`); - } - } - - this.logger.info(""); - this.logger.info("šŸ“ EXPECTED WRITABLE ACCOUNTS:"); - expectedWritable.forEach((idx) => { - const desc = descriptions[idx] || "Additional account"; - const addr = addresses[idx]?.toString() || "Not found in ALT"; - this.logger.info(` [${idx}]: ${desc} - ${addr}`); - }); - - // Validate specific requirements - this.logger.info(""); - this.logger.info("šŸ”§ VALIDATION CHECKS"); - this.logger.info("----------------------------------------"); - - // Check if token mint matches - if (addresses.length > 7 && addresses[7].equals(tokenMint)) { - this.logger.info("āœ… Token mint matches ALT address at index 7"); - } else { - this.logger.error("āŒ Token mint mismatch in ALT"); - } - - // Check minimum required addresses - if (addresses.length >= 10) { - this.logger.info("āœ… ALT contains minimum required addresses (10)"); - } else { - this.logger.warn(`āš ļø ALT has only ${addresses.length} addresses (expected 10)`); - } - - return { - isCorrectConfig, - currentWritable: writableIndices, - expectedWritable, - totalAddresses: addresses.length, - }; - } - - protected async execute(): Promise { - this.logger.info("šŸ” CCIP Token Configuration Inspector"); - this.logger.info("========================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet (optional for read-only operations) - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - let tokenMint: PublicKey; - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`CCIP Router Program: ${config.routerProgramId.toString()}`); - this.logger.info(`Network: ${config.id}`); - - this.logger.debug(`Using keypair from ${keypairPath} for connection...`); - - try { - // Create token registry client - const tokenRegistryClient = TokenRegistryClient.create( - config.connection, - walletKeypair, - config.routerProgramId.toString(), - {}, - { logLevel: this.options.logLevel } - ); - - // Fetch token admin registry - this.logger.info(""); - this.logger.info("šŸ“„ FETCHING TOKEN ADMIN REGISTRY"); - this.logger.info( - "================================================================================" - ); - - const registry = await tokenRegistryClient.getTokenAdminRegistry( - tokenMint - ); - - if (!registry) { - this.logger.error("āŒ No token admin registry found for this token"); - this.logger.info("This token is not registered with CCIP or doesn't exist"); - this.logger.info( - `Use: yarn svm:admin:propose-administrator --token-mint ${tokenMint.toString()}` - ); - throw new Error("Token admin registry not found"); - } - - // Display registry information - this.logger.info("āœ… Token admin registry found!"); - this.logger.info(`Administrator: ${registry.administrator.toString()}`); - this.logger.info( - `Pending Administrator: ${registry.pendingAdministrator.toString()}` - ); - this.logger.info(`Lookup Table: ${registry.lookupTable.toString()}`); - this.logger.info(`Mint: ${registry.mint.toString()}`); - - // Check if ALT is set - const isALTSet = !registry.lookupTable.equals(PublicKey.default); - - if (!isALTSet) { - this.logger.warn("āš ļø No ALT registered with this token"); - this.logger.info("The token has an admin registry but no pool is set"); - this.logger.info( - `Use: yarn svm:admin:create-alt --token-mint ${tokenMint.toString()}` - ); - this.logger.info(`Then: yarn svm:admin:set-pool to register the ALT`); - return; - } - - // Log raw writable indices before decoding (for debugging) - this.logger.debug("Raw writable indices from registry:"); - this.logger.debug( - ` writableIndexes: [${registry.writableIndexes - .map((bn) => bn.toString()) - .join(", ")}]` - ); - - // Decode writable indices - const writableIndices = decodeWritableIndices( - registry.writableIndexes, - this.logger - ); - this.logger.info(`Writable Indices: [${writableIndices.join(", ")}]`); - - // Fetch ALT data - this.logger.info(""); - this.logger.info("šŸ“„ FETCHING ADDRESS LOOKUP TABLE"); - this.logger.info( - "================================================================================" - ); - - const { value: lookupTableAccount } = - await config.connection.getAddressLookupTable(registry.lookupTable); - - if (!lookupTableAccount) { - this.logger.error("āŒ Address Lookup Table not found"); - this.logger.error(`ALT address: ${registry.lookupTable.toString()}`); - this.logger.info("The registry points to an ALT that doesn't exist"); - throw new Error("Address Lookup Table not found"); - } - - this.logger.info("āœ… Address Lookup Table found!"); - this.logger.info(`ALT Address: ${registry.lookupTable.toString()}`); - this.logger.info( - `Total Addresses: ${lookupTableAccount.state.addresses.length}` - ); - this.logger.info( - `Authority: ${lookupTableAccount.state.authority?.toString() || "None"}` - ); - this.logger.info( - `Last Extended Slot: ${lookupTableAccount.state.lastExtendedSlot}` - ); - - // Analyze configuration - const analysis = this.analyzeALTConfiguration( - lookupTableAccount.state.addresses, - writableIndices, - tokenMint - ); - - // Summary - this.logger.info(""); - this.logger.info("šŸ“Š CONFIGURATION SUMMARY"); - this.logger.info( - "================================================================================" - ); - - if (analysis.isCorrectConfig) { - this.logger.info("šŸŽ‰ CONFIGURATION IS CORRECT!"); - this.logger.info( - "āœ… This token follows the standard burn-mint CCIP configuration" - ); - this.logger.info( - "āœ… Writable indices: [3, 4, 7] (Pool Config, Pool Token Account, Token Mint)" - ); - this.logger.info("āœ… Ready for CCIP cross-chain burn-mint operations"); - } else { - this.logger.warn("āš ļø CONFIGURATION DIFFERS FROM STANDARD"); - this.logger.warn( - "This token uses a non-standard writable indices configuration" - ); - this.logger.warn( - "This may be intentional for lock-release tokens or specific use cases" - ); - } - - this.logger.info(""); - this.logger.info("šŸ“‹ NEXT STEPS FOR NEW TOKENS:"); - this.logger.info( - "1. Create ALT: yarn svm:admin:create-alt --token-mint --pool-program " - ); - this.logger.info( - "2. Set Pool: yarn svm:admin:set-pool --token-mint --lookup-table --writable-indices 3,4,7" - ); - this.logger.info( - "3. Test: Use this configuration as a reference for new token setups" - ); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Token Inspection Complete!"); - this.logger.info("āœ… Configuration analysis finished successfully"); - - } catch (error) { - this.logger.error( - `āŒ Token inspection failed: ${error instanceof Error ? error.message : String(error)}` - ); - - if (error instanceof Error && error.stack) { - this.logger.debug("\\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new InspectTokenCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/admin/propose-administrator.ts b/ccip-scripts/svm/admin/propose-administrator.ts deleted file mode 100644 index 0e08cd70..00000000 --- a/ccip-scripts/svm/admin/propose-administrator.ts +++ /dev/null @@ -1,267 +0,0 @@ -/** - * Token Admin Registry Propose Administrator Script (CLI Framework Version) - * - * This script proposes a new administrator for a token's admin registry. - * Only the token owner (mint authority) can execute this operation. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenRegistryClient, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { ChainId, getCCIPSVMConfig, resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { loadKeypair, getKeypairPath } from "../utils"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for admin proposal - */ -const MIN_SOL_REQUIRED = 0.01; // Minimum SOL needed for transaction fees - -/** - * Options specific to the propose-administrator command - */ -interface ProposeAdministratorOptions extends BaseCommandOptions { - tokenMint: string; - newAdmin?: string; -} - -/** - * Token Admin Registry Propose Administrator Command - */ -class ProposeAdministratorCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "propose-administrator", - description: "šŸ‘¤ CCIP Token Admin Registry Administrator Proposer\n\nProposes a new administrator for a token's admin registry. Only the token owner (mint authority) can execute this operation.", - examples: [ - "# Propose yourself as administrator (most common case)", - "yarn svm:admin:propose-administrator \\", - " --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", - "", - "# Propose someone else as administrator", - "yarn svm:admin:propose-administrator \\", - " --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \\", - " --new-admin 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T", - "", - "# With debug logging", - "yarn svm:admin:propose-administrator \\", - " --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \\", - " --log-level DEBUG" - ], - notes: [ - "Only the token mint authority can propose an administrator", - "Router program ID is automatically loaded from CCIP configuration", - "If --new-admin is not provided, the current signer will be proposed as admin", - "This is step 1 of a 2-step process - the proposed admin must accept the role", - "Proposal requires SOL for transaction fees", - "Use 'yarn svm:admin:accept-admin-role' for the proposed admin to complete the transfer", - "Use 'yarn svm:admin:get-registry' to view current registry configuration" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "new-admin", - required: false, - type: "string", - description: "Address of the proposed new administrator (defaults to current signer if not provided)", - example: "8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T" - } - ]; - } - - protected async execute(): Promise { - this.logger.info("CCIP Token Admin Registry - Propose Administrator"); - this.logger.info("========================================================="); - - // Resolve network configuration based on options - const config = resolveNetworkConfig(this.options); - - // Get keypair path and load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Router Program: ${config.routerProgramId.toString()}`); - this.logger.info(`Wallet (Mint Authority): ${walletKeypair.publicKey.toString()}`); - - // Convert token mint string to PublicKey - let tokenMint: PublicKey; - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch (error) { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - - // Determine new admin - use current signer if not provided - let newAdminPublicKey: PublicKey; - if (this.options.newAdmin) { - try { - newAdminPublicKey = new PublicKey(this.options.newAdmin); - this.logger.info(`Proposed New Administrator: ${newAdminPublicKey.toString()}`); - } catch (error) { - throw new Error(`Invalid new admin address: ${this.options.newAdmin}`); - } - } else { - newAdminPublicKey = walletKeypair.publicKey; - this.logger.info(`Proposed New Administrator: ${newAdminPublicKey.toString()} (current signer)`); - } - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° CHECKING WALLET BALANCE"); - this.logger.info("========================================================="); - - const solBalance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalanceInSol = solBalance / LAMPORTS_PER_SOL; - - this.logger.info(`SOL Balance: ${solBalanceInSol.toFixed(9)} SOL (${solBalance} lamports)`); - - if (solBalanceInSol < MIN_SOL_REQUIRED) { - throw new Error( - `Insufficient SOL balance. Need at least ${MIN_SOL_REQUIRED} SOL for transaction fees, but you have ${solBalanceInSol.toFixed(9)} SOL.` - ); - } - - this.logger.info(`āœ… Sufficient balance for transaction fees (minimum: ${MIN_SOL_REQUIRED} SOL)`); - - // Create Token Registry client - this.logger.info(""); - this.logger.info("šŸ”— CONNECTING TO TOKEN REGISTRY"); - this.logger.info("========================================================="); - - const tokenRegistryClient = TokenRegistryClient.create( - config.connection, - walletKeypair, - config.routerProgramId.toString(), - {}, - { logLevel: this.options.logLevel } - ); - - // Check if registry already exists - this.logger.info("šŸ“‹ Checking existing token admin registry..."); - - const existingRegistry = await tokenRegistryClient.getTokenAdminRegistry(tokenMint); - - if (existingRegistry) { - this.logger.info("āœ… Token admin registry found!"); - this.logger.info(`Current Administrator: ${existingRegistry.administrator.toString()}`); - this.logger.info(`Current Pending Administrator: ${existingRegistry.pendingAdministrator.toString()}`); - - // Check if already the proposed admin - if (existingRegistry.pendingAdministrator.equals(newAdminPublicKey)) { - this.logger.info(""); - this.logger.info("ā„¹ļø ALREADY PROPOSED"); - this.logger.info("========================================================="); - this.logger.info(`${newAdminPublicKey.toString()} is already the pending administrator.`); - this.logger.info("No action needed - use 'yarn svm:admin:accept-admin-role' to complete the transfer."); - return; - } - - // Check if already the current admin - if (existingRegistry.administrator.equals(newAdminPublicKey)) { - this.logger.info(""); - this.logger.info("ā„¹ļø ALREADY ADMINISTRATOR"); - this.logger.info("========================================================="); - this.logger.info(`${newAdminPublicKey.toString()} is already the current administrator.`); - this.logger.info("No action needed - they are already in control of this token's CCIP registry."); - return; - } - } else { - this.logger.info("šŸ“ No existing registry found - will create new one"); - } - - // Propose the administrator - this.logger.info(""); - this.logger.info("šŸŽÆ PROPOSING ADMINISTRATOR"); - this.logger.info("========================================================="); - - this.logger.info("Preparing to propose administrator..."); - this.logger.info(`Token: ${tokenMint.toString()}`); - this.logger.info(`Proposed Administrator: ${newAdminPublicKey.toString()}`); - this.logger.info(`Mint Authority (you): ${walletKeypair.publicKey.toString()}`); - - try { - const signature = await tokenRegistryClient.proposeAdministrator({ - tokenMint, - newAdmin: newAdminPublicKey, - }); - - this.logger.info(""); - this.logger.info("āœ… ADMINISTRATOR PROPOSAL SUCCESSFUL!"); - this.logger.info("========================================================="); - this.logger.info(`Transaction Signature: ${signature}`); - this.logger.info(`Explorer URL: ${getExplorerUrl(config.id, signature)}`); - - this.logger.info(""); - this.logger.info("šŸ“‹ REGISTRY INFORMATION"); - this.logger.info("========================================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Proposed Administrator: ${newAdminPublicKey.toString()}`); - this.logger.info(`Registry Created/Updated By: ${walletKeypair.publicKey.toString()}`); - - this.logger.info(""); - this.logger.info("šŸŽ‰ SUCCESS!"); - this.logger.info(`Administrator proposal completed successfully!`); - - if (newAdminPublicKey.equals(walletKeypair.publicKey)) { - this.logger.info("Since you proposed yourself, you can now accept the role."); - this.logger.info(""); - this.logger.info("šŸ“ NEXT STEP:"); - this.logger.info(`yarn svm:admin:accept-admin-role --token-mint ${tokenMint.toString()}`); - } else { - this.logger.info(`The proposed administrator must now accept the role.`); - this.logger.info(""); - this.logger.info("šŸ“ NEXT STEP FOR THE PROPOSED ADMIN:"); - this.logger.info(`yarn svm:admin:accept-admin-role --token-mint ${tokenMint.toString()}`); - this.logger.info(`(Must be run by: ${newAdminPublicKey.toString()})`); - } - - } catch (error) { - this.logger.error(""); - this.logger.error("āŒ FAILED TO PROPOSE ADMINISTRATOR"); - this.logger.error("========================================================="); - - if (error instanceof Error) { - this.logger.error(`Error: ${error.message}`); - - // Provide specific guidance for common errors - if (error.message.includes("unauthorized") || error.message.includes("mint authority")) { - this.logger.error(""); - this.logger.error("šŸ’” TROUBLESHOOTING:"); - this.logger.error("• Ensure you are the mint authority for this token"); - this.logger.error("• Verify your wallet keypair is correct"); - this.logger.error("• Check that the token mint address is valid"); - } else if (error.message.includes("insufficient")) { - this.logger.error(""); - this.logger.error("šŸ’” TROUBLESHOOTING:"); - this.logger.error("• Ensure you have enough SOL for transaction fees"); - this.logger.error("• Try with a higher gas fee"); - } - } else { - this.logger.error(`Unexpected error: ${String(error)}`); - } - - throw error; - } - } -} - -// Create and run the command -const command = new ProposeAdministratorCommand(); -command.run().catch((error) => { - // Error handling is already done in the framework - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/admin/set-pool.ts b/ccip-scripts/svm/admin/set-pool.ts deleted file mode 100644 index eea29cc3..00000000 --- a/ccip-scripts/svm/admin/set-pool.ts +++ /dev/null @@ -1,435 +0,0 @@ -/** - * Token Admin Registry Set Pool Script (CLI Framework Version) - * - * This script registers an Address Lookup Table (ALT) with a token's admin registry, - * enabling the token for CCIP cross-chain operations. Only the token administrator - * can execute this operation. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenRegistryClient } from "../../../ccip-lib/svm/core/client/tokenregistry"; -import { ChainId, getCCIPSVMConfig, resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { loadKeypair, getKeypairPath } from "../utils"; -import { LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for set pool operations - */ -const SET_POOL_CONFIG = { - minSolRequired: 0.01, - minAltAddresses: 7, - defaultLogLevel: LogLevel.INFO, - commonWritableIndices: [3, 4, 7], // pool_config, pool_token_account, token_mint -}; - -/** - * Options specific to the set-pool command - */ -interface SetPoolOptions extends BaseCommandOptions { - tokenMint: string; - lookupTable: string; - writableIndices: string; -} - -/** - * Token Admin Registry Set Pool Command - */ -class SetPoolCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "set-pool", - description: "šŸŠ CCIP Token Admin Registry Pool Setter\\n\\nRegisters an Address Lookup Table (ALT) with a token's admin registry, enabling the token for CCIP cross-chain operations. Only the token administrator can execute this operation.", - examples: [ - "# Set pool with typical writable indices for burn-mint tokens (most common case)", - "yarn svm:admin:set-pool --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --lookup-table 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T --writable-indices 3,4,7", - "", - "# With debug logging", - "yarn svm:admin:set-pool --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --lookup-table 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T --writable-indices 3,4,7 --log-level DEBUG" - ], - notes: [ - "Only the token administrator can set the pool", - "The ALT must be created first using 'yarn svm:admin:create-alt'", - `Writable indices are typically [${SET_POOL_CONFIG.commonWritableIndices.join(", ")}] for burn-mint tokens (pool_config, pool_token_account, token_mint)`, - "Pool registration requires SOL for transaction fees", - "This enables the token for CCIP cross-chain operations", - "Use 'yarn svm:admin:propose-administrator' and 'yarn svm:admin:accept-admin-role' to become administrator", - "Verify registration with token admin registry query tools", - `Minimum ${SET_POOL_CONFIG.minSolRequired} SOL required for transaction fees` - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "lookup-table", - required: true, - type: "string", - description: "Address Lookup Table address (from create-alt script)", - example: "8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T" - }, - { - name: "writable-indices", - required: true, - type: "string", - description: `Comma-separated writable indices (e.g., "${SET_POOL_CONFIG.commonWritableIndices.join(",")}" for burn-mint)`, - example: "3,4,7" - } - ]; - } - - /** - * Validate set pool configuration - */ - private validateConfig(): { tokenMint: PublicKey; lookupTableAddress: PublicKey; writableIndices: number[] } { - const errors: string[] = []; - - // Validate token mint address - let tokenMint: PublicKey; - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - errors.push("Invalid token mint address format"); - throw new Error(`Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}`); - } - - // Validate lookup table address - let lookupTableAddress: PublicKey; - try { - lookupTableAddress = new PublicKey(this.options.lookupTable); - } catch { - errors.push("Invalid lookup table address format"); - throw new Error(`Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}`); - } - - // Parse and validate writable indices - let writableIndices: number[]; - try { - writableIndices = this.options.writableIndices - .split(",") - .map((index) => { - const num = Number(index.trim()); - if (isNaN(num)) { - throw new Error(`Invalid writable index: ${index}`); - } - return num; - }); - - if (writableIndices.length === 0) { - errors.push("At least one writable index must be provided"); - } - } catch (error) { - errors.push("Invalid writable indices format. Use comma-separated numbers (e.g., '3,4,7' for burn-mint tokens)"); - throw new Error(`Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}`); - } - - if (errors.length > 0) { - throw new Error( - `Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}` - ); - } - - return { tokenMint, lookupTableAddress, writableIndices }; - } - - /** - * Check token admin registry status and permissions - */ - private async checkTokenAdminRegistry( - tokenMint: PublicKey, - walletPublicKey: PublicKey, - lookupTableAddress: PublicKey, - tokenRegistryClient: any - ): Promise { - this.logger.info("Checking current token admin registry..."); - this.logger.debug(`Checking registry for mint: ${tokenMint.toString()}`); - - try { - const currentRegistry = await tokenRegistryClient.getTokenAdminRegistry(tokenMint); - - if (!currentRegistry) { - throw new Error( - "No token admin registry found for this token\\n" + - "You must first propose and accept an administrator for this token\\n" + - `Use: yarn svm:admin:propose-administrator --token-mint ${tokenMint.toString()}` - ); - } - - this.logger.info(`Current administrator: ${currentRegistry.administrator.toString()}`); - this.logger.info(`Current pending administrator: ${currentRegistry.pendingAdministrator.toString()}`); - this.logger.info(`Current lookup table: ${currentRegistry.lookupTable.toString()}`); - - // Check if signer is the administrator - if (!currentRegistry.administrator.equals(walletPublicKey)) { - throw new Error( - `Signer is not the administrator of this token\\n` + - `Required: ${currentRegistry.administrator.toString()}\\n` + - `Provided: ${walletPublicKey.toString()}\\n` + - `Only the token administrator can set the pool` - ); - } - - // Check if lookup table is already set to the same value - if (currentRegistry.lookupTable.equals(lookupTableAddress)) { - this.logger.info("āœ… Lookup table is already set to the specified address"); - this.logger.info("No changes needed"); - return null; // Signal that no operation is needed - } - - this.logger.debug("Current registry details:", { - administrator: currentRegistry.administrator.toString(), - pendingAdministrator: currentRegistry.pendingAdministrator.toString(), - lookupTable: currentRegistry.lookupTable.toString(), - mint: currentRegistry.mint.toString(), - }); - - return currentRegistry; - } catch (error) { - if (error instanceof Error && error.message.includes("Configuration validation failed")) { - throw error; - } - throw new Error( - `Failed to fetch token admin registry: ${error instanceof Error ? error.message : String(error)}\\n` + - `Ensure the token has an admin registry before setting the pool` - ); - } - } - - /** - * Verify the lookup table exists and is valid - */ - private async verifyLookupTable(lookupTableAddress: PublicKey, config: any): Promise { - this.logger.info("Verifying lookup table exists..."); - this.logger.debug(`Checking ALT at address: ${lookupTableAddress.toString()}`); - - try { - const { value: lookupTableAccount } = await config.connection.getAddressLookupTable(lookupTableAddress); - - if (!lookupTableAccount) { - throw new Error( - `Lookup table not found: ${lookupTableAddress.toString()}\\n` + - `Create the lookup table first using: yarn svm:admin:create-alt` - ); - } - - const addressCount = lookupTableAccount.state.addresses.length; - this.logger.info(`Lookup table verified with ${addressCount} addresses`); - - if (addressCount < SET_POOL_CONFIG.minAltAddresses) { - this.logger.warn( - `Lookup table has only ${addressCount} addresses (expected at least ${SET_POOL_CONFIG.minAltAddresses} for CCIP operations)` - ); - this.logger.info("Ensure the lookup table was created with create-alt script"); - } - - this.logger.debug("Lookup table details:", { - address: lookupTableAddress.toString(), - addressCount: addressCount, - authority: lookupTableAccount.state.authority?.toString() || "None", - lastExtendedSlot: lookupTableAccount.state.lastExtendedSlot, - }); - } catch (error) { - if (error instanceof Error && error.message.includes("Configuration validation failed")) { - throw error; - } - throw new Error( - `Failed to verify lookup table: ${error instanceof Error ? error.message : String(error)}\\n` + - `Ensure the lookup table address is correct and exists` - ); - } - } - - /** - * Verify pool registration was successful - */ - private async verifyPoolRegistration( - tokenMint: PublicKey, - lookupTableAddress: PublicKey, - writableIndices: number[], - tokenRegistryClient: any - ): Promise { - this.logger.info("Verifying pool registration..."); - this.logger.debug("Attempting to fetch updated registry to verify pool..."); - - try { - const updatedRegistry = await tokenRegistryClient.getTokenAdminRegistry(tokenMint); - - if (!updatedRegistry) { - this.logger.warn( - "Pool registration succeeded but registry not found during verification\\n" + - "This may be due to network delays - the registration should be recorded shortly" - ); - return; - } - - const currentLookupTable = updatedRegistry.lookupTable.toString(); - - if (updatedRegistry.lookupTable.equals(lookupTableAddress)) { - this.logger.info("āœ… Pool registration verified successfully!"); - this.logger.info(`Registered lookup table: ${currentLookupTable}`); - this.logger.info(`Writable indices: [${writableIndices.join(", ")}]`); - - this.logger.debug("Pool verification details:", { - administrator: updatedRegistry.administrator.toString(), - lookupTable: currentLookupTable, - registeredLookupTable: lookupTableAddress.toString(), - mint: updatedRegistry.mint.toString(), - }); - } else { - this.logger.warn( - "Pool registration completed but verification shows different lookup table\\n" + - `Expected: ${lookupTableAddress.toString()}\\n` + - `Actual: ${currentLookupTable}` - ); - } - - this.logger.trace("Complete verification info:", updatedRegistry); - } catch (error) { - this.logger.warn( - `Pool registration succeeded but verification failed: ${error instanceof Error ? error.message : String(error)}\\n` + - `This may be due to network delays - the registration should be recorded shortly` - ); - this.logger.debug("Verification error details:", error); - } - } - - protected async execute(): Promise { - this.logger.info("CCIP Token Admin Registry Set Pool"); - this.logger.info("============================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - const walletPublicKey = walletKeypair.publicKey; - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletPublicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("============================================="); - const balance = await config.connection.getBalance(walletPublicKey); - const solBalanceDisplay = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalanceDisplay.toFixed(9)} SOL)`); - - if (solBalanceDisplay < SET_POOL_CONFIG.minSolRequired) { - throw new Error( - `Insufficient SOL balance. Need at least ${SET_POOL_CONFIG.minSolRequired} SOL for transaction fees. ` + - `Current balance: ${solBalanceDisplay.toFixed(9)} SOL` - ); - } - - // Validate configuration and parse parameters - const { tokenMint, lookupTableAddress, writableIndices } = this.validateConfig(); - - this.logger.info(""); - this.logger.info("āš™ļø POOL CONFIGURATION"); - this.logger.info("============================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Lookup Table: ${lookupTableAddress.toString()}`); - this.logger.info(`Writable Indices: [${writableIndices.join(", ")}]`); - - this.logger.debug(""); - this.logger.debug("šŸ” CONFIGURATION DETAILS"); - this.logger.debug("============================================="); - this.logger.debug(`Network: ${config.id}`); - this.logger.debug(`Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(`Commitment level: ${config.connection.commitment}`); - this.logger.debug(`Skip preflight: ${this.options.skipPreflight}`); - this.logger.debug(`Log level: ${this.options.logLevel}`); - - // Create token registry client - const tokenRegistryClient = TokenRegistryClient.create( - config.connection, - walletKeypair, - config.routerProgramId.toString(), - {}, - { logLevel: this.options.logLevel } - ); - - // Check token admin registry status and permissions - this.logger.info(""); - this.logger.info("šŸ” REGISTRY VERIFICATION"); - this.logger.info("============================================="); - const currentRegistry = await this.checkTokenAdminRegistry( - tokenMint, - walletPublicKey, - lookupTableAddress, - tokenRegistryClient - ); - - // If lookup table is already set correctly, we're done - if (currentRegistry === null) { - return; - } - - // Verify the lookup table exists and is valid - this.logger.info(""); - this.logger.info("šŸ” LOOKUP TABLE VERIFICATION"); - this.logger.info("============================================="); - await this.verifyLookupTable(lookupTableAddress, config); - - // Set the pool (register ALT with token) - this.logger.info(""); - this.logger.info("šŸŠ SETTING POOL"); - this.logger.info("============================================="); - this.logger.info("Setting pool (registering ALT with token)..."); - const signature = await tokenRegistryClient.setPool({ - tokenMint, - lookupTable: lookupTableAddress, - writableIndices, - }); - - // Display results - this.logger.info(""); - this.logger.info("āœ… POOL SET SUCCESSFULLY"); - this.logger.info("============================================="); - this.logger.info(`Transaction Signature: ${signature}`); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("============================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, signature)}`); - - // Verify the pool was set - this.logger.info(""); - this.logger.info("šŸ” FINAL VERIFICATION"); - this.logger.info("============================================="); - await this.verifyPoolRegistration(tokenMint, lookupTableAddress, writableIndices, tokenRegistryClient); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Pool Registration Complete!"); - this.logger.info(`āœ… Token: ${tokenMint.toString()}`); - this.logger.info(`āœ… ALT: ${lookupTableAddress.toString()}`); - this.logger.info(`āœ… Ready for CCIP cross-chain operations`); - - this.logger.info(""); - this.logger.info("šŸ“‹ NEXT STEPS"); - this.logger.info("============================================="); - this.logger.info("• The token is now enabled for CCIP transfers"); - this.logger.info("• Test cross-chain operations using the CCIP router scripts"); - this.logger.info("• Use yarn ccip:send to send tokens cross-chain"); - this.logger.info("• Monitor transactions on CCIP Explorer"); - } -} - -// Create and run the command -const command = new SetPoolCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/pool/accept-ownership.ts b/ccip-scripts/svm/pool/accept-ownership.ts deleted file mode 100644 index e6b4d638..00000000 --- a/ccip-scripts/svm/pool/accept-ownership.ts +++ /dev/null @@ -1,302 +0,0 @@ -/** - * Pool Accept Ownership Script (CLI Framework Version) - * - * This script accepts the ownership of a token pool by the proposed owner. - * This is step 2 of a two-step ownership transfer process. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenPoolManager } from "../../../ccip-lib/svm/core/client/tokenpools"; -import { TokenPoolType, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { BurnMintTokenPoolInfo } from "../../../ccip-lib/svm/tokenpools/burnmint/accounts"; -import { resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { getKeypairPath, loadKeypair } from "../utils"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for accept ownership operations - */ -const ACCEPT_OWNERSHIP_CONFIG = { - minSolRequired: 0.01, - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the accept-ownership command - */ -interface AcceptOwnershipOptions extends BaseCommandOptions { - tokenMint: string; - burnMintPoolProgram: string; -} - -/** - * Pool Accept Ownership Command - */ -class AcceptOwnershipCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "accept-ownership", - description: "āœ… Pool Ownership Acceptance\n\nAccepts the ownership of a token pool by the proposed owner. This is step 2 of a two-step ownership transfer process for security.", - examples: [ - "# Accept pool ownership (you must be the proposed owner)", - "yarn svm:pool:accept-ownership \\", - " --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \\", - " --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh", - "", - "# With debug logging", - "yarn svm:pool:accept-ownership \\", - " --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \\", - " --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh \\", - " --log-level DEBUG" - ], - notes: [ - "āœ… This completes the 2-step ownership transfer process", - "Only callable by the proposed owner (set via transfer-ownership)", - `Minimum ${ACCEPT_OWNERSHIP_CONFIG.minSolRequired} SOL required for transaction fees`, - "You must be the proposed owner to execute this command", - "Once accepted, you become the pool owner with full administrative rights", - "Use 'yarn svm:pool:get-info' to verify ownership after acceptance", - "Ensure you have secure access to this keypair before accepting" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address identifying the pool", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - } - ]; - } - - protected async execute(): Promise { - this.logger.info("āœ… CCIP Token Pool Accept Ownership"); - this.logger.info("=========================================="); - this.logger.warn("āš ļø Step 2 of 2-step ownership transfer process"); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet (must be proposed owner) - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Proposed Owner (Wallet): ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("=========================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalance = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalance.toFixed(9)} SOL)`); - - if (solBalance < ACCEPT_OWNERSHIP_CONFIG.minSolRequired) { - throw new Error( - `Insufficient balance. Need at least ${ACCEPT_OWNERSHIP_CONFIG.minSolRequired} SOL for transaction fees.\n` + - `Current balance: ${solBalance.toFixed(9)} SOL\n\n` + - `Request airdrop with:\n` + - `solana airdrop 1 ${walletKeypair.publicKey.toString()} --url devnet` - ); - } - - // Parse and validate addresses - let tokenMint: PublicKey; - let burnMintPoolProgramId: PublicKey; - - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - throw new Error(`Invalid burn-mint pool program ID: ${this.options.burnMintPoolProgram}`); - } - - // Display configuration - this.logger.info(""); - this.logger.info("šŸ“‹ OWNERSHIP ACCEPTANCE CONFIGURATION"); - this.logger.info("=========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`Proposed Owner (You): ${walletKeypair.publicKey.toString()}`); - - this.logger.debug("Configuration details:"); - this.logger.debug(` Network: ${config.id}`); - this.logger.debug(` Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(` Commitment level: ${config.connection.commitment}`); - this.logger.debug(` Skip preflight: ${this.options.skipPreflight}`); - - try { - // Create token pool manager using SDK - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - { - burnMint: burnMintPoolProgramId, - }, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? LogLevel.INFO } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Check if pool exists and get current pool info for verification - this.logger.info(""); - this.logger.info("šŸ” VERIFYING POOL AND PENDING OWNERSHIP"); - this.logger.info("=========================================="); - this.logger.info("Checking pool exists and verifying pending ownership..."); - - let poolInfo: BurnMintTokenPoolInfo; - try { - poolInfo = await tokenPoolClient.getPoolInfo(tokenMint) as BurnMintTokenPoolInfo; - this.logger.info("āœ… Pool exists"); - this.logger.info(`Current Pool Owner: ${poolInfo.config.config.owner.toString()}`); - this.logger.info(`Current Proposed Owner: ${poolInfo.config.config.proposedOwner?.toString() || 'none'}`); - - this.logger.debug("Current pool details:", { - poolType: poolInfo.poolType, - owner: poolInfo.config.config.owner.toString(), - proposedOwner: poolInfo.config.config.proposedOwner?.toString() || 'none', - version: poolInfo.config.version, - decimals: poolInfo.config.config.decimals, - router: poolInfo.config.config.router.toString(), - }); - } catch (error) { - this.logger.error(""); - this.logger.error("āŒ POOL NOT FOUND"); - this.logger.error("=========================================="); - this.logger.error("Pool does not exist for this token mint"); - this.logger.error("Initialize the pool first using 'yarn svm:pool:initialize'"); - this.logger.debug( - `To initialize: yarn svm:pool:initialize --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()}` - ); - throw new Error("Pool does not exist for this token mint"); - } - - // Check if there's a pending ownership transfer to this wallet - if (!poolInfo.config.config.proposedOwner || poolInfo.config.config.proposedOwner.equals(PublicKey.default)) { - throw new Error( - `No pending ownership transfer found.\n` + - `Current Owner: ${poolInfo.config.config.owner.toString()}\n` + - `Proposed Owner: none\n\n` + - `The current owner must first propose you as the new owner using 'yarn svm:pool:transfer-ownership'.` - ); - } - - // Verify current wallet is the proposed owner - if (!poolInfo.config.config.proposedOwner.equals(walletKeypair.publicKey)) { - throw new Error( - `Access denied: You are not the proposed owner of this pool.\n` + - `Proposed Owner: ${poolInfo.config.config.proposedOwner.toString()}\n` + - `Your Wallet: ${walletKeypair.publicKey.toString()}\n\n` + - `Only the proposed owner can accept ownership.` - ); - } - - // Check if already the current owner (edge case) - if (poolInfo.config.config.owner.equals(walletKeypair.publicKey)) { - this.logger.info(""); - this.logger.info("ā„¹ļø ALREADY THE OWNER"); - this.logger.info("=========================================="); - this.logger.info("You are already the current owner of this pool."); - this.logger.info("No action needed - ownership transfer not required."); - return; - } - - this.logger.info("āœ… Verified: You are the proposed owner"); - - // Accept ownership - this.logger.info(""); - this.logger.info("šŸ”§ ACCEPTING OWNERSHIP"); - this.logger.info("=========================================="); - this.logger.warn("āš ļø FINALIZING OWNERSHIP TRANSFER"); - this.logger.info("Executing ownership acceptance..."); - - const signature = await tokenPoolClient.acceptAdminRole(tokenMint, { - skipPreflight: this.options.skipPreflight, - }); - - // Display results - this.logger.info(""); - this.logger.info("āœ… OWNERSHIP ACCEPTED SUCCESSFULLY"); - this.logger.info("=========================================="); - this.logger.info(`Transaction Signature: ${signature}`); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("=========================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, signature)}`); - - // Display summary - this.logger.info(""); - this.logger.info("šŸ‘¤ OWNERSHIP TRANSFER COMPLETE"); - this.logger.info("=========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Previous Owner: ${poolInfo.config.config.owner.toString()}`); - this.logger.info(`New Owner (You): ${walletKeypair.publicKey.toString()}`); - this.logger.info(`Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`Transaction: ${signature}`); - - this.logger.info(""); - this.logger.info("šŸ“‹ NEXT STEPS"); - this.logger.info("=========================================="); - this.logger.info("1. Verify the ownership transfer completed:"); - this.logger.info(` yarn svm:pool:get-info --token-mint ${tokenMint.toString()}`); - this.logger.info(""); - this.logger.info("2. You can now manage the pool as the owner:"); - this.logger.info(" • Configure remote chains for cross-chain transfers"); - this.logger.info(" • Set rate limits for security"); - this.logger.info(" • Transfer ownership to others if needed"); - this.logger.info(""); - this.logger.info("3. Keep your keypair secure - you are now the pool administrator"); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Ownership Transfer Complete!"); - this.logger.info("āœ… You are now the owner of this token pool"); - this.logger.info("šŸ”§ You have full administrative rights over the pool"); - - } catch (error) { - this.logger.error( - `āŒ Failed to accept ownership: ${error instanceof Error ? error.message : String(error)}` - ); - - if (error instanceof Error && error.stack) { - this.logger.debug("\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new AcceptOwnershipCommand(); -command.run().catch((error) => { - process.exit(1); -}); diff --git a/ccip-scripts/svm/pool/configure-allowlist.ts b/ccip-scripts/svm/pool/configure-allowlist.ts deleted file mode 100644 index 217b9da5..00000000 --- a/ccip-scripts/svm/pool/configure-allowlist.ts +++ /dev/null @@ -1,326 +0,0 @@ -/** - * Configure Allowlist Script (CLI Framework Version) - * - * This script manages the allowlist for a burn-mint token pool, allowing you to - * add addresses and enable/disable allowlist checking for on-ramp operations. - * The allowlist controls which addresses are permitted to receive tokens from cross-chain transfers. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenPoolManager } from "../../../ccip-lib/svm/core/client/tokenpools"; -import { TokenPoolType, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { getKeypairPath, loadKeypair } from "../utils"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for allowlist operations - */ -const ALLOWLIST_CONFIG = { - minSolRequired: 0.01, - defaultLogLevel: LogLevel.INFO, - maxAddressesPerTransaction: 10, // Reasonable limit to avoid transaction size issues -}; - -/** - * Options specific to the configure-allowlist command - */ -interface ConfigureAllowlistOptions extends BaseCommandOptions { - tokenMint: string; - burnMintPoolProgram: string; - addAddresses?: string; - enabled: boolean; -} - -/** - * Configure Allowlist Command - */ -class ConfigureAllowlistCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "configure-allowlist", - description: "šŸ“‹ Allowlist Configuration Manager\n\nManage the allowlist for a burn-mint token pool. The allowlist controls which addresses are permitted to receive tokens from cross-chain transfers (on-ramp operations). You can add addresses and enable/disable allowlist checking.", - examples: [ - "# Add addresses to allowlist and enable checking", - "yarn svm:pool:configure-allowlist --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --add-addresses \"8UJgxaiQx9LHvAYV3nFecLy83dLECKSTt9Y82MuJFSWH,9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM\" --enabled true", - "", - "# Add single address to allowlist", - "yarn svm:pool:configure-allowlist --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --add-addresses \"8UJgxaiQx9LHvAYV3nFecLy83dLECKSTt9Y82MuJFSWH\" --enabled true", - "", - "# Disable allowlist checking (allow all addresses)", - "yarn svm:pool:configure-allowlist --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --enabled false", - "", - "# Enable allowlist checking without adding new addresses", - "yarn svm:pool:configure-allowlist --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --enabled true" - ], - notes: [ - `Minimum ${ALLOWLIST_CONFIG.minSolRequired} SOL required for transaction fees`, - "The token pool must already exist", - "Wallet must be the pool owner", - "Allowlist affects on-ramp operations (tokens coming TO Solana from other chains)", - "Multiple addresses can be separated by commas", - `Maximum ${ALLOWLIST_CONFIG.maxAddressesPerTransaction} addresses per transaction`, - "Addresses must be valid Solana public keys", - "Setting enabled=false allows all addresses (disables allowlist checking)", - "Setting enabled=true restricts transfers to allowlisted addresses only", - "Use 'yarn svm:pool:get-info' to view current allowlist configuration" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address of existing pool", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - }, - { - name: "add-addresses", - required: false, - type: "string", - description: "Comma-separated Solana addresses to add to allowlist", - example: "8UJgxaiQx9LHvAYV3nFecLy83dLECKSTt9Y82MuJFSWH,9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM" - }, - { - name: "enabled", - required: true, - type: "boolean", - description: "Enable allowlist checking (true) or allow all addresses (false)", - example: "true" - } - ]; - } - - /** - * Parse and validate addresses - */ - private parseAddresses(addressesString?: string): PublicKey[] { - if (!addressesString || addressesString.trim() === "") { - return []; - } - - const addresses = addressesString - .split(",") - .map((addr) => addr.trim()) - .filter((addr) => addr.length > 0); - - if (addresses.length > ALLOWLIST_CONFIG.maxAddressesPerTransaction) { - throw new Error( - `Too many addresses provided (${addresses.length}). ` + - `Maximum ${ALLOWLIST_CONFIG.maxAddressesPerTransaction} addresses per transaction.` - ); - } - - const publicKeys: PublicKey[] = []; - const invalidAddresses: string[] = []; - - for (const addr of addresses) { - try { - publicKeys.push(new PublicKey(addr)); - } catch { - invalidAddresses.push(addr); - } - } - - if (invalidAddresses.length > 0) { - throw new Error( - `Invalid Solana addresses found:\n${invalidAddresses.map(addr => ` - ${addr}`).join('\n')}\n\n` + - `Please provide valid Solana public key addresses.` - ); - } - - return publicKeys; - } - - /** - * Validate configuration - */ - private validateConfiguration(addresses: PublicKey[], enabled: boolean): void { - if (enabled && addresses.length === 0) { - this.logger.warn("āš ļø Warning: Enabling allowlist without adding any addresses."); - this.logger.warn(" This will block ALL cross-chain transfers to this pool."); - this.logger.warn(" Consider adding at least one address or setting --enabled false."); - } - - if (!enabled && addresses.length > 0) { - this.logger.warn("āš ļø Warning: Adding addresses while allowlist is disabled."); - this.logger.warn(" Addresses will be added but allowlist checking will remain disabled."); - this.logger.warn(" Set --enabled true to activate allowlist checking."); - } - } - - protected async execute(): Promise { - this.logger.info("šŸ“‹ CCIP Allowlist Configuration Manager"); - this.logger.info("=========================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("=========================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalance = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalance.toFixed(9)} SOL)`); - - if (solBalance < ALLOWLIST_CONFIG.minSolRequired) { - throw new Error( - `Insufficient balance. Need at least ${ALLOWLIST_CONFIG.minSolRequired} SOL for transaction fees.\n` + - `Current balance: ${solBalance.toFixed(9)} SOL\n\n` + - `Request airdrop with:\n` + - `solana airdrop 1 ${walletKeypair.publicKey.toString()} --url devnet` - ); - } - - // Parse and validate addresses - let tokenMint: PublicKey; - let burnMintPoolProgramId: PublicKey; - - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - throw new Error(`Invalid burn-mint pool program ID: ${this.options.burnMintPoolProgram}`); - } - - // Parse addresses to add - const addressesToAdd = this.parseAddresses(this.options.addAddresses); - - // Validate configuration - this.validateConfiguration(addressesToAdd, this.options.enabled); - - // Display configuration - this.logger.info(""); - this.logger.info("šŸ“‹ ALLOWLIST CONFIGURATION"); - this.logger.info("=========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Burn-Mint Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`Allowlist Enabled: ${this.options.enabled}`); - this.logger.info(`Addresses to Add: ${addressesToAdd.length}`); - - if (addressesToAdd.length > 0) { - this.logger.info(""); - this.logger.info("šŸ“ ADDRESSES TO ADD:"); - addressesToAdd.forEach((addr, index) => { - this.logger.info(` ${index + 1}. ${addr.toString()}`); - }); - } - - this.logger.debug("Configuration details:"); - this.logger.debug(` Network: ${config.id}`); - this.logger.debug(` Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(` Commitment level: ${config.connection.commitment}`); - this.logger.debug(` Skip preflight: ${this.options.skipPreflight}`); - - try { - // Create token pool manager using SDK - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - { - burnMint: burnMintPoolProgramId, - }, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? LogLevel.INFO } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Configure the allowlist - this.logger.info(""); - this.logger.info("šŸ“‹ CONFIGURING ALLOWLIST"); - this.logger.info("=========================================="); - this.logger.info("Updating allowlist configuration..."); - - const signature = await tokenPoolClient.configureAllowlist(tokenMint, { - add: addressesToAdd, - enabled: this.options.enabled, - txOptions: { - skipPreflight: this.options.skipPreflight, - }, - }); - - // Display results - this.logger.info(""); - this.logger.info("āœ… ALLOWLIST CONFIGURED SUCCESSFULLY"); - this.logger.info("=========================================="); - this.logger.info(`Transaction Signature: ${signature}`); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("=========================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, signature)}`); - - this.logger.info(""); - this.logger.info("šŸ“‹ NEXT STEPS"); - this.logger.info("=========================================="); - this.logger.info("View updated configuration:"); - this.logger.info(` yarn svm:pool:get-info --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()}`); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Allowlist Configuration Complete!"); - this.logger.info(`āœ… Allowlist checking: ${this.options.enabled ? "Enabled" : "Disabled"}`); - if (addressesToAdd.length > 0) { - this.logger.info(`āœ… Added ${addressesToAdd.length} address${addressesToAdd.length === 1 ? '' : 'es'} to allowlist`); - } - - if (this.options.enabled) { - this.logger.info(""); - this.logger.info("ā„¹ļø With allowlist enabled, only allowlisted addresses can receive tokens from cross-chain transfers."); - } else { - this.logger.info(""); - this.logger.info("ā„¹ļø With allowlist disabled, any address can receive tokens from cross-chain transfers."); - } - - } catch (error) { - this.logger.error( - `āŒ Failed to configure allowlist: ${error instanceof Error ? error.message : String(error)}` - ); - - if (error instanceof Error && error.stack) { - this.logger.debug("\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new ConfigureAllowlistCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/pool/create-pool-token-account.ts b/ccip-scripts/svm/pool/create-pool-token-account.ts deleted file mode 100644 index 7492e216..00000000 --- a/ccip-scripts/svm/pool/create-pool-token-account.ts +++ /dev/null @@ -1,343 +0,0 @@ -/** - * Pool Token Account Creation Script (CLI Framework Version) - * - * This script creates the Associated Token Account (ATA) for the pool signer PDA. - * This account is required for the pool to hold tokens during cross-chain operations. - */ - -import { - PublicKey, - LAMPORTS_PER_SOL, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { - createAssociatedTokenAccountInstruction, - getAssociatedTokenAddress, - ASSOCIATED_TOKEN_PROGRAM_ID, -} from "@solana/spl-token"; -import { TokenPoolManager } from "../../../ccip-lib/svm/core/client/tokenpools"; -import { TokenPoolType, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { BurnMintTokenPoolInfo } from "../../../ccip-lib/svm/tokenpools/burnmint/accounts"; -import { resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { getKeypairPath, loadKeypair } from "../utils"; -import { detectTokenProgram } from "../../../ccip-lib/svm"; -import { findPoolSignerPDA } from "../../../ccip-lib/svm/utils/pdas/tokenpool"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for create pool token account operations - */ -const CREATE_POOL_ACCOUNT_CONFIG = { - minSolRequired: 0.01, - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the create-pool-token-account command - */ -interface CreatePoolTokenAccountOptions extends BaseCommandOptions { - tokenMint: string; - burnMintPoolProgram: string; -} - -/** - * Create Pool Token Account Command - */ -class CreatePoolTokenAccountCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "create-pool-token-account", - description: "šŸŠ Pool Token Account Creator\n\nCreates the Associated Token Account (ATA) for the pool signer PDA. This account is required for the pool to hold tokens during cross-chain operations.", - examples: [ - "# Create pool token account", - "yarn svm:pool:create-token-account --token-mint 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY --burn-mint-pool-program 4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz", - "", - "# Create with debug logging", - "yarn svm:pool:create-token-account --token-mint 4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY --burn-mint-pool-program 4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz --log-level DEBUG" - ], - notes: [ - `Minimum ${CREATE_POOL_ACCOUNT_CONFIG.minSolRequired} SOL required for transaction fees`, - "Pool must be initialized first (yarn svm:pool:initialize)", - "Wallet must have sufficient SOL for transaction fees", - "Token mint must exist and be valid", - "Verifies the pool exists and gets configuration", - "Calculates the pool signer PDA address", - "Creates the Associated Token Account for the pool signer", - "After running: pool can hold tokens during cross-chain operations", - "Prevents 'AccountNotInitialized' errors in cross-chain transfers" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address for the pool", - example: "4yT122YQdx7mdVvoArRgWJpnDbxxWadZpRFHRz2G9SnY" - }, - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "4rtU5pVwtQaAfLhd1AkAsL1VopCJciBZewiPgjudeahz" - } - ]; - } - - protected async execute(): Promise { - this.logger.info("šŸŠ CCIP Pool Token Account Creation"); - this.logger.info("=========================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("=========================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalance = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalance.toFixed(9)} SOL)`); - - if (solBalance < CREATE_POOL_ACCOUNT_CONFIG.minSolRequired) { - throw new Error( - `Insufficient balance. Need at least ${CREATE_POOL_ACCOUNT_CONFIG.minSolRequired} SOL for transaction fees.\n` + - `Current balance: ${solBalance.toFixed(9)} SOL\n\n` + - `Request airdrop with:\n` + - `solana airdrop 1 ${walletKeypair.publicKey.toString()} --url devnet` - ); - } - - // Parse and validate addresses - let tokenMint: PublicKey; - let burnMintPoolProgramId: PublicKey; - - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - throw new Error(`Invalid burn-mint pool program ID: ${this.options.burnMintPoolProgram}`); - } - - // Display configuration - this.logger.info(""); - this.logger.info("šŸ“‹ ACCOUNT CREATION CONFIGURATION"); - this.logger.info("=========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Burn-Mint Pool Program: ${burnMintPoolProgramId.toString()}`); - - try { - // Create token pool manager using SDK - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - { - burnMint: burnMintPoolProgramId, - }, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? LogLevel.INFO } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Verify pool exists - this.logger.info(""); - this.logger.info("šŸ” VERIFYING POOL EXISTENCE"); - this.logger.info("=========================================="); - - let poolInfo: BurnMintTokenPoolInfo; - try { - poolInfo = await tokenPoolClient.getPoolInfo(tokenMint) as BurnMintTokenPoolInfo; - this.logger.info("āœ… Pool exists"); - } catch (error) { - throw new Error( - "Pool does not exist for this token mint.\n" + - "Initialize the pool first:\n" + - `yarn svm:pool:initialize --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()}` - ); - } - - // Get pool info - const currentPoolTokenAccount = poolInfo.config.config.poolTokenAccount; - this.logger.info(`Current pool token account: ${currentPoolTokenAccount.toString()}`); - - // Determine token program ID - const tokenProgramId = await detectTokenProgram(tokenMint, config.connection, this.logger); - - // Derive pool signer PDA - const [poolSigner, poolSignerBump] = findPoolSignerPDA(tokenMint, burnMintPoolProgramId); - this.logger.info(`Pool signer PDA: ${poolSigner.toString()}`); - this.logger.debug(`Pool signer bump: ${poolSignerBump}`); - - // Check if pool signer matches what's in the pool config - const configPoolSigner = poolInfo.config.config.poolSigner; - if (!poolSigner.equals(configPoolSigner)) { - this.logger.warn("Pool signer mismatch!"); - this.logger.warn(` Calculated: ${poolSigner.toString()}`); - this.logger.warn(` In config: ${configPoolSigner.toString()}`); - this.logger.info("Using pool signer from configuration..."); - } - - // Use the pool signer from the configuration - const actualPoolSigner = configPoolSigner; - - // Calculate the expected ATA - const expectedATA = await getAssociatedTokenAddress( - tokenMint, - actualPoolSigner, - true, // allowOwnerOffCurve - tokenProgramId, - ASSOCIATED_TOKEN_PROGRAM_ID - ); - - this.logger.info(`Expected pool token account (ATA): ${expectedATA.toString()}`); - - // Check if the expected ATA matches the current pool token account - if (!expectedATA.equals(currentPoolTokenAccount)) { - this.logger.warn("Pool token account mismatch!"); - this.logger.warn(` Expected: ${expectedATA.toString()}`); - this.logger.warn(` Current: ${currentPoolTokenAccount.toString()}`); - this.logger.info("This script will create the expected ATA..."); - } - - // Check if the ATA already exists - this.logger.info(""); - this.logger.info("šŸ” CHECKING EXISTING ACCOUNT"); - this.logger.info("=========================================="); - - const existingAccount = await config.connection.getAccountInfo(expectedATA); - - if (existingAccount) { - this.logger.info(""); - this.logger.info("āœ… ACCOUNT ALREADY EXISTS"); - this.logger.info("=========================================="); - this.logger.info("Pool token account already exists!"); - this.logger.info(`Account address: ${expectedATA.toString()}`); - this.logger.info(`Owner: ${actualPoolSigner.toString()}`); - this.logger.info("No action needed."); - return; - } - - // Create the ATA - this.logger.info(""); - this.logger.info("šŸ”§ CREATING POOL TOKEN ACCOUNT"); - this.logger.info("=========================================="); - this.logger.info("Creating pool token account (ATA)..."); - - this.logger.debug("Creating ATA for:"); - this.logger.debug(` Mint: ${tokenMint.toString()}`); - this.logger.debug(` Owner (Pool Signer): ${actualPoolSigner.toString()}`); - this.logger.debug(` Payer: ${walletKeypair.publicKey.toString()}`); - this.logger.debug(` Token Program: ${tokenProgramId.toString()}`); - - const createATAInstruction = createAssociatedTokenAccountInstruction( - walletKeypair.publicKey, // payer - expectedATA, // ata address - actualPoolSigner, // owner of the ATA (pool signer) - tokenMint, // token mint - tokenProgramId, // token program - ASSOCIATED_TOKEN_PROGRAM_ID // ATA program - ); - - // Create and send transaction - const transaction = new Transaction().add(createATAInstruction); - - this.logger.debug("Sending transaction..."); - const signature = await sendAndConfirmTransaction( - config.connection, - transaction, - [walletKeypair], - { - skipPreflight: this.options.skipPreflight, - commitment: config.connection.commitment, - } - ); - - // Display results - this.logger.info(""); - this.logger.info("āœ… POOL TOKEN ACCOUNT CREATED SUCCESSFULLY"); - this.logger.info("=========================================="); - this.logger.info(`Transaction Signature: ${signature}`); - this.logger.info(`Pool Token Account Address: ${expectedATA.toString()}`); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("=========================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, signature)}`); - - // Verify creation - this.logger.info(""); - this.logger.info("šŸ” VERIFYING ACCOUNT CREATION"); - this.logger.info("=========================================="); - - const verificationAccount = await config.connection.getAccountInfo(expectedATA); - - if (verificationAccount) { - this.logger.info("āœ… Account creation verified!"); - this.logger.debug(`Account owner: ${verificationAccount.owner.toString()}`); - this.logger.debug(`Account lamports: ${verificationAccount.lamports}`); - } else { - this.logger.warn("āš ļø Account verification failed - this may be due to network delays"); - } - - this.logger.info(""); - this.logger.info("šŸŽ‰ Pool Token Account Setup Complete!"); - this.logger.info(`āœ… ATA Address: ${expectedATA.toString()}`); - this.logger.info(`āœ… Owner: ${actualPoolSigner.toString()} (Pool Signer PDA)`); - this.logger.info(`āœ… Ready for cross-chain token operations`); - - } catch (error) { - if (error instanceof Error) { - if (error.message.includes("insufficient funds")) { - this.logger.error("Insufficient SOL for transaction fees"); - this.logger.info("Request more SOL from the devnet faucet"); - } else if (error.message.includes("already in use")) { - this.logger.info("Account may already exist - check with get-pool-info"); - } - } - - this.logger.error( - `āŒ Failed to create pool token account: ${error instanceof Error ? error.message : String(error)}` - ); - - if (error instanceof Error && error.stack) { - this.logger.debug("\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new CreatePoolTokenAccountCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/pool/edit-chain-remote-config.ts b/ccip-scripts/svm/pool/edit-chain-remote-config.ts deleted file mode 100644 index 9e95c14f..00000000 --- a/ccip-scripts/svm/pool/edit-chain-remote-config.ts +++ /dev/null @@ -1,314 +0,0 @@ -/** - * Chain Remote Configuration Edit Script (CLI Framework Version) - * - * This script edits an existing chain remote configuration for a burn-mint token pool, - * updating the configuration for cross-chain token transfers to a specific remote chain. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenPoolManager } from "../../../ccip-lib/svm/core/client/tokenpools"; -import { TokenPoolType, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { ChainId, CHAIN_SELECTORS, resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { getKeypairPath, loadKeypair } from "../utils"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for edit chain remote config operations - */ -const EDIT_CHAIN_CONFIG = { - minSolRequired: 0.01, - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the edit-chain-remote-config command - */ -interface EditChainRemoteConfigOptions extends BaseCommandOptions { - tokenMint: string; - burnMintPoolProgram: string; - remoteChain: string; - poolAddresses: string; - tokenAddress: string; - decimals: number; -} - -/** - * Edit Chain Remote Configuration Command - */ -class EditChainRemoteConfigCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "edit-chain-remote-config", - description: "šŸ”— Chain Remote Configuration Editor\n\nEdits an existing chain remote configuration for a burn-mint token pool, updating the configuration for cross-chain token transfers to a specific remote chain.", - examples: [ - "# Edit chain config for Ethereum Sepolia", - "yarn svm:pool:edit-chain-remote-config --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --remote-chain ethereum-sepolia --pool-addresses \"0x742d35Cc6634C0532925a3b8D5c42A2cDd1e4b6d\" --token-address \"0xA0b86991c431e59b4b59dac67ba9b82c31a30d15c\" --decimals 6", - "", - "# Edit with multiple pool addresses", - "yarn svm:pool:edit-chain-remote-config --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --remote-chain ethereum-sepolia --pool-addresses \"0x742d35Cc6634C0532925a3b8D5c42A2cDd1e4b6d,0x123...\" --token-address \"0xA0b86991c431e59b4b59dac67ba9b82c31a30d15c\" --decimals 6" - ], - notes: [ - `Minimum ${EDIT_CHAIN_CONFIG.minSolRequired} SOL required for transaction fees`, - "The token pool and chain configuration must already exist", - "Wallet must be the pool administrator", - "Addresses should be provided as hex strings with '0x' prefix", - "Multiple pool addresses can be separated by commas", - "Chain configuration editing requires SOL for transaction fees", - "Remote chains: ethereum-sepolia, avalanche-fuji, base-sepolia, etc.", - "Use 'yarn svm:pool:get-info' to view current configuration" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address of existing pool", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - }, - { - name: "remote-chain", - required: true, - type: "string", - description: "Remote chain to configure (chain-id)", - example: "ethereum-sepolia" - }, - { - name: "pool-addresses", - required: true, - type: "string", - description: "Comma-separated pool addresses on remote chain (hex)", - example: "0x742d35Cc6634C0532925a3b8D5c42A2cDd1e4b6d" - }, - { - name: "token-address", - required: true, - type: "string", - description: "Token address on remote chain (hex)", - example: "0xA0b86991c431e59b4b59dac67ba9b82c31a30d15c" - }, - { - name: "decimals", - required: true, - type: "number", - description: "Token decimals on remote chain", - example: "6" - } - ]; - } - - /** - * Resolve remote chain selector from chain ID - */ - private resolveRemoteChainSelector(remoteChain: string): bigint { - const chainSelector = CHAIN_SELECTORS[remoteChain as ChainId]; - if (!chainSelector) { - throw new Error( - `Unknown remote chain: ${remoteChain}\n` + - `Available chains: ${Object.keys(CHAIN_SELECTORS).join(", ")}` - ); - } - return chainSelector; - } - - /** - * Display available remote chains - */ - private displayAvailableChains(): void { - this.logger.info(""); - this.logger.info("šŸ“‹ AVAILABLE REMOTE CHAINS"); - this.logger.info("=========================================="); - Object.entries(CHAIN_SELECTORS).forEach(([chainId, selector]) => { - this.logger.info(` ${chainId}: ${selector.toString()}`); - }); - } - - protected async execute(): Promise { - this.logger.info("šŸ”— CCIP Chain Remote Configuration Editor"); - this.logger.info("=========================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("=========================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalance = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalance.toFixed(9)} SOL)`); - - if (solBalance < EDIT_CHAIN_CONFIG.minSolRequired) { - throw new Error( - `Insufficient balance. Need at least ${EDIT_CHAIN_CONFIG.minSolRequired} SOL for transaction fees.\n` + - `Current balance: ${solBalance.toFixed(9)} SOL\n\n` + - `Request airdrop with:\n` + - `solana airdrop 1 ${walletKeypair.publicKey.toString()} --url devnet` - ); - } - - // Parse and validate addresses - let tokenMint: PublicKey; - let burnMintPoolProgramId: PublicKey; - - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - throw new Error(`Invalid burn-mint pool program ID: ${this.options.burnMintPoolProgram}`); - } - - // Resolve remote chain selector - let remoteChainSelector: bigint; - try { - remoteChainSelector = this.resolveRemoteChainSelector(this.options.remoteChain); - } catch (error) { - this.displayAvailableChains(); - throw error; - } - - // Parse pool addresses - const poolAddresses = this.options.poolAddresses - .split(",") - .map((addr) => addr.trim()) - .filter((addr) => addr.length > 0); - - if (poolAddresses.length === 0) { - throw new Error("At least one pool address must be provided"); - } - - const tokenAddress = this.options.tokenAddress; - const decimals = this.options.decimals; - - // Validate hex addresses - const hexRegex = /^0x[a-fA-F0-9]+$/; - poolAddresses.forEach((addr) => { - if (!hexRegex.test(addr)) { - throw new Error(`Invalid hex address format: ${addr}. Must start with '0x' and contain only hex characters.`); - } - }); - - if (!hexRegex.test(tokenAddress)) { - throw new Error(`Invalid hex token address format: ${tokenAddress}. Must start with '0x' and contain only hex characters.`); - } - - // Display configuration - this.logger.info(""); - this.logger.info("šŸ“‹ EDIT CONFIGURATION"); - this.logger.info("=========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Burn-Mint Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`Remote Chain: ${this.options.remoteChain}`); - this.logger.info(`Remote Chain Selector: ${remoteChainSelector.toString()}`); - this.logger.info(`Pool Addresses: ${poolAddresses.join(", ")}`); - this.logger.info(`Token Address: ${tokenAddress}`); - this.logger.info(`Decimals: ${decimals}`); - - this.logger.debug("Configuration details:"); - this.logger.debug(` Network: ${config.id}`); - this.logger.debug(` Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(` Commitment level: ${config.connection.commitment}`); - this.logger.debug(` Skip preflight: ${this.options.skipPreflight}`); - - try { - // Create token pool manager using SDK - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - { - burnMint: burnMintPoolProgramId, - }, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? LogLevel.INFO } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Edit the chain remote config - this.logger.info(""); - this.logger.info("šŸ”§ EDITING CHAIN REMOTE CONFIG"); - this.logger.info("=========================================="); - this.logger.info("Updating chain remote configuration..."); - - const result = await tokenPoolClient.editChainRemoteConfig(tokenMint, remoteChainSelector, { - poolAddresses, - tokenAddress, - decimals, - txOptions: { - skipPreflight: this.options.skipPreflight, - }, - }); - - // Display results - this.logger.info(""); - this.logger.info("āœ… CHAIN CONFIG EDITED SUCCESSFULLY"); - this.logger.info("=========================================="); - this.logger.info(`Transaction Signature: ${result.signature}`); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("=========================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, result.signature)}`); - - this.logger.info(""); - this.logger.info("šŸ“‹ NEXT STEPS"); - this.logger.info("=========================================="); - this.logger.info("View updated configuration:"); - this.logger.info(` yarn svm:pool:get-info --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()}`); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Chain Configuration Update Complete!"); - this.logger.info(`āœ… Remote chain ${this.options.remoteChain} configuration updated`); - this.logger.info(`āœ… Pool addresses: ${poolAddresses.length} configured`); - - } catch (error) { - this.logger.error( - `āŒ Failed to edit chain remote configuration: ${error instanceof Error ? error.message : String(error)}` - ); - - if (error instanceof Error && error.stack) { - this.logger.debug("\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new EditChainRemoteConfigCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/pool/get-chain-config.ts b/ccip-scripts/svm/pool/get-chain-config.ts deleted file mode 100644 index 718a1911..00000000 --- a/ccip-scripts/svm/pool/get-chain-config.ts +++ /dev/null @@ -1,298 +0,0 @@ -/** - * Chain Configuration Retrieval Script (CLI Framework Version) - * - * This script retrieves and displays the chain remote configuration for a burn-mint token pool, - * showing the configuration details for cross-chain token transfers to a specific remote chain. - */ - -import { PublicKey } from "@solana/web3.js"; -import { TokenPoolManager } from "../../../ccip-lib/svm/core/client/tokenpools"; -import { TokenPoolType, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { ChainId, CHAIN_SELECTORS, resolveNetworkConfig } from "../../config"; -import { loadKeypair } from "../utils"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for get chain config operations - */ -const GET_CHAIN_CONFIG_CONFIG = { - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the get-chain-config command - */ -interface GetChainConfigOptions extends BaseCommandOptions { - tokenMint: string; - burnMintPoolProgram: string; - remoteChain: string; -} - -/** - * Get Chain Configuration Command - */ -class GetChainConfigCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "get-chain-config", - description: "šŸ” Chain Configuration Reader\n\nRetrieves and displays the chain remote configuration for a burn-mint token pool, showing the configuration details for cross-chain token transfers to a specific remote chain.", - examples: [ - "# Get chain config for Ethereum Sepolia", - "yarn svm:pool:get-chain-config --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --remote-chain ethereum-sepolia", - "", - "# Get chain config with debug logging", - "yarn svm:pool:get-chain-config --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --remote-chain base-sepolia --log-level DEBUG" - ], - notes: [ - "This is a READ-ONLY operation that doesn't require a wallet/keypair", - "No transaction fees or signatures needed", - "The token pool and chain configuration must already exist", - "Shows detailed configuration including rate limits and current usage", - "Remote chains: ethereum-sepolia, avalanche-fuji, base-sepolia, etc.", - "Use this before editing configurations to see current values", - "Shows token address, decimals, pool addresses, and rate limits" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address of existing pool", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - }, - { - name: "remote-chain", - required: true, - type: "string", - description: "Remote chain to query (chain-id)", - example: "ethereum-sepolia" - } - ]; - } - - /** - * Resolve remote chain selector from chain ID - */ - private resolveRemoteChainSelector(remoteChain: string): bigint { - const chainSelector = CHAIN_SELECTORS[remoteChain as ChainId]; - if (!chainSelector) { - throw new Error( - `Unknown remote chain: ${remoteChain}\n` + - `Available chains: ${Object.keys(CHAIN_SELECTORS).join(", ")}` - ); - } - return chainSelector; - } - - /** - * Display available remote chains - */ - private displayAvailableChains(): void { - this.logger.info(""); - this.logger.info("šŸ“‹ AVAILABLE REMOTE CHAINS"); - this.logger.info("=========================================="); - Object.entries(CHAIN_SELECTORS).forEach(([chainId, selector]) => { - this.logger.info(` ${chainId}: ${selector.toString()}`); - }); - } - - /** - * Format token amount for display - */ - private formatTokenAmount(amount: bigint, decimals: number = 18): string { - if (amount === BigInt(0)) return "0"; - - const divisor = BigInt(10 ** decimals); - const whole = amount / divisor; - const remainder = amount % divisor; - - if (remainder === BigInt(0)) { - return whole.toString(); - } - - const fractional = remainder.toString().padStart(decimals, '0').replace(/0+$/, ''); - return `${whole}.${fractional}`; - } - - /** - * Display chain configuration details - */ - private displayChainConfig(chainConfig: any): void { - this.logger.info(""); - this.logger.info("šŸ“‹ CHAIN CONFIGURATION DETAILS"); - this.logger.info("=========================================="); - this.logger.info(`Account Address: ${chainConfig.address}`); - - this.logger.info(""); - this.logger.info("šŸ”— REMOTE CHAIN INFORMATION"); - this.logger.info("------------------------------------------"); - this.logger.info(`Decimals: ${chainConfig.base.decimals}`); - this.logger.info(`Token Address: 0x${chainConfig.base.tokenAddress.address}`); - - this.logger.info(""); - this.logger.info("šŸŠ POOL ADDRESSES"); - this.logger.info("------------------------------------------"); - if (chainConfig.base.poolAddresses.length === 0) { - this.logger.info("No pool addresses configured"); - } else { - chainConfig.base.poolAddresses.forEach((pool: any, index: number) => { - this.logger.info(`${index + 1}. 0x${pool.address}`); - }); - } - - this.logger.info(""); - this.logger.info("ā¬‡ļø INBOUND RATE LIMIT"); - this.logger.info("------------------------------------------"); - this.logger.info(`Enabled: ${chainConfig.base.inboundRateLimit.isEnabled}`); - this.logger.info(`Capacity: ${chainConfig.base.inboundRateLimit.capacity.toString()} (${this.formatTokenAmount(BigInt(chainConfig.base.inboundRateLimit.capacity), chainConfig.base.decimals)} tokens)`); - this.logger.info(`Rate: ${chainConfig.base.inboundRateLimit.rate.toString()} (${this.formatTokenAmount(BigInt(chainConfig.base.inboundRateLimit.rate), chainConfig.base.decimals)} tokens/second)`); - this.logger.info(`Current Bucket Value: ${chainConfig.base.inboundRateLimit.currentBucketValue.toString()} (${this.formatTokenAmount(BigInt(chainConfig.base.inboundRateLimit.currentBucketValue), chainConfig.base.decimals)} tokens)`); - this.logger.info(`Last Updated: ${new Date( - Number(chainConfig.base.inboundRateLimit.lastTxTimestamp) * 1000 - ).toISOString()}`); - - this.logger.info(""); - this.logger.info("ā¬†ļø OUTBOUND RATE LIMIT"); - this.logger.info("------------------------------------------"); - this.logger.info(`Enabled: ${chainConfig.base.outboundRateLimit.isEnabled}`); - this.logger.info(`Capacity: ${chainConfig.base.outboundRateLimit.capacity.toString()} (${this.formatTokenAmount(BigInt(chainConfig.base.outboundRateLimit.capacity), chainConfig.base.decimals)} tokens)`); - this.logger.info(`Rate: ${chainConfig.base.outboundRateLimit.rate.toString()} (${this.formatTokenAmount(BigInt(chainConfig.base.outboundRateLimit.rate), chainConfig.base.decimals)} tokens/second)`); - this.logger.info(`Current Bucket Value: ${chainConfig.base.outboundRateLimit.currentBucketValue.toString()} (${this.formatTokenAmount(BigInt(chainConfig.base.outboundRateLimit.currentBucketValue), chainConfig.base.decimals)} tokens)`); - this.logger.info(`Last Updated: ${new Date( - Number(chainConfig.base.outboundRateLimit.lastTxTimestamp) * 1000 - ).toISOString()}`); - } - - protected async execute(): Promise { - this.logger.info("šŸ” CCIP Chain Configuration Reader (Read-Only)"); - this.logger.info("=========================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Parse and validate addresses - let tokenMint: PublicKey; - let burnMintPoolProgramId: PublicKey; - - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - throw new Error(`Invalid burn-mint pool program ID: ${this.options.burnMintPoolProgram}`); - } - - // Resolve remote chain selector - let remoteChainSelector: bigint; - try { - remoteChainSelector = this.resolveRemoteChainSelector(this.options.remoteChain); - } catch (error) { - this.displayAvailableChains(); - throw error; - } - - // Display query parameters - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Burn-Mint Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`Remote Chain: ${this.options.remoteChain}`); - this.logger.info(`Remote Chain Selector: ${remoteChainSelector.toString()}`); - - this.logger.debug("Configuration details:"); - this.logger.debug(` Network: ${config.id}`); - this.logger.debug(` Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(` Commitment level: ${config.connection.commitment}`); - - try { - // Create token pool manager using SDK (using dummy wallet for read operations) - const walletKeypair = loadKeypair(`${process.env.HOME}/.config/solana/id.json`); - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - { - burnMint: burnMintPoolProgramId, - }, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? LogLevel.INFO } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Get the chain config - this.logger.info(""); - this.logger.info("šŸ”„ RETRIEVING CHAIN CONFIGURATION"); - this.logger.info("=========================================="); - this.logger.info("Fetching chain configuration..."); - - const chainConfig = await tokenPoolClient.getChainConfig(tokenMint, remoteChainSelector); - - // Display the configuration - this.displayChainConfig(chainConfig); - - this.logger.info(""); - this.logger.info("šŸ“‹ NEXT STEPS"); - this.logger.info("=========================================="); - this.logger.info("• Use edit-chain-remote-config to update this configuration"); - this.logger.info("• Use set-rate-limit to update rate limits separately"); - this.logger.info("• Use get-pool-info to see all chain configurations"); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Chain Configuration Retrieved Successfully!"); - - } catch (error) { - this.logger.error( - `āŒ Failed to retrieve chain configuration: ${error instanceof Error ? error.message : String(error)}` - ); - - this.logger.info(""); - this.logger.info("āŒ COMMON ISSUES"); - this.logger.info("=========================================="); - this.logger.info("• Chain configuration does not exist for this remote chain"); - this.logger.info("• Token pool does not exist for this mint"); - this.logger.info("• Invalid remote chain selector"); - - this.logger.info(""); - this.logger.info("šŸ’” SOLUTIONS"); - this.logger.info("=========================================="); - this.logger.info("• Use init-chain-remote-config to create the configuration first"); - this.logger.info("• Use get-pool-info to verify the pool exists"); - this.logger.info("• Check available chains with --help"); - - if (error instanceof Error && error.stack) { - this.logger.debug("\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new GetChainConfigCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/pool/get-pool-info.ts b/ccip-scripts/svm/pool/get-pool-info.ts deleted file mode 100644 index 9b21bcba..00000000 --- a/ccip-scripts/svm/pool/get-pool-info.ts +++ /dev/null @@ -1,452 +0,0 @@ -/** - * Pool Information Script (CLI Framework Version) - * - * This script retrieves and displays comprehensive information about a burn-mint token pool. - * It shows all configuration details, ownership information, and status. - */ - -import { PublicKey } from "@solana/web3.js"; -import { - TokenPoolManager, - TokenPoolType, - LogLevel, - createLogger, - TokenPoolClient, -} from "../../../ccip-lib/svm"; -import { BurnMintTokenPoolInfo } from "../../../ccip-lib/svm/tokenpools/burnmint/accounts"; -import { ChainId, getCCIPSVMConfig, resolveNetworkConfig } from "../../config"; -import { loadKeypair, getKeypairPath } from "../utils"; -import { - findBurnMintPoolConfigPDA, - findGlobalConfigPDA, -} from "../../../ccip-lib/svm/utils/pdas/tokenpool"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for pool info operations - */ -const POOL_INFO_CONFIG = { - defaultLogLevel: LogLevel.INFO, - separatorLength: 80, - subSeparatorLength: 40, -}; - -/** - * Options specific to the get-pool-info command - */ -interface GetPoolInfoOptions extends BaseCommandOptions { - tokenMint: string; - burnMintPoolProgram: string; -} - -/** - * Pool Information Command - */ -class GetPoolInfoCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "get-pool-info", - description: "šŸŠ CCIP Pool Information Viewer\\n\\nRetrieves and displays comprehensive information about a burn-mint token pool. Shows all configuration details, ownership information, and status.", - examples: [ - "# Get pool info for a token", - "yarn svm:pool:get-info --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh", - "", - "# With debug logging", - "yarn svm:pool:get-info --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --log-level DEBUG" - ], - notes: [ - "This script provides comprehensive information about an existing pool", - "All addresses and configuration details are displayed", - "Suggestions for next steps are provided", - "Pool must be initialized before running this script", - "Wallet is used for querying purposes only (no transactions)", - "Shows global configuration and pool-specific settings" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address to get info for", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - } - ]; - } - - /** - * Validate pool info configuration - */ - private validateConfig(): { tokenMint: PublicKey; burnMintPoolProgramId: PublicKey } { - const errors: string[] = []; - - // Validate token mint address - let tokenMint: PublicKey; - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - errors.push("Invalid token mint address format"); - throw new Error(`Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}`); - } - - // Validate burn-mint pool program ID - let burnMintPoolProgramId: PublicKey; - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - errors.push("Invalid burn-mint pool program ID format"); - throw new Error(`Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}`); - } - - if (errors.length > 0) { - throw new Error( - `Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}` - ); - } - - return { tokenMint, burnMintPoolProgramId }; - } - - /** - * Format a PublicKey for display, showing if it's a default/empty key - */ - private formatPublicKey(key: PublicKey, label?: string): string { - const keyStr = key.toString(); - const isDefault = key.equals(PublicKey.default); - const suffix = isDefault ? " (default/unset)" : ""; - return label ? `${label}: ${keyStr}${suffix}` : `${keyStr}${suffix}`; - } - - /** - * Format boolean values with visual indicators - */ - private formatBoolean(value: boolean): string { - return value ? "āœ… Enabled" : "āŒ Disabled"; - } - - /** - * Check if pool exists and get basic status - */ - private async checkPoolExistence( - tokenMint: PublicKey, - burnMintPoolProgramId: PublicKey, - tokenPoolClient: TokenPoolClient - ): Promise { - this.logger.info("Checking if pool exists..."); - this.logger.debug(`Checking pool existence for mint: ${tokenMint.toString()}`); - - const poolExists = await tokenPoolClient.hasPool(tokenMint); - this.logger.debug(`Pool exists: ${poolExists}`); - - if (!poolExists) { - this.logger.info("\\nāŒ Pool does not exist for this token mint"); - this.logger.info("\\nšŸ’” Run the initialization script first:"); - this.logger.info( - `yarn svm:pool:initialize --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()}` - ); - this.logger.debug("Pool not found - terminating script"); - return false; - } - - return true; - } - - /** - * Get global configuration information - */ - private async getGlobalConfigInfo(tokenPoolClient: TokenPoolClient): Promise { - this.logger.debug("Fetching global configuration..."); - - try { - const globalConfigInfo = await tokenPoolClient.getGlobalConfigInfo(); - this.logger.debug("Global config retrieved:", { - version: globalConfigInfo.config.version, - selfServedAllowed: globalConfigInfo.config.self_served_allowed, - }); - this.logger.trace("Complete global config:", globalConfigInfo); - return globalConfigInfo; - } catch (error) { - this.logger.debug(`Failed to fetch global config: ${error}`); - return { - exists: false, - error: error instanceof Error ? error.message : String(error), - }; - } - } - - /** - * Display comprehensive pool information - */ - private displayPoolInfo( - poolInfo: BurnMintTokenPoolInfo, - globalConfigInfo: any, - tokenMint: PublicKey, - burnMintPoolProgramId: PublicKey - ): void { - // Header - this.logger.info("\\n" + "=".repeat(POOL_INFO_CONFIG.separatorLength)); - this.logger.info("šŸŠ BURN-MINT TOKEN POOL INFORMATION"); - this.logger.info("=".repeat(POOL_INFO_CONFIG.separatorLength)); - - // Global Configuration - this.logger.info("\\nšŸŒ GLOBAL CONFIGURATION"); - this.logger.info("-".repeat(POOL_INFO_CONFIG.subSeparatorLength)); - if (globalConfigInfo && globalConfigInfo.config) { - this.logger.info(`Program Version: ${globalConfigInfo.config.version}`); - this.logger.info( - `Self-Served Pools: ${this.formatBoolean( - globalConfigInfo.config.self_served_allowed - )}` - ); - } else { - this.logger.info("āŒ Global config not found or not initialized"); - this.logger.info("šŸ’” Run: yarn svm:pool:init-global-config first"); - } - - // Basic Pool Info - this.logger.info("\\nšŸ“‹ BASIC INFORMATION"); - this.logger.info("-".repeat(POOL_INFO_CONFIG.subSeparatorLength)); - this.logger.info(`Pool Type: ${poolInfo.poolType}`); - this.logger.info(`Version: ${poolInfo.config.version}`); - this.logger.info(this.formatPublicKey(poolInfo.config.config.mint, "Token Mint")); - this.logger.info(`Decimals: ${poolInfo.config.config.decimals}`); - - // Ownership & Permissions - this.logger.info("\\nšŸ‘„ OWNERSHIP & PERMISSIONS"); - this.logger.info("-".repeat(POOL_INFO_CONFIG.subSeparatorLength)); - this.logger.info(this.formatPublicKey(poolInfo.config.config.owner, "Current Owner")); - this.logger.info( - this.formatPublicKey(poolInfo.config.config.proposedOwner, "Proposed Owner") - ); - this.logger.info( - this.formatPublicKey(poolInfo.config.config.rateLimitAdmin, "Rate Limit Admin") - ); - - // Token Configuration - this.logger.info("\\nšŸŖ™ TOKEN CONFIGURATION"); - this.logger.info("-".repeat(POOL_INFO_CONFIG.subSeparatorLength)); - this.logger.info( - this.formatPublicKey(poolInfo.config.config.tokenProgram, "Token Program") - ); - this.logger.info( - this.formatPublicKey(poolInfo.config.config.poolSigner, "Pool Signer PDA") - ); - this.logger.info( - this.formatPublicKey( - poolInfo.config.config.poolTokenAccount, - "Pool Token Account" - ) - ); - - // CCIP Integration - this.logger.info("\\nšŸŒ‰ CCIP INTEGRATION"); - this.logger.info("-".repeat(POOL_INFO_CONFIG.subSeparatorLength)); - this.logger.info(this.formatPublicKey(poolInfo.config.config.router, "CCIP Router")); - this.logger.info( - this.formatPublicKey( - poolInfo.config.config.routerOnrampAuthority, - "Router Onramp Authority" - ) - ); - this.logger.info( - this.formatPublicKey(poolInfo.config.config.rmnRemote, "RMN Remote") - ); - - // Security & Controls - this.logger.info("\\nšŸ”’ SECURITY & CONTROLS"); - this.logger.info("-".repeat(POOL_INFO_CONFIG.subSeparatorLength)); - this.logger.info( - `Allowlist: ${this.formatBoolean(poolInfo.config.config.listEnabled)}` - ); - if ( - poolInfo.config.config.listEnabled && - poolInfo.config.config.allowList.length > 0 - ) { - this.logger.info( - `Allowlist Entries (${poolInfo.config.config.allowList.length}):` - ); - poolInfo.config.config.allowList.forEach((addr, index) => { - this.logger.info(` ${index + 1}. ${addr.toString()}`); - }); - } else if (poolInfo.config.config.listEnabled) { - this.logger.info( - " āš ļø Allowlist is enabled but empty - no addresses can transfer" - ); - } - - // Rebalancing (for reference, not used in burn-mint pools) - this.logger.info("\\nāš–ļø REBALANCING (Lock/Release Only)"); - this.logger.info("-".repeat(POOL_INFO_CONFIG.subSeparatorLength)); - this.logger.info( - this.formatPublicKey(poolInfo.config.config.rebalancer, "Rebalancer") - ); - this.logger.info( - `Can Accept Liquidity: ${this.formatBoolean( - poolInfo.config.config.canAcceptLiquidity - )}` - ); - - // Address Summary - this.logger.info("\\nšŸ“ ADDRESS SUMMARY"); - this.logger.info("-".repeat(POOL_INFO_CONFIG.subSeparatorLength)); - - // Derive important PDAs for the summary - const [poolConfigPDA] = findBurnMintPoolConfigPDA( - tokenMint, - burnMintPoolProgramId - ); - const [globalConfigPDA] = findGlobalConfigPDA(burnMintPoolProgramId); - - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info( - `Pool Config PDA: ${poolConfigPDA.toString()} (Pool state account)` - ); - this.logger.info( - `Global Config PDA: ${globalConfigPDA.toString()} (Program global config)` - ); - this.logger.info( - `Pool Owner: ${poolInfo.config.config.owner.toString()}` - ); - this.logger.info( - `Pool Signer PDA: ${poolInfo.config.config.poolSigner.toString()} (Token authority)` - ); - - this.logger.info("\\n" + "=".repeat(POOL_INFO_CONFIG.separatorLength)); - this.logger.info("āœ… Pool information retrieved successfully!"); - - // Next steps suggestions - this.logger.info("\\nšŸ’” NEXT STEPS"); - this.logger.info("-".repeat(POOL_INFO_CONFIG.subSeparatorLength)); - this.logger.info("• Configure remote chains for cross-chain transfers"); - this.logger.info("• Set up rate limits for security"); - this.logger.info("• Configure allowlists if needed"); - this.logger.info("• Transfer ownership if this is a temporary deployer"); - } - - protected async execute(): Promise { - this.logger.info("šŸŠ CCIP Token Pool Information"); - this.logger.info("==========================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet (for querying purposes) - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Querying as: ${walletKeypair.publicKey.toString()}`); - - // Validate configuration and parse parameters - const { tokenMint, burnMintPoolProgramId } = this.validateConfig(); - - this.logger.info(""); - this.logger.info("āš™ļø QUERY CONFIGURATION"); - this.logger.info("==========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Program ID: ${burnMintPoolProgramId.toString()}`); - - this.logger.debug(""); - this.logger.debug("šŸ” CONFIGURATION DETAILS"); - this.logger.debug("==========================================="); - this.logger.debug(`Network: ${config.id}`); - this.logger.debug(`Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(`Log level: ${this.options.logLevel}`); - this.logger.debug(`Wallet: ${walletKeypair.publicKey.toString()}`); - - try { - // Create token pool manager using SDK - const programIds = { burnMint: burnMintPoolProgramId }; - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - programIds, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? POOL_INFO_CONFIG.defaultLogLevel } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Check if pool exists - this.logger.info(""); - this.logger.info("šŸ” POOL EXISTENCE CHECK"); - this.logger.info("==========================================="); - const poolExists = await this.checkPoolExistence( - tokenMint, - burnMintPoolProgramId, - tokenPoolClient - ); - - if (!poolExists) { - return; - } - - // Get pool information - this.logger.info(""); - this.logger.info("šŸ“Š FETCHING POOL DATA"); - this.logger.info("==========================================="); - this.logger.info("Fetching pool information..."); - this.logger.debug("Retrieving complete pool configuration..."); - - const poolInfo = await tokenPoolClient.getPoolInfo(tokenMint) as BurnMintTokenPoolInfo; - this.logger.debug("Pool info retrieved:", { - poolType: poolInfo.poolType, - version: poolInfo.config.version, - owner: poolInfo.config.config.owner.toString(), - mint: poolInfo.config.config.mint.toString(), - decimals: poolInfo.config.config.decimals, - }); - this.logger.trace("Complete pool info:", poolInfo); - - // Get global config information - const globalConfigInfo = await this.getGlobalConfigInfo(tokenPoolClient); - - // Display comprehensive pool information - this.displayPoolInfo(poolInfo, globalConfigInfo, tokenMint, burnMintPoolProgramId); - - } catch (error) { - this.logger.error("Failed to get pool info:", error); - - if (error instanceof Error) { - if (error.message.includes("not found")) { - this.logger.info("\\nāŒ Pool not found"); - this.logger.info( - "The pool may not be initialized yet or the addresses may be incorrect." - ); - } else if (error.message.includes("Account is not owned")) { - this.logger.info("\\nāŒ Invalid program ID"); - this.logger.info( - "The account exists but is not owned by the specified program." - ); - } - } - - throw error; - } - } -} - -// Create and run the command -const command = new GetPoolInfoCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/pool/get-pool-signer.ts b/ccip-scripts/svm/pool/get-pool-signer.ts deleted file mode 100644 index bba99ea1..00000000 --- a/ccip-scripts/svm/pool/get-pool-signer.ts +++ /dev/null @@ -1,183 +0,0 @@ -/** - * Token Pool Signer PDA Retrieval Script (CLI Framework Version) - * - * This script retrieves the Pool Signer PDA for a burn-mint token pool. - * The Pool Signer PDA is used as the authority for token operations and - * is essential for transferring mint authority to enable CCIP functionality. - */ - -import { PublicKey } from "@solana/web3.js"; -import { findPoolSignerPDA } from "../../../ccip-lib/svm/utils/pdas/tokenpool"; -import { LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for get pool signer operations - */ -const GET_POOL_SIGNER_CONFIG = { - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the get-pool-signer command - */ -interface GetPoolSignerOptions extends BaseCommandOptions { - tokenMint: string; - burnMintPoolProgram: string; -} - -/** - * Get Pool Signer Command - */ -class GetPoolSignerCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "get-pool-signer", - description: "šŸ” Token Pool Signer PDA Reader\n\nRetrieves the Pool Signer PDA for a burn-mint token pool. The Pool Signer PDA is used as the authority for token operations and is essential for transferring mint authority to enable CCIP functionality.", - examples: [ - "# Get pool signer PDA", - "yarn svm:pool:get-pool-signer --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh", - "", - "# Get pool signer with debug logging", - "yarn svm:pool:get-pool-signer --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --log-level DEBUG" - ], - notes: [ - "This is a read-only operation that doesn't require a wallet", - "The PDA is deterministically derived from the token mint and program ID", - "Use the returned address to transfer mint authority to the token pool", - "The pool program uses this PDA for automated token operations during CCIP transfers", - "This PDA serves as the authority for token operations", - "Transfer mint authority to this address to enable CCIP", - "The pool program will use this PDA for burns/mints during cross-chain transfers", - "Seeds used: ['ccip_tokenpool_signer', token_mint]" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - } - ]; - } - - protected async execute(): Promise { - this.logger.info("šŸ” CCIP Token Pool Signer PDA Reader (Read-Only)"); - this.logger.info("=========================================="); - - // Parse and validate addresses - let tokenMint: PublicKey; - let burnMintPoolProgramId: PublicKey; - - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - throw new Error(`Invalid burn-mint pool program ID: ${this.options.burnMintPoolProgram}`); - } - - // Display input parameters - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Burn-Mint Pool Program: ${burnMintPoolProgramId.toString()}`); - - this.logger.debug("Configuration details:"); - this.logger.debug(` Log level: ${this.options.logLevel}`); - - try { - // Derive the Pool Signer PDA - this.logger.info(""); - this.logger.info("šŸ”§ DERIVING POOL SIGNER PDA"); - this.logger.info("=========================================="); - this.logger.info("Deriving Pool Signer PDA..."); - - const [poolSignerPDA, poolSignerBump] = findPoolSignerPDA( - tokenMint, - burnMintPoolProgramId - ); - - // Display the results - this.logger.info(""); - this.logger.info("šŸ“‹ POOL SIGNER PDA DETAILS"); - this.logger.info("=========================================="); - this.logger.info(`Address: ${poolSignerPDA.toString()}`); - this.logger.info(`Bump Seed: ${poolSignerBump}`); - - this.logger.info(""); - this.logger.info("šŸ”§ PDA DERIVATION"); - this.logger.info("------------------------------------------"); - this.logger.info(`Seeds: ["ccip_tokenpool_signer", "${tokenMint.toString()}"]`); - this.logger.info(`Program: ${burnMintPoolProgramId.toString()}`); - - this.logger.info(""); - this.logger.info("šŸ“ USAGE NOTES"); - this.logger.info("------------------------------------------"); - this.logger.info("• This PDA serves as the authority for token operations"); - this.logger.info("• Transfer mint authority to this address to enable CCIP"); - this.logger.info("• The pool program will use this PDA for burns/mints during cross-chain transfers"); - - this.logger.info(""); - this.logger.info("šŸ”— NEXT STEPS"); - this.logger.info("------------------------------------------"); - this.logger.info("1. Transfer mint authority to this PDA address"); - this.logger.info("2. Verify the transfer using token program commands"); - this.logger.info("3. The token pool will then have authority for CCIP operations"); - - this.logger.info(""); - this.logger.info("šŸ’” Use this PDA address for mint authority transfer operations"); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Pool Signer PDA Retrieved Successfully!"); - this.logger.info(`āœ… PDA Address: ${poolSignerPDA.toString()}`); - - } catch (error) { - this.logger.error( - `āŒ Failed to derive Pool Signer PDA: ${error instanceof Error ? error.message : String(error)}` - ); - - this.logger.info(""); - this.logger.info("āŒ COMMON ISSUES"); - this.logger.info("=========================================="); - this.logger.info("• Invalid token mint address format"); - this.logger.info("• Invalid burn-mint pool program ID format"); - - this.logger.info(""); - this.logger.info("šŸ’” SOLUTIONS"); - this.logger.info("=========================================="); - this.logger.info("• Verify token mint address is a valid PublicKey"); - this.logger.info("• Verify pool program ID is a valid PublicKey"); - this.logger.info("• Check addresses for typos or formatting issues"); - - if (error instanceof Error && error.stack) { - this.logger.debug("\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new GetPoolSignerCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/pool/init-chain-remote-config.ts b/ccip-scripts/svm/pool/init-chain-remote-config.ts deleted file mode 100644 index 11474b55..00000000 --- a/ccip-scripts/svm/pool/init-chain-remote-config.ts +++ /dev/null @@ -1,293 +0,0 @@ -/** - * Chain Remote Configuration Initialization Script (CLI Framework Version) - * - * This script initializes a chain remote configuration for a burn-mint token pool, - * enabling cross-chain token transfers to a specific remote chain. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenPoolManager } from "../../../ccip-lib/svm/core/client/tokenpools"; -import { TokenPoolType, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { ChainId, CHAIN_SELECTORS, resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { getKeypairPath, loadKeypair } from "../utils"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for init chain remote config operations - */ -const INIT_CHAIN_CONFIG = { - minSolRequired: 0.01, - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the init-chain-remote-config command - */ -interface InitChainRemoteConfigOptions extends BaseCommandOptions { - tokenMint: string; - burnMintPoolProgram: string; - remoteChain: string; - tokenAddress: string; - decimals: number; -} - -/** - * Init Chain Remote Configuration Command - */ -class InitChainRemoteConfigCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "init-chain-remote-config", - description: "šŸ”— Chain Remote Configuration Initializer\n\nInitializes a chain remote configuration for a burn-mint token pool, enabling cross-chain token transfers to a specific remote chain.", - examples: [ - "# Initialize chain config for Ethereum Sepolia", - "yarn svm:pool:init-chain-remote-config --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --remote-chain ethereum-sepolia --token-address \"0xA0b86991c431e59b4b59dac67ba9b82c31a30d15c\" --decimals 6", - "", - "# Initialize chain config for Base Sepolia", - "yarn svm:pool:init-chain-remote-config --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --remote-chain base-sepolia --token-address \"0xA0b86991c431e59b4b59dac67ba9b82c31a30d15c\" --decimals 6" - ], - notes: [ - `Minimum ${INIT_CHAIN_CONFIG.minSolRequired} SOL required for transaction fees`, - "The token pool must already exist before configuring chains", - "Wallet must be the pool administrator", - "Addresses should be provided as hex strings with '0x' prefix", - "Pool addresses are NOT provided during initialization (required by Rust program)", - "Use 'yarn svm:pool:edit-chain-remote-config' to add pool addresses after initialization", - "Remote chains: ethereum-sepolia, avalanche-fuji, base-sepolia, etc.", - "Chain configuration initialization requires SOL for transaction fees" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address of existing pool", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - }, - { - name: "remote-chain", - required: true, - type: "string", - description: "Remote chain to configure (chain-id)", - example: "ethereum-sepolia" - }, - { - name: "token-address", - required: true, - type: "string", - description: "Token address on remote chain (hex)", - example: "0xA0b86991c431e59b4b59dac67ba9b82c31a30d15c" - }, - { - name: "decimals", - required: true, - type: "number", - description: "Token decimals on remote chain", - example: "6" - } - ]; - } - - /** - * Resolve remote chain selector from chain ID - */ - private resolveRemoteChainSelector(remoteChain: string): bigint { - const chainSelector = CHAIN_SELECTORS[remoteChain as ChainId]; - if (!chainSelector) { - throw new Error( - `Unknown remote chain: ${remoteChain}\n` + - `Available chains: ${Object.keys(CHAIN_SELECTORS).join(", ")}` - ); - } - return chainSelector; - } - - /** - * Display available remote chains - */ - private displayAvailableChains(): void { - this.logger.info(""); - this.logger.info("šŸ“‹ AVAILABLE REMOTE CHAINS"); - this.logger.info("=========================================="); - Object.entries(CHAIN_SELECTORS).forEach(([chainId, selector]) => { - this.logger.info(` ${chainId}: ${selector.toString()}`); - }); - } - - protected async execute(): Promise { - this.logger.info("šŸ”— CCIP Chain Remote Configuration Initialization"); - this.logger.info("=========================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("=========================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalance = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalance.toFixed(9)} SOL)`); - - if (solBalance < INIT_CHAIN_CONFIG.minSolRequired) { - throw new Error( - `Insufficient balance. Need at least ${INIT_CHAIN_CONFIG.minSolRequired} SOL for transaction fees.\n` + - `Current balance: ${solBalance.toFixed(9)} SOL\n\n` + - `Request airdrop with:\n` + - `solana airdrop 1 ${walletKeypair.publicKey.toString()} --url devnet` - ); - } - - // Parse and validate addresses - let tokenMint: PublicKey; - let burnMintPoolProgramId: PublicKey; - - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - throw new Error(`Invalid burn-mint pool program ID: ${this.options.burnMintPoolProgram}`); - } - - // Resolve remote chain selector - let remoteChainSelector: bigint; - try { - remoteChainSelector = this.resolveRemoteChainSelector(this.options.remoteChain); - } catch (error) { - this.displayAvailableChains(); - throw error; - } - - const tokenAddress = this.options.tokenAddress; - const decimals = this.options.decimals; - - // Validate hex address - const hexRegex = /^0x[a-fA-F0-9]+$/; - if (!hexRegex.test(tokenAddress)) { - throw new Error(`Invalid hex token address format: ${tokenAddress}. Must start with '0x' and contain only hex characters.`); - } - - // Display configuration - this.logger.info(""); - this.logger.info("šŸ“‹ INITIALIZATION CONFIGURATION"); - this.logger.info("=========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Burn-Mint Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`Remote Chain: ${this.options.remoteChain}`); - this.logger.info(`Remote Chain Selector: ${remoteChainSelector.toString()}`); - this.logger.info(`Token Address: ${tokenAddress}`); - this.logger.info(`Decimals: ${decimals}`); - - this.logger.debug("Configuration details:"); - this.logger.debug(` Network: ${config.id}`); - this.logger.debug(` Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(` Commitment level: ${config.connection.commitment}`); - this.logger.debug(` Skip preflight: ${this.options.skipPreflight}`); - - try { - // Create token pool manager using SDK - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - { - burnMint: burnMintPoolProgramId, - }, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? LogLevel.INFO } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Initialize the chain remote config (pool addresses must be empty for initialization) - this.logger.info(""); - this.logger.info("šŸ”§ INITIALIZING CHAIN REMOTE CONFIG"); - this.logger.info("=========================================="); - this.logger.info("Creating chain remote configuration..."); - this.logger.info("Note: Pool addresses will be empty initially"); - - const result = await tokenPoolClient.initChainRemoteConfig(tokenMint, remoteChainSelector, { - tokenAddress, - decimals, - txOptions: { - skipPreflight: this.options.skipPreflight, - }, - }); - - // Display results - this.logger.info(""); - this.logger.info("āœ… CHAIN CONFIG INITIALIZED SUCCESSFULLY"); - this.logger.info("=========================================="); - this.logger.info(`Transaction Signature: ${result.signature}`); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("=========================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, result.signature)}`); - - this.logger.info(""); - this.logger.info("šŸ“‹ NEXT STEPS"); - this.logger.info("=========================================="); - this.logger.info("1. View configuration details:"); - this.logger.info(` yarn svm:pool:get-info --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()}`); - this.logger.info(""); - this.logger.info("2. Add pool addresses to enable cross-chain transfers:"); - this.logger.info(` yarn svm:pool:edit-chain-remote-config --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()} --remote-chain ${this.options.remoteChain} --pool-addresses "0x..." --token-address "${tokenAddress}" --decimals ${decimals}`); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Chain Configuration Initialization Complete!"); - this.logger.info(`āœ… Remote chain ${this.options.remoteChain} configuration created`); - this.logger.info(`āœ… Token address and decimals configured`); - this.logger.info(`āš ļø Pool addresses must be added before transfers can occur`); - - } catch (error) { - this.logger.error( - `āŒ Failed to initialize chain remote configuration: ${error instanceof Error ? error.message : String(error)}` - ); - - if (error instanceof Error && error.stack) { - this.logger.debug("\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new InitChainRemoteConfigCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/pool/initialize-global-config.ts b/ccip-scripts/svm/pool/initialize-global-config.ts deleted file mode 100644 index 09a35251..00000000 --- a/ccip-scripts/svm/pool/initialize-global-config.ts +++ /dev/null @@ -1,228 +0,0 @@ -/** - * Global Config Initialization Script (CLI Framework Version) - * - * This script initializes the global configuration for a burn-mint token pool program. - * This MUST be run once per program deployment before any individual pools can be created. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenPoolManager } from "../../../ccip-lib/svm/core/client/tokenpools"; -import { TokenPoolType, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { getKeypairPath, loadKeypair } from "../utils"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for global config initialization - */ -const GLOBAL_CONFIG_CONFIG = { - minSolRequired: 0.01, - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the initialize-global-config command - */ -interface InitializeGlobalConfigOptions extends BaseCommandOptions { - burnMintPoolProgram: string; -} - -/** - * Global Config Initialization Command - */ -class InitializeGlobalConfigCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "initialize-global-config", - description: "šŸŒ Global Config Initialization\n\nInitializes the global configuration for a burn-mint token pool program. This MUST be run once per program deployment before any individual pools can be created.", - examples: [ - "# Initialize global config with burn-mint pool program", - "yarn svm:pool:init-global-config --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh", - "", - "# Initialize with debug logging", - "yarn svm:pool:init-global-config --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --log-level DEBUG" - ], - notes: [ - "āš ļø This must be run by the program upgrade authority", - "This only needs to be run ONCE per program deployment", - `Minimum ${GLOBAL_CONFIG_CONFIG.minSolRequired} SOL required for transaction fees`, - "Creates the program-wide configuration PDA", - "After this succeeds, individual pools can be initialized with initialize-pool.ts", - "Global config initialization is a prerequisite for all pool operations", - "If already initialized, the script will fail with an appropriate message" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - } - ]; - } - - protected async execute(): Promise { - this.logger.info("šŸŒ CCIP Token Pool Global Config Initialization"); - this.logger.info("=========================================="); - this.logger.warn("āš ļø This must be run by the program upgrade authority ONCE per deployment"); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet (must be upgrade authority) - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - this.logger.warn("šŸ”‘ Ensure this wallet is the program upgrade authority for the token pool program"); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("=========================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalance = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalance.toFixed(9)} SOL)`); - - if (solBalance < GLOBAL_CONFIG_CONFIG.minSolRequired) { - throw new Error( - `Insufficient balance. Need at least ${GLOBAL_CONFIG_CONFIG.minSolRequired} SOL for transaction fees.\n` + - `Current balance: ${solBalance.toFixed(9)} SOL\n\n` + - `Request airdrop with:\n` + - `solana airdrop 1 ${walletKeypair.publicKey.toString()} --url devnet` - ); - } - - // Parse and validate burn-mint pool program ID - let burnMintPoolProgramId: PublicKey; - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - throw new Error(`Invalid burn-mint pool program ID: ${this.options.burnMintPoolProgram}`); - } - - // Display program information - this.logger.info(""); - this.logger.info("šŸ“‹ PROGRAM INFORMATION"); - this.logger.info("=========================================="); - this.logger.info(`Burn-Mint Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`Router Program: ${config.routerProgramId.toString()}`); - this.logger.info(`RMN Remote Program: ${config.rmnRemoteProgramId.toString()}`); - - this.logger.debug("Global config initialization details:"); - this.logger.debug(` Network: ${config.id}`); - this.logger.debug(` Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(` Commitment level: ${config.connection.commitment}`); - this.logger.debug(` Authority: ${walletKeypair.publicKey.toString()}`); - this.logger.debug(` Skip preflight: ${this.options.skipPreflight}`); - - try { - // Create token pool manager using SDK - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - { - burnMint: burnMintPoolProgramId, - }, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? LogLevel.INFO } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Initialize the global config - this.logger.info(""); - this.logger.info("šŸ”§ INITIALIZING GLOBAL CONFIG"); - this.logger.info("=========================================="); - this.logger.info("Creating the program-wide configuration PDA..."); - - this.logger.debug("Calling SDK initializeGlobalConfig method..."); - this.logger.debug(`Transaction options: skipPreflight=${this.options.skipPreflight}`); - - const signature = await tokenPoolClient.initializeGlobalConfig({ - txOptions: { - skipPreflight: this.options.skipPreflight, - }, - }); - - this.logger.debug(`Transaction completed with signature: ${signature}`); - - // Display results - this.logger.info(""); - this.logger.info("āœ… GLOBAL CONFIG INITIALIZED SUCCESSFULLY"); - this.logger.info("=========================================="); - this.logger.info(`Transaction Signature: ${signature}`); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("=========================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, signature)}`); - - this.logger.info(""); - this.logger.info("šŸ“‹ NEXT STEPS"); - this.logger.info("=========================================="); - this.logger.info("1. Deploy your token mint (if not already done)"); - this.logger.info("2. Enable self-served pools:"); - this.logger.info(" yarn svm:pool:update-self-served-allowed --self-served-allowed true --burn-mint-pool-program "); - this.logger.info("3. Initialize individual token pools:"); - this.logger.info(" yarn svm:pool:initialize-pool"); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Global Configuration Complete!"); - this.logger.info("āœ… Global configuration is now ready"); - this.logger.info("āœ… You can now initialize individual token pools"); - - } catch (error) { - // Handle specific error cases - if (error instanceof Error) { - if (error.message.includes("Unauthorized")) { - this.logger.error(""); - this.logger.error("🚨 AUTHORIZATION ERROR"); - this.logger.error("=========================================="); - this.logger.error("The wallet is not the program upgrade authority for this program."); - this.logger.error("Only the program upgrade authority can initialize global config."); - throw error; - } else if (error.message.includes("already in use")) { - this.logger.warn(""); - this.logger.warn("āš ļø ALREADY INITIALIZED"); - this.logger.warn("=========================================="); - this.logger.warn("Global config may already be initialized."); - this.logger.warn("This script only needs to be run once per deployment."); - throw error; - } - } - - this.logger.error( - `āŒ Failed to initialize global config: ${error instanceof Error ? error.message : String(error)}` - ); - - if (error instanceof Error && error.stack) { - this.logger.debug("\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new InitializeGlobalConfigCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/pool/initialize-pool.ts b/ccip-scripts/svm/pool/initialize-pool.ts deleted file mode 100644 index 4e123cb0..00000000 --- a/ccip-scripts/svm/pool/initialize-pool.ts +++ /dev/null @@ -1,329 +0,0 @@ -/** - * Token Pool Initialization Script (CLI Framework Version) - * - * This script initializes a burn-mint token pool for CCIP cross-chain token transfers. - * It creates a State PDA (Program Derived Address) that stores the pool configuration. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenPoolManager, TokenPoolType, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { ChainId, getCCIPSVMConfig, resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { loadKeypair, getKeypairPath } from "../utils"; -import { findBurnMintPoolConfigPDA } from "../../../ccip-lib/svm/utils/pdas/tokenpool"; -import { BurnMintTokenPoolInfo } from "../../../ccip-lib/svm/tokenpools/burnmint/accounts"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for pool initialization operations - */ -const POOL_INIT_CONFIG = { - minSolRequired: 0.01, - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the initialize-pool command - */ -interface InitializePoolOptions extends BaseCommandOptions { - tokenMint: string; - burnMintPoolProgram: string; -} - -/** - * Token Pool Initialization Command - */ -class InitializePoolCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "initialize-pool", - description: "šŸŠ CCIP Token Pool Initializer\\n\\nInitializes a burn-mint token pool for CCIP cross-chain token transfers. Creates a State PDA that stores the pool configuration.", - examples: [ - "# Initialize a token pool", - "yarn svm:pool:initialize --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh", - "", - "# With debug logging", - "yarn svm:pool:initialize --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --log-level DEBUG" - ], - notes: [ - "The wallet will become the pool administrator", - "Router and RMN Remote program IDs are retrieved from configuration", - "Pool initialization requires SOL for transaction fees", - "Creates a State PDA account that represents the pool configuration", - `Minimum ${POOL_INIT_CONFIG.minSolRequired} SOL required for transaction fees`, - "Pool must be initialized before other operations like registration or transfers" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address to create pool for", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - } - ]; - } - - /** - * Validate pool initialization configuration - */ - private validateConfig(): { tokenMint: PublicKey; burnMintPoolProgramId: PublicKey } { - const errors: string[] = []; - - // Validate token mint address - let tokenMint: PublicKey; - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - errors.push("Invalid token mint address format"); - throw new Error(`Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}`); - } - - // Validate burn-mint pool program ID - let burnMintPoolProgramId: PublicKey; - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - errors.push("Invalid burn-mint pool program ID format"); - throw new Error(`Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}`); - } - - if (errors.length > 0) { - throw new Error( - `Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}` - ); - } - - return { tokenMint, burnMintPoolProgramId }; - } - - /** - * Check if pool already exists - */ - private async checkPoolExistence( - tokenMint: PublicKey, - burnMintPoolProgramId: PublicKey, - config: any - ): Promise<{ exists: boolean; statePDA: PublicKey; stateBump: number }> { - this.logger.info("Checking if pool already exists..."); - - const [statePDA, stateBump] = findBurnMintPoolConfigPDA( - tokenMint, - burnMintPoolProgramId - ); - this.logger.debug(`State PDA: ${statePDA.toString()} (bump: ${stateBump})`); - - const stateAccountInfo = await config.connection.getAccountInfo(statePDA); - const poolExists = stateAccountInfo !== null; - this.logger.debug(`Pool exists: ${poolExists}`); - - if (poolExists) { - this.logger.warn("Pool already exists for this token mint"); - this.logger.info(`Existing pool State PDA: ${statePDA.toString()}`); - this.logger.info("Use 'yarn svm:pool:get-info' to view pool details"); - this.logger.debug( - `To view details: yarn svm:pool:get-info --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()}` - ); - } - - return { exists: poolExists, statePDA, stateBump }; - } - - /** - * Verify pool initialization was successful - */ - private async verifyPoolInitialization( - tokenMint: PublicKey, - burnMintPoolProgramId: PublicKey, - statePDA: PublicKey, - stateBump: number, - tokenPoolClient: any - ): Promise { - this.logger.info("Verifying pool initialization..."); - this.logger.debug("Attempting to fetch pool info to verify initialization..."); - - try { - const poolInfo = await tokenPoolClient.getPoolInfo(tokenMint) as BurnMintTokenPoolInfo; - this.logger.info("āœ… Pool initialization verified successfully!"); - this.logger.info(`āœ… State PDA confirmed active: ${statePDA.toString()}`); - - this.logger.debug("Pool verification details:", { - statePDA: statePDA.toString(), - stateBump: stateBump, - poolType: poolInfo.poolType, - owner: poolInfo.config.config.owner.toString(), - version: poolInfo.config.version, - decimals: poolInfo.config.config.decimals, - router: poolInfo.config.config.router.toString(), - }); - this.logger.trace("Complete verification info:", poolInfo); - - this.logger.info(""); - this.logger.info("šŸŽÆ POOL CREATION SUMMARY"); - this.logger.info("==============================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`State PDA: ${statePDA.toString()}`); - this.logger.info(`Owner: ${poolInfo.config.config.owner.toString()}`); - this.logger.info(`Program: ${burnMintPoolProgramId.toString()}`); - - this.logger.info(""); - this.logger.info("šŸ’” NEXT STEPS"); - this.logger.info("==============================================="); - this.logger.info(`View details: yarn svm:pool:get-info --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()}`); - - } catch (error) { - this.logger.warn( - `Pool transaction succeeded but verification failed: ${error instanceof Error ? error.message : String(error)}` - ); - this.logger.debug("Verification error details:", error); - - this.logger.info(""); - this.logger.info("šŸŽÆ POOL CREATION SUMMARY (UNVERIFIED)"); - this.logger.info("==============================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`State PDA: ${statePDA.toString()}`); - this.logger.info(`Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(""); - this.logger.info("This may be due to network delays - the pool should exist shortly"); - } - } - - protected async execute(): Promise { - this.logger.info("CCIP Token Pool Initialization"); - this.logger.info("==========================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("==========================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalanceDisplay = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalanceDisplay.toFixed(9)} SOL)`); - - if (solBalanceDisplay < POOL_INIT_CONFIG.minSolRequired) { - throw new Error( - `Insufficient SOL balance. Need at least ${POOL_INIT_CONFIG.minSolRequired} SOL for transaction fees. ` + - `Current balance: ${solBalanceDisplay.toFixed(9)} SOL` - ); - } - - // Validate configuration and parse parameters - const { tokenMint, burnMintPoolProgramId } = this.validateConfig(); - - this.logger.info(""); - this.logger.info("āš™ļø POOL CONFIGURATION"); - this.logger.info("==========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Burn-Mint Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`Router Program: ${config.routerProgramId.toString()}`); - this.logger.info(`RMN Remote Program: ${config.rmnRemoteProgramId.toString()}`); - - this.logger.debug(""); - this.logger.debug("šŸ” CONFIGURATION DETAILS"); - this.logger.debug("==========================================="); - this.logger.debug(`Network: ${config.id}`); - this.logger.debug(`Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(`Commitment level: ${config.connection.commitment}`); - this.logger.debug(`Skip preflight: ${this.options.skipPreflight}`); - this.logger.debug(`Log level: ${this.options.logLevel}`); - - // Create token pool manager using SDK - const programIds = { burnMint: burnMintPoolProgramId }; - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - programIds, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? POOL_INIT_CONFIG.defaultLogLevel } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Check if pool already exists - this.logger.info(""); - this.logger.info("šŸ” POOL EXISTENCE CHECK"); - this.logger.info("==========================================="); - const { exists: poolExists, statePDA, stateBump } = await this.checkPoolExistence( - tokenMint, - burnMintPoolProgramId, - config - ); - - if (poolExists) { - return; - } - - // Initialize the pool - this.logger.info(""); - this.logger.info("šŸ—ļø INITIALIZING POOL"); - this.logger.info("==========================================="); - this.logger.info("Initializing token pool..."); - this.logger.debug(`Creating State PDA at: ${statePDA.toString()}`); - - const signature = await tokenPoolClient.initializePool(tokenMint, { - txOptions: { - skipPreflight: this.options.skipPreflight, - }, - }); - - // Display results - this.logger.info(""); - this.logger.info("āœ… POOL INITIALIZED SUCCESSFULLY"); - this.logger.info("==========================================="); - this.logger.info(`Transaction Signature: ${signature}`); - this.logger.info(`šŸ“ Pool State PDA: ${statePDA.toString()}`); - this.logger.debug(`State PDA bump: ${stateBump}`); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("==========================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, signature)}`); - - // Verify initialization - this.logger.info(""); - this.logger.info("šŸ” VERIFICATION"); - this.logger.info("==========================================="); - await this.verifyPoolInitialization( - tokenMint, - burnMintPoolProgramId, - statePDA, - stateBump, - tokenPoolClient - ); - } -} - -// Create and run the command -const command = new InitializePoolCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/pool/set-rate-limit.ts b/ccip-scripts/svm/pool/set-rate-limit.ts deleted file mode 100644 index e08e06a5..00000000 --- a/ccip-scripts/svm/pool/set-rate-limit.ts +++ /dev/null @@ -1,373 +0,0 @@ -/** - * Set Rate Limit Script (CLI Framework Version) - * - * This script configures inbound and outbound rate limits for a burn-mint token pool - * on a specific remote chain. Rate limits control the maximum token transfer capacity - * and refill rate to manage cross-chain transfer risks. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenPoolManager } from "../../../ccip-lib/svm/core/client/tokenpools"; -import { TokenPoolType, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { ChainId, CHAIN_SELECTORS, resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { getKeypairPath, loadKeypair } from "../utils"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for rate limit operations - */ -const RATE_LIMIT_CONFIG = { - minSolRequired: 0.01, - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the set-rate-limit command - */ -interface SetRateLimitOptions extends BaseCommandOptions { - tokenMint: string; - burnMintPoolProgram: string; - remoteChain: string; - inboundEnabled: boolean; - inboundCapacity: string; - inboundRate: string; - outboundEnabled: boolean; - outboundCapacity: string; - outboundRate: string; -} - -/** - * Set Rate Limit Command - */ -class SetRateLimitCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "set-rate-limit", - description: "⚔ Rate Limit Configuration Manager\n\nConfigure inbound and outbound rate limits for a burn-mint token pool on a specific remote chain. Rate limits control the maximum token transfer capacity and refill rate to manage cross-chain transfer risks.", - examples: [ - "# Set rate limits for Ethereum Sepolia", - "yarn svm:pool:set-rate-limit --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --remote-chain ethereum-sepolia --inbound-enabled true --inbound-capacity 1000000000000000000 --inbound-rate 100000000000000000 --outbound-enabled true --outbound-capacity 500000000000000000 --outbound-rate 50000000000000000", - "", - "# Disable inbound rate limiting, keep outbound active", - "yarn svm:pool:set-rate-limit --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --remote-chain ethereum-sepolia --inbound-enabled false --inbound-capacity 0 --inbound-rate 0 --outbound-enabled true --outbound-capacity 1000000000000000000 --outbound-rate 100000000000000000", - "", - "# Set conservative rate limits for production", - "yarn svm:pool:set-rate-limit --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --remote-chain ethereum-sepolia --inbound-enabled true --inbound-capacity 10000000000000000000 --inbound-rate 1000000000000000000 --outbound-enabled true --outbound-capacity 10000000000000000000 --outbound-rate 1000000000000000000" - ], - notes: [ - `Minimum ${RATE_LIMIT_CONFIG.minSolRequired} SOL required for transaction fees`, - "The token pool and chain configuration must already exist", - "Wallet must be the pool owner or rate limit admin", - "Capacity and rate values are in token's smallest unit (e.g., wei for 18-decimal tokens)", - "Rate is tokens per second that refill the bucket", - "Capacity is the maximum bucket size (burst limit)", - "Setting enabled=false disables rate limiting for that direction", - "Inbound = tokens coming FROM the remote chain TO Solana", - "Outbound = tokens going FROM Solana TO the remote chain", - "Use 'yarn svm:pool:get-info' to view current rate limits" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address of existing pool", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - }, - { - name: "remote-chain", - required: true, - type: "string", - description: "Remote chain to configure rate limits for (chain-id)", - example: "ethereum-sepolia" - }, - { - name: "inbound-enabled", - required: true, - type: "boolean", - description: "Enable inbound rate limiting (tokens FROM remote chain TO Solana)", - example: "true" - }, - { - name: "inbound-capacity", - required: true, - type: "string", - description: "Inbound rate limit capacity (bucket size in token's smallest unit)", - example: "1000000000000000000" - }, - { - name: "inbound-rate", - required: true, - type: "string", - description: "Inbound refill rate (tokens per second in token's smallest unit)", - example: "100000000000000000" - }, - { - name: "outbound-enabled", - required: true, - type: "boolean", - description: "Enable outbound rate limiting (tokens FROM Solana TO remote chain)", - example: "true" - }, - { - name: "outbound-capacity", - required: true, - type: "string", - description: "Outbound rate limit capacity (bucket size in token's smallest unit)", - example: "500000000000000000" - }, - { - name: "outbound-rate", - required: true, - type: "string", - description: "Outbound refill rate (tokens per second in token's smallest unit)", - example: "50000000000000000" - } - ]; - } - - /** - * Resolve remote chain selector from chain ID - */ - private resolveRemoteChainSelector(remoteChain: string): bigint { - const chainSelector = CHAIN_SELECTORS[remoteChain as ChainId]; - if (!chainSelector) { - throw new Error( - `Unknown remote chain: ${remoteChain}\n` + - `Available chains: ${Object.keys(CHAIN_SELECTORS).join(", ")}` - ); - } - return chainSelector; - } - - /** - * Display available remote chains - */ - private displayAvailableChains(): void { - this.logger.info(""); - this.logger.info("šŸ“‹ AVAILABLE REMOTE CHAINS"); - this.logger.info("=========================================="); - Object.entries(CHAIN_SELECTORS).forEach(([chainId, selector]) => { - this.logger.info(` ${chainId}: ${selector.toString()}`); - }); - } - - /** - * Validate and parse numeric string values - */ - private parseTokenAmount(value: string, fieldName: string): bigint { - try { - const parsed = BigInt(value); - if (parsed < 0n) { - throw new Error(`${fieldName} cannot be negative`); - } - return parsed; - } catch (error) { - throw new Error(`Invalid ${fieldName}: ${value}. Must be a valid non-negative integer.`); - } - } - - /** - * Format token amount for display - */ - private formatTokenAmount(amount: bigint, decimals: number = 18): string { - if (amount === 0n) return "0"; - - const divisor = BigInt(10 ** decimals); - const whole = amount / divisor; - const remainder = amount % divisor; - - if (remainder === 0n) { - return whole.toString(); - } - - const fractional = remainder.toString().padStart(decimals, '0').replace(/0+$/, ''); - return `${whole}.${fractional}`; - } - - protected async execute(): Promise { - this.logger.info("⚔ CCIP Rate Limit Configuration Manager"); - this.logger.info("=========================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("=========================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalance = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalance.toFixed(9)} SOL)`); - - if (solBalance < RATE_LIMIT_CONFIG.minSolRequired) { - throw new Error( - `Insufficient balance. Need at least ${RATE_LIMIT_CONFIG.minSolRequired} SOL for transaction fees.\n` + - `Current balance: ${solBalance.toFixed(9)} SOL\n\n` + - `Request airdrop with:\n` + - `solana airdrop 1 ${walletKeypair.publicKey.toString()} --url devnet` - ); - } - - // Parse and validate addresses - let tokenMint: PublicKey; - let burnMintPoolProgramId: PublicKey; - - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - throw new Error(`Invalid burn-mint pool program ID: ${this.options.burnMintPoolProgram}`); - } - - // Resolve remote chain selector - let remoteChainSelector: bigint; - try { - remoteChainSelector = this.resolveRemoteChainSelector(this.options.remoteChain); - } catch (error) { - this.displayAvailableChains(); - throw error; - } - - // Parse and validate rate limit values - const inboundCapacity = this.parseTokenAmount(this.options.inboundCapacity, "inbound capacity"); - const inboundRate = this.parseTokenAmount(this.options.inboundRate, "inbound rate"); - const outboundCapacity = this.parseTokenAmount(this.options.outboundCapacity, "outbound capacity"); - const outboundRate = this.parseTokenAmount(this.options.outboundRate, "outbound rate"); - - // Display configuration - this.logger.info(""); - this.logger.info("šŸ“‹ RATE LIMIT CONFIGURATION"); - this.logger.info("=========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Burn-Mint Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`Remote Chain: ${this.options.remoteChain}`); - this.logger.info(`Remote Chain Selector: ${remoteChainSelector.toString()}`); - this.logger.info(""); - this.logger.info("šŸ“„ INBOUND RATE LIMITS (Remote → Solana):"); - this.logger.info(` Enabled: ${this.options.inboundEnabled}`); - this.logger.info(` Capacity: ${inboundCapacity.toString()} (${this.formatTokenAmount(inboundCapacity)} tokens)`); - this.logger.info(` Rate: ${inboundRate.toString()} (${this.formatTokenAmount(inboundRate)} tokens/sec)`); - this.logger.info(""); - this.logger.info("šŸ“¤ OUTBOUND RATE LIMITS (Solana → Remote):"); - this.logger.info(` Enabled: ${this.options.outboundEnabled}`); - this.logger.info(` Capacity: ${outboundCapacity.toString()} (${this.formatTokenAmount(outboundCapacity)} tokens)`); - this.logger.info(` Rate: ${outboundRate.toString()} (${this.formatTokenAmount(outboundRate)} tokens/sec)`); - - this.logger.debug("Configuration details:"); - this.logger.debug(` Network: ${config.id}`); - this.logger.debug(` Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(` Commitment level: ${config.connection.commitment}`); - this.logger.debug(` Skip preflight: ${this.options.skipPreflight}`); - - try { - // Create token pool manager using SDK - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - { - burnMint: burnMintPoolProgramId, - }, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? LogLevel.INFO } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Set the rate limits - this.logger.info(""); - this.logger.info("⚔ SETTING RATE LIMITS"); - this.logger.info("=========================================="); - this.logger.info("Configuring rate limits..."); - - const signature = await tokenPoolClient.setRateLimit(tokenMint, remoteChainSelector, { - inbound: { - enabled: this.options.inboundEnabled, - capacity: inboundCapacity, - rate: inboundRate, - }, - outbound: { - enabled: this.options.outboundEnabled, - capacity: outboundCapacity, - rate: outboundRate, - }, - txOptions: { - skipPreflight: this.options.skipPreflight, - }, - }); - - // Display results - this.logger.info(""); - this.logger.info("āœ… RATE LIMITS CONFIGURED SUCCESSFULLY"); - this.logger.info("=========================================="); - this.logger.info(`Transaction Signature: ${signature}`); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("=========================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, signature)}`); - - this.logger.info(""); - this.logger.info("šŸ“‹ NEXT STEPS"); - this.logger.info("=========================================="); - this.logger.info("View updated configuration:"); - this.logger.info(` yarn svm:pool:get-info --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()}`); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Rate Limit Configuration Complete!"); - this.logger.info(`āœ… Rate limits configured for chain ${this.options.remoteChain}`); - this.logger.info(`āœ… Inbound: ${this.options.inboundEnabled ? "Enabled" : "Disabled"}`); - this.logger.info(`āœ… Outbound: ${this.options.outboundEnabled ? "Enabled" : "Disabled"}`); - - } catch (error) { - this.logger.error( - `āŒ Failed to set rate limits: ${error instanceof Error ? error.message : String(error)}` - ); - - if (error instanceof Error && error.stack) { - this.logger.debug("\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new SetRateLimitCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/pool/set-router.ts b/ccip-scripts/svm/pool/set-router.ts deleted file mode 100644 index 25c4f4c9..00000000 --- a/ccip-scripts/svm/pool/set-router.ts +++ /dev/null @@ -1,294 +0,0 @@ -/** - * Token Pool Set Router Script (CLI Framework Version) - * - * This script sets the configured CCIP router for an existing burn-mint token pool. - * Only the pool owner can execute this operation. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenPoolManager } from "../../../ccip-lib/svm/core/client/tokenpools"; -import { TokenPoolType, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { BurnMintTokenPoolInfo } from "../../../ccip-lib/svm/tokenpools/burnmint/accounts"; -import { resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { getKeypairPath, loadKeypair } from "../utils"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for set router operations - */ -const SET_ROUTER_CONFIG = { - minSolRequired: 0.01, - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the set-router command - */ -interface SetRouterOptions extends BaseCommandOptions { - tokenMint: string; - burnMintPoolProgram: string; -} - -/** - * Set Router Command - */ -class SetRouterCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "set-router", - description: "šŸ”„ Token Pool Router Setter\n\nSets the configured CCIP router for an existing burn-mint token pool. Only the pool owner can execute this operation. The router address is automatically loaded from the configuration, ensuring consistency with other CCIP scripts.", - examples: [ - "# Set router for token pool", - "yarn svm:pool:set-router --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh", - "", - "# Set router with debug logging", - "yarn svm:pool:set-router --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --log-level DEBUG" - ], - notes: [ - "Only the pool owner can set a router", - `Minimum ${SET_ROUTER_CONFIG.minSolRequired} SOL required for transaction fees`, - "The pool must already exist before setting a router", - "Router address is automatically loaded from CCIP configuration", - "Router change requires SOL for transaction fees", - "Use 'yarn svm:pool:get-info' to view current pool configuration", - "Verifies the router update after transaction completion", - "No action needed if router is already set correctly" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address of the pool", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - } - ]; - } - - protected async execute(): Promise { - this.logger.info("šŸ”„ CCIP Token Pool Set Router"); - this.logger.info("=========================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet (must be pool owner) - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("=========================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalance = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalance.toFixed(9)} SOL)`); - - if (solBalance < SET_ROUTER_CONFIG.minSolRequired) { - throw new Error( - `Insufficient balance. Need at least ${SET_ROUTER_CONFIG.minSolRequired} SOL for transaction fees.\n` + - `Current balance: ${solBalance.toFixed(9)} SOL\n\n` + - `Request airdrop with:\n` + - `solana airdrop 1 ${walletKeypair.publicKey.toString()} --url devnet` - ); - } - - // Parse and validate addresses - let tokenMint: PublicKey; - let burnMintPoolProgramId: PublicKey; - - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - throw new Error(`Invalid burn-mint pool program ID: ${this.options.burnMintPoolProgram}`); - } - - const newRouter = config.routerProgramId; // Get router from config - - // Display configuration - this.logger.info(""); - this.logger.info("šŸ“‹ ROUTER CONFIGURATION"); - this.logger.info("=========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Burn-Mint Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`CCIP Router (from config): ${newRouter.toString()}`); - - this.logger.debug("Configuration details:"); - this.logger.debug(` Network: ${config.id}`); - this.logger.debug(` Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(` Commitment level: ${config.connection.commitment}`); - this.logger.debug(` Skip preflight: ${this.options.skipPreflight}`); - - try { - // Create token pool manager using SDK - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - { - burnMint: burnMintPoolProgramId, - }, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? LogLevel.INFO } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Check if pool exists - this.logger.info(""); - this.logger.info("šŸ” VERIFYING POOL EXISTENCE"); - this.logger.info("=========================================="); - - const poolExists = await tokenPoolClient.hasPool(tokenMint); - this.logger.debug(`Pool exists: ${poolExists}`); - - if (!poolExists) { - throw new Error( - "Pool does not exist for this token mint.\n" + - "Initialize the pool first using 'yarn svm:pool:initialize'\n" + - `To initialize: yarn svm:pool:initialize --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()}` - ); - } - - this.logger.info("āœ… Pool exists"); - - // Get current pool info to show current router - this.logger.info(""); - this.logger.info("šŸ” CHECKING CURRENT ROUTER"); - this.logger.info("=========================================="); - - try { - const poolInfo = await tokenPoolClient.getPoolInfo(tokenMint) as BurnMintTokenPoolInfo; - const currentRouter = poolInfo.config.config.router.toString(); - this.logger.info(`Current router: ${currentRouter}`); - this.logger.info(`Pool owner: ${poolInfo.config.config.owner.toString()}`); - - if (currentRouter === newRouter.toString()) { - this.logger.info(""); - this.logger.info("āœ… ROUTER ALREADY SET CORRECTLY"); - this.logger.info("=========================================="); - this.logger.info("Router is already set to the configured CCIP router"); - this.logger.info("No changes needed"); - return; - } - - this.logger.debug("Current pool details:", { - poolType: poolInfo.poolType, - owner: poolInfo.config.config.owner.toString(), - version: poolInfo.config.version, - decimals: poolInfo.config.config.decimals, - currentRouter: currentRouter, - }); - } catch (error) { - this.logger.warn(`Could not fetch current pool info: ${error}`); - this.logger.debug("Pool info fetch error:", error); - } - - // Set the new router - this.logger.info(""); - this.logger.info("šŸ”§ SETTING ROUTER"); - this.logger.info("=========================================="); - this.logger.info("Setting router to configured CCIP router..."); - - const signature = await tokenPoolClient.setRouter(tokenMint, { - newRouter: newRouter, - skipPreflight: this.options.skipPreflight, - }); - - // Display results - this.logger.info(""); - this.logger.info("āœ… ROUTER UPDATED SUCCESSFULLY"); - this.logger.info("=========================================="); - this.logger.info(`Transaction Signature: ${signature}`); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("=========================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, signature)}`); - - // Verify the router update - this.logger.info(""); - this.logger.info("šŸ” VERIFYING ROUTER UPDATE"); - this.logger.info("=========================================="); - - try { - const updatedPoolInfo = await tokenPoolClient.getPoolInfo(tokenMint) as BurnMintTokenPoolInfo; - const updatedRouter = updatedPoolInfo.config.config.router.toString(); - - if (updatedRouter === newRouter.toString()) { - this.logger.info("āœ… Router update verified successfully!"); - this.logger.info(`Updated router: ${updatedRouter}`); - - this.logger.debug("Router update verification details:", { - newRouter: updatedRouter, - owner: updatedPoolInfo.config.config.owner.toString(), - }); - } else { - this.logger.warn("Router update completed but verification shows different router"); - this.logger.warn(`Expected: ${newRouter.toString()}`); - this.logger.warn(`Actual: ${updatedRouter}`); - } - } catch (error) { - this.logger.warn(`Router transaction succeeded but verification failed: ${error}`); - this.logger.debug("Verification error details:", error); - this.logger.info("This may be due to network delays - the router should be updated shortly"); - } - - this.logger.info(""); - this.logger.info("šŸ“‹ NEXT STEPS"); - this.logger.info("=========================================="); - this.logger.info("View updated pool details:"); - this.logger.info(` yarn svm:pool:get-info --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()}`); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Router Update Complete!"); - this.logger.info("āœ… Pool router successfully updated to configured CCIP router"); - - } catch (error) { - this.logger.error( - `āŒ Failed to set router: ${error instanceof Error ? error.message : String(error)}` - ); - - if (error instanceof Error && error.stack) { - this.logger.debug("\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new SetRouterCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/pool/transfer-mint-authority-to-multisig.ts b/ccip-scripts/svm/pool/transfer-mint-authority-to-multisig.ts deleted file mode 100644 index 14aaf8ab..00000000 --- a/ccip-scripts/svm/pool/transfer-mint-authority-to-multisig.ts +++ /dev/null @@ -1,297 +0,0 @@ -/** - * Transfer Mint Authority to Multisig Script (CLI Framework Version) - * - * This script transfers the mint authority of a token to a multisig account. - * This is a critical security operation for production deployments that ensures - * the mint authority is controlled by a multisig rather than a single key. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenPoolManager } from "../../../ccip-lib/svm/core/client/tokenpools"; -import { TokenPoolType, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { BurnMintTokenPoolInfo } from "../../../ccip-lib/svm/tokenpools/burnmint/accounts"; -import { resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { getKeypairPath, loadKeypair } from "../utils"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for transfer mint authority operations - */ -const TRANSFER_AUTHORITY_CONFIG = { - minSolRequired: 0.01, - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the transfer-mint-authority-to-multisig command - */ -interface TransferMintAuthorityOptions extends BaseCommandOptions { - tokenMint: string; - burnMintPoolProgram: string; - newMultisigMintAuthority: string; -} - -/** - * Transfer Mint Authority to Multisig Command - */ -class TransferMintAuthorityCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "transfer-mint-authority-to-multisig", - description: "šŸ” Transfer Mint Authority to Multisig\n\nTransfers the mint authority of a token to a multisig account. This is a critical security operation for production deployments that ensures the mint authority is controlled by a multisig rather than a single key.", - examples: [ - "# Transfer mint authority to multisig", - "yarn svm:pool:transfer-mint-authority-to-multisig --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --new-multisig-mint-authority FgS7xNY9uQvFunKEsWH2pSsDTH8SB78bfvgBLKAESzAZ", - "", - "# Transfer with debug logging", - "yarn svm:pool:transfer-mint-authority-to-multisig --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --new-multisig-mint-authority FgS7xNY9uQvFunKEsWH2pSsDTH8SB78bfvgBLKAESzAZ --log-level DEBUG" - ], - notes: [ - "āš ļø CRITICAL SECURITY OPERATION - This transfers mint authority permanently", - "Only callable by the program upgrade authority", - `Minimum ${TRANSFER_AUTHORITY_CONFIG.minSolRequired} SOL required for transaction fees`, - "The new multisig must be a valid Token Program or Token-2022 multisig account", - "The multisig must include the pool signer as one of its signers", - "The multisig must meet specific threshold requirements for security", - "Verify multisig configuration before executing this operation", - "Always test multisig configuration in development first", - "Use 'spl-token display ' to verify the transfer was successful" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address whose authority should be transferred", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - }, - { - name: "new-multisig-mint-authority", - required: true, - type: "string", - description: "PublicKey of the new multisig mint authority account", - example: "FgS7xNY9uQvFunKEsWH2pSsDTH8SB78bfvgBLKAESzAZ" - } - ]; - } - - protected async execute(): Promise { - this.logger.info("šŸ” CCIP Token Pool Transfer Mint Authority to Multisig"); - this.logger.info("=========================================="); - this.logger.warn("āš ļø CRITICAL SECURITY OPERATION - This transfers mint authority permanently"); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet (must be upgrade authority) - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("=========================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalance = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalance.toFixed(9)} SOL)`); - - if (solBalance < TRANSFER_AUTHORITY_CONFIG.minSolRequired) { - throw new Error( - `Insufficient balance. Need at least ${TRANSFER_AUTHORITY_CONFIG.minSolRequired} SOL for transaction fees.\n` + - `Current balance: ${solBalance.toFixed(9)} SOL\n\n` + - `Request airdrop with:\n` + - `solana airdrop 1 ${walletKeypair.publicKey.toString()} --url devnet` - ); - } - - // Parse and validate addresses - let tokenMint: PublicKey; - let burnMintPoolProgramId: PublicKey; - let newMultisigMintAuthority: PublicKey; - - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - throw new Error(`Invalid burn-mint pool program ID: ${this.options.burnMintPoolProgram}`); - } - - try { - newMultisigMintAuthority = new PublicKey(this.options.newMultisigMintAuthority); - } catch { - throw new Error(`Invalid new multisig mint authority address: ${this.options.newMultisigMintAuthority}`); - } - - // Display configuration - this.logger.info(""); - this.logger.info("šŸ“‹ TRANSFER CONFIGURATION"); - this.logger.info("=========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Burn-Mint Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`New Multisig Mint Authority: ${newMultisigMintAuthority.toString()}`); - - this.logger.debug("Configuration details:"); - this.logger.debug(` Network: ${config.id}`); - this.logger.debug(` Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(` Commitment level: ${config.connection.commitment}`); - this.logger.debug(` Skip preflight: ${this.options.skipPreflight}`); - - try { - // Create token pool manager using SDK - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - { - burnMint: burnMintPoolProgramId, - }, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? LogLevel.INFO } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Check if pool exists and get current pool info for verification - this.logger.info(""); - this.logger.info("šŸ” VERIFYING POOL EXISTENCE"); - this.logger.info("=========================================="); - this.logger.info("Checking if pool exists and fetching current pool configuration..."); - - let poolInfo: BurnMintTokenPoolInfo; - try { - poolInfo = await tokenPoolClient.getPoolInfo(tokenMint) as BurnMintTokenPoolInfo; - this.logger.info("āœ… Pool exists"); - this.logger.info(`Pool owner: ${poolInfo.config.config.owner.toString()}`); - - this.logger.debug("Current pool details:", { - poolType: poolInfo.poolType, - owner: poolInfo.config.config.owner.toString(), - version: poolInfo.config.version, - decimals: poolInfo.config.config.decimals, - router: poolInfo.config.config.router.toString(), - }); - } catch (error) { - this.logger.error(""); - this.logger.error("āŒ POOL NOT FOUND"); - this.logger.error("=========================================="); - this.logger.error("Pool does not exist for this token mint"); - this.logger.error("Initialize the pool first using 'yarn svm:pool:initialize'"); - this.logger.debug( - `To initialize: yarn svm:pool:initialize --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()}` - ); - throw new Error("Pool does not exist for this token mint"); - } - - // Verify the new multisig address is valid - this.logger.info(""); - this.logger.info("šŸ” VERIFYING MULTISIG ACCOUNT"); - this.logger.info("=========================================="); - this.logger.info("Verifying new multisig mint authority account..."); - - const multisigAccountInfo = await config.connection.getAccountInfo(newMultisigMintAuthority); - if (!multisigAccountInfo) { - throw new Error( - `Multisig account not found: ${newMultisigMintAuthority.toString()}\n` + - "Ensure the multisig account exists and is properly configured" - ); - } - - this.logger.info("āœ… Multisig account exists"); - this.logger.debug(`Multisig account owner: ${multisigAccountInfo.owner.toString()}`); - - // Transfer mint authority to multisig - this.logger.info(""); - this.logger.info("šŸ”§ TRANSFERRING MINT AUTHORITY"); - this.logger.info("=========================================="); - this.logger.warn("āš ļø CRITICAL SECURITY OPERATION āš ļø"); - this.logger.warn("This will transfer mint authority to a multisig account."); - this.logger.warn("Ensure the multisig is properly configured and includes the pool signer."); - this.logger.info("Executing transfer..."); - - const signature = await tokenPoolClient.transferMintAuthorityToMultisig(tokenMint, { - newMultisigMintAuthority: newMultisigMintAuthority, - skipPreflight: this.options.skipPreflight, - }); - - // Display results - this.logger.info(""); - this.logger.info("āœ… MINT AUTHORITY TRANSFERRED SUCCESSFULLY"); - this.logger.info("=========================================="); - this.logger.info(`Transaction Signature: ${signature}`); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("=========================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, signature)}`); - - // Display summary - this.logger.info(""); - this.logger.info("šŸ” MINT AUTHORITY TRANSFER SUMMARY"); - this.logger.info("=========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`New Multisig Authority: ${newMultisigMintAuthority.toString()}`); - this.logger.info(`Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`Transaction: ${signature}`); - - this.logger.info(""); - this.logger.info("šŸ“‹ NEXT STEPS"); - this.logger.info("=========================================="); - this.logger.info("1. Verify the mint authority transfer:"); - this.logger.info(` spl-token display ${tokenMint.toString()}`); - this.logger.info(""); - this.logger.info("2. Test multisig operations to ensure proper configuration"); - this.logger.info("3. Document multisig signer information and procedures"); - this.logger.info("4. Keep secure backups of all multisig signer keys"); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Mint Authority Transfer Complete!"); - this.logger.info("āœ… Mint authority successfully transferred to multisig"); - this.logger.info("āœ… Enhanced security now in place for mint operations"); - - } catch (error) { - this.logger.error( - `āŒ Failed to transfer mint authority: ${error instanceof Error ? error.message : String(error)}` - ); - - if (error instanceof Error && error.stack) { - this.logger.debug("\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new TransferMintAuthorityCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/pool/transfer-ownership.ts b/ccip-scripts/svm/pool/transfer-ownership.ts deleted file mode 100644 index 83d8fc98..00000000 --- a/ccip-scripts/svm/pool/transfer-ownership.ts +++ /dev/null @@ -1,324 +0,0 @@ -/** - * Pool Transfer Ownership Script (CLI Framework Version) - * - * This script transfers the ownership of a token pool to a new administrator. - * This is step 1 of a two-step ownership transfer process. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenPoolManager } from "../../../ccip-lib/svm/core/client/tokenpools"; -import { TokenPoolType, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { BurnMintTokenPoolInfo } from "../../../ccip-lib/svm/tokenpools/burnmint/accounts"; -import { resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { getKeypairPath, loadKeypair } from "../utils"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for transfer ownership operations - */ -const TRANSFER_OWNERSHIP_CONFIG = { - minSolRequired: 0.01, - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the transfer-ownership command - */ -interface TransferOwnershipOptions extends BaseCommandOptions { - tokenMint: string; - burnMintPoolProgram: string; - newOwner: string; -} - -/** - * Pool Transfer Ownership Command - */ -class TransferOwnershipCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "transfer-ownership", - description: "šŸ‘¤ Pool Ownership Transfer\n\nTransfers the ownership of a token pool to a new administrator. This is step 1 of a two-step ownership transfer process for security.", - examples: [ - "# Transfer pool ownership to new administrator", - "yarn svm:pool:transfer-ownership \\", - " --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \\", - " --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh \\", - " --new-owner 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T", - "", - "# With debug logging", - "yarn svm:pool:transfer-ownership \\", - " --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU \\", - " --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh \\", - " --new-owner 8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T \\", - " --log-level DEBUG" - ], - notes: [ - "āš ļø SECURITY: This is step 1 of a 2-step process - the new owner must accept", - "Only callable by the current pool owner", - `Minimum ${TRANSFER_OWNERSHIP_CONFIG.minSolRequired} SOL required for transaction fees`, - "The new owner must call 'accept-ownership' to complete the transfer", - "Always verify the new owner address before executing", - "Use 'yarn svm:pool:get-info' to check current ownership status", - "Test ownership transfers on devnet before mainnet" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "token-mint", - required: true, - type: "string", - description: "Token mint address identifying the pool", - example: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" - }, - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - }, - { - name: "new-owner", - required: true, - type: "string", - description: "PublicKey of the proposed new pool owner", - example: "8YHhQnHe4fPvKimt3R4KrvaV9K4d4t1f3KjG2J3RzP8T" - } - ]; - } - - protected async execute(): Promise { - this.logger.info("šŸ‘¤ CCIP Token Pool Transfer Ownership"); - this.logger.info("=========================================="); - this.logger.warn("āš ļø Step 1 of 2-step ownership transfer process"); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet (must be current owner) - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Current Owner (Wallet): ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("=========================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalance = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalance.toFixed(9)} SOL)`); - - if (solBalance < TRANSFER_OWNERSHIP_CONFIG.minSolRequired) { - throw new Error( - `Insufficient balance. Need at least ${TRANSFER_OWNERSHIP_CONFIG.minSolRequired} SOL for transaction fees.\n` + - `Current balance: ${solBalance.toFixed(9)} SOL\n\n` + - `Request airdrop with:\n` + - `solana airdrop 1 ${walletKeypair.publicKey.toString()} --url devnet` - ); - } - - // Parse and validate addresses - let tokenMint: PublicKey; - let burnMintPoolProgramId: PublicKey; - let newOwner: PublicKey; - - try { - tokenMint = new PublicKey(this.options.tokenMint); - } catch { - throw new Error(`Invalid token mint address: ${this.options.tokenMint}`); - } - - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - throw new Error(`Invalid burn-mint pool program ID: ${this.options.burnMintPoolProgram}`); - } - - try { - newOwner = new PublicKey(this.options.newOwner); - } catch { - throw new Error(`Invalid new owner address: ${this.options.newOwner}`); - } - - // Display configuration - this.logger.info(""); - this.logger.info("šŸ“‹ OWNERSHIP TRANSFER CONFIGURATION"); - this.logger.info("=========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`Current Owner: ${walletKeypair.publicKey.toString()}`); - this.logger.info(`Proposed New Owner: ${newOwner.toString()}`); - - // Validate addresses - if (walletKeypair.publicKey.equals(newOwner)) { - this.logger.warn("āš ļø Warning: Transferring ownership to the same address (current owner)"); - this.logger.warn("This operation will still work but is typically not necessary"); - } - - this.logger.debug("Configuration details:"); - this.logger.debug(` Network: ${config.id}`); - this.logger.debug(` Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(` Commitment level: ${config.connection.commitment}`); - this.logger.debug(` Skip preflight: ${this.options.skipPreflight}`); - - try { - // Create token pool manager using SDK - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - { - burnMint: burnMintPoolProgramId, - }, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? LogLevel.INFO } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Check if pool exists and get current pool info for verification - this.logger.info(""); - this.logger.info("šŸ” VERIFYING POOL OWNERSHIP"); - this.logger.info("=========================================="); - this.logger.info("Checking pool exists and verifying current ownership..."); - - let poolInfo: BurnMintTokenPoolInfo; - try { - poolInfo = await tokenPoolClient.getPoolInfo(tokenMint) as BurnMintTokenPoolInfo; - this.logger.info("āœ… Pool exists"); - this.logger.info(`Current Pool Owner: ${poolInfo.config.config.owner.toString()}`); - this.logger.info(`Current Proposed Owner: ${poolInfo.config.config.proposedOwner?.toString() || 'none'}`); - - this.logger.debug("Current pool details:", { - poolType: poolInfo.poolType, - owner: poolInfo.config.config.owner.toString(), - proposedOwner: poolInfo.config.config.proposedOwner?.toString() || 'none', - version: poolInfo.config.version, - decimals: poolInfo.config.config.decimals, - router: poolInfo.config.config.router.toString(), - }); - } catch (error) { - this.logger.error(""); - this.logger.error("āŒ POOL NOT FOUND"); - this.logger.error("=========================================="); - this.logger.error("Pool does not exist for this token mint"); - this.logger.error("Initialize the pool first using 'yarn svm:pool:initialize'"); - this.logger.debug( - `To initialize: yarn svm:pool:initialize --token-mint ${tokenMint.toString()} --burn-mint-pool-program ${burnMintPoolProgramId.toString()}` - ); - throw new Error("Pool does not exist for this token mint"); - } - - // Verify current wallet is the owner - if (!poolInfo.config.config.owner.equals(walletKeypair.publicKey)) { - throw new Error( - `Access denied: You are not the current owner of this pool.\n` + - `Current Owner: ${poolInfo.config.config.owner.toString()}\n` + - `Your Wallet: ${walletKeypair.publicKey.toString()}\n\n` + - `Only the current owner can transfer ownership.` - ); - } - - // Check if there's already a pending ownership transfer - if (poolInfo.config.config.proposedOwner && !poolInfo.config.config.proposedOwner.equals(PublicKey.default)) { - if (poolInfo.config.config.proposedOwner.equals(newOwner)) { - this.logger.info(""); - this.logger.info("ā„¹ļø OWNERSHIP ALREADY PROPOSED"); - this.logger.info("=========================================="); - this.logger.info(`${newOwner.toString()} is already the proposed owner.`); - this.logger.info("No action needed - they can accept ownership using 'yarn svm:pool:accept-ownership'"); - return; - } else { - this.logger.warn(""); - this.logger.warn("āš ļø EXISTING PENDING TRANSFER"); - this.logger.warn("=========================================="); - this.logger.warn(`There is already a pending ownership transfer to: ${poolInfo.config.config.proposedOwner.toString()}`); - this.logger.warn("This operation will replace the pending transfer."); - } - } - - // Transfer ownership - this.logger.info(""); - this.logger.info("šŸ”§ TRANSFERRING OWNERSHIP"); - this.logger.info("=========================================="); - this.logger.warn("āš ļø PROPOSING NEW OWNER"); - this.logger.info("Executing ownership transfer proposal..."); - - const signature = await tokenPoolClient.transferAdminRole(tokenMint, { - newAdmin: newOwner, - skipPreflight: this.options.skipPreflight, - }); - - // Display results - this.logger.info(""); - this.logger.info("āœ… OWNERSHIP TRANSFER PROPOSED SUCCESSFULLY"); - this.logger.info("=========================================="); - this.logger.info(`Transaction Signature: ${signature}`); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("=========================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, signature)}`); - - // Display summary - this.logger.info(""); - this.logger.info("šŸ‘¤ OWNERSHIP TRANSFER SUMMARY"); - this.logger.info("=========================================="); - this.logger.info(`Token Mint: ${tokenMint.toString()}`); - this.logger.info(`Current Owner: ${walletKeypair.publicKey.toString()}`); - this.logger.info(`Proposed New Owner: ${newOwner.toString()}`); - this.logger.info(`Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`Transaction: ${signature}`); - - this.logger.info(""); - this.logger.info("šŸ“‹ NEXT STEPS"); - this.logger.info("=========================================="); - this.logger.info("1. The proposed owner must accept ownership:"); - this.logger.info(` yarn svm:pool:accept-ownership \\`); - this.logger.info(` --token-mint ${tokenMint.toString()} \\`); - this.logger.info(` --burn-mint-pool-program ${burnMintPoolProgramId.toString()}`); - this.logger.info(` (Must be run by: ${newOwner.toString()})`); - this.logger.info(""); - this.logger.info("2. Verify the ownership transfer:"); - this.logger.info(` yarn svm:pool:get-info --token-mint ${tokenMint.toString()}`); - this.logger.info(""); - this.logger.info("3. Until accepted, you remain the owner and can cancel by proposing yourself"); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Ownership Transfer Proposal Complete!"); - this.logger.info("āœ… Ownership transfer successfully proposed"); - this.logger.info("ā³ Waiting for new owner to accept the transfer"); - - } catch (error) { - this.logger.error( - `āŒ Failed to transfer ownership: ${error instanceof Error ? error.message : String(error)}` - ); - - if (error instanceof Error && error.stack) { - this.logger.debug("\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new TransferOwnershipCommand(); -command.run().catch((error) => { - process.exit(1); -}); diff --git a/ccip-scripts/svm/pool/update-self-served-allowed.ts b/ccip-scripts/svm/pool/update-self-served-allowed.ts deleted file mode 100644 index 834768fd..00000000 --- a/ccip-scripts/svm/pool/update-self-served-allowed.ts +++ /dev/null @@ -1,300 +0,0 @@ -/** - * Update Self-Served Allowed Global Config Script (CLI Framework Version) - * - * This script updates the global self-served allowed flag for a burn-mint token pool program. - * This flag controls whether pool creators can initialize pools without being the program upgrade authority. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { TokenPoolManager } from "../../../ccip-lib/svm/core/client/tokenpools"; -import { TokenPoolType, LogLevel, createLogger } from "../../../ccip-lib/svm"; -import { resolveNetworkConfig, getExplorerUrl } from "../../config"; -import { getKeypairPath, loadKeypair } from "../utils"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for update self-served allowed operations - */ -const UPDATE_SELF_SERVED_CONFIG = { - minSolRequired: 0.01, - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the update-self-served-allowed command - */ -interface UpdateSelfServedAllowedOptions extends BaseCommandOptions { - burnMintPoolProgram: string; - selfServedAllowed: boolean; -} - -/** - * Update Self-Served Allowed Command - */ -class UpdateSelfServedAllowedCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "update-self-served-allowed", - description: "šŸ”§ Update Self-Served Pool Creation\n\nUpdates the global self-served allowed flag for a burn-mint token pool program. This flag controls whether pool creators can initialize pools without being the program upgrade authority.", - examples: [ - "# Allow mint authority holders to create pools", - "yarn svm:pool:update-self-served-allowed --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --self-served-allowed true", - "", - "# Restrict pool creation to upgrade authority only", - "yarn svm:pool:update-self-served-allowed --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --self-served-allowed false", - "", - "# With debug logging", - "yarn svm:pool:update-self-served-allowed --burn-mint-pool-program 2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh --self-served-allowed true --log-level DEBUG" - ], - notes: [ - "āš ļø This must be run by the program upgrade authority", - `Minimum ${UPDATE_SELF_SERVED_CONFIG.minSolRequired} SOL required for transaction fees`, - "Setting to 'true' allows anyone with mint authority to create pools", - "Setting to 'false' restricts pool creation to upgrade authority only", - "This affects ALL future pool creations across the program", - "Existing pools are not affected by this change", - "Consider security implications before enabling self-served mode", - "Verifies the update after transaction completes" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "burn-mint-pool-program", - required: true, - type: "string", - description: "Burn-mint token pool program ID", - example: "2YzPLhHBpRMwxCN7yLpHJGHg2AXBzQ5VPuKt51BDKxqh" - }, - { - name: "self-served-allowed", - required: true, - type: "boolean", - description: "Allow self-served pool creation (true/false)", - example: "true" - } - ]; - } - - protected async execute(): Promise { - this.logger.info("šŸ”§ CCIP Token Pool Update Self-Served Allowed Flag"); - this.logger.info("=========================================="); - this.logger.warn("āš ļø This must be run by the program upgrade authority"); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet (must be upgrade authority) - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - this.logger.warn("šŸ”‘ Ensure this wallet is the program upgrade authority for the token pool program"); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("=========================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalance = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalance.toFixed(9)} SOL)`); - - if (solBalance < UPDATE_SELF_SERVED_CONFIG.minSolRequired) { - throw new Error( - `Insufficient balance. Need at least ${UPDATE_SELF_SERVED_CONFIG.minSolRequired} SOL for transaction fees.\n` + - `Current balance: ${solBalance.toFixed(9)} SOL\n\n` + - `Request airdrop with:\n` + - `solana airdrop 1 ${walletKeypair.publicKey.toString()} --url devnet` - ); - } - - // Parse and validate burn-mint pool program ID - let burnMintPoolProgramId: PublicKey; - try { - burnMintPoolProgramId = new PublicKey(this.options.burnMintPoolProgram); - } catch { - throw new Error(`Invalid burn-mint pool program ID: ${this.options.burnMintPoolProgram}`); - } - - const selfServedAllowed = this.options.selfServedAllowed; - - // Display configuration - this.logger.info(""); - this.logger.info("šŸ“‹ UPDATE CONFIGURATION"); - this.logger.info("=========================================="); - this.logger.info(`Burn-Mint Pool Program: ${burnMintPoolProgramId.toString()}`); - this.logger.info(`New Self-Served Allowed: ${selfServedAllowed}`); - - if (selfServedAllowed) { - this.logger.info("šŸ”“ Pool creation will be allowed for mint authority holders"); - } else { - this.logger.info("šŸ”’ Pool creation will be restricted to program upgrade authority only"); - } - - this.logger.debug("Update self-served allowed details:"); - this.logger.debug(` Network: ${config.id}`); - this.logger.debug(` Connection endpoint: ${config.connection.rpcEndpoint}`); - this.logger.debug(` Commitment level: ${config.connection.commitment}`); - this.logger.debug(` Authority: ${walletKeypair.publicKey.toString()}`); - this.logger.debug(` Skip preflight: ${this.options.skipPreflight}`); - - try { - // Create token pool manager using SDK - const tokenPoolManager = TokenPoolManager.create( - config.connection, - walletKeypair, - { - burnMint: burnMintPoolProgramId, - }, - { - ccipRouterProgramId: config.routerProgramId.toString(), - feeQuoterProgramId: config.feeQuoterProgramId.toString(), - rmnRemoteProgramId: config.rmnRemoteProgramId.toString(), - linkTokenMint: config.linkTokenMint.toString(), - receiverProgramId: config.receiverProgramId.toString(), - }, - { logLevel: this.options.logLevel ?? LogLevel.INFO } - ); - - const tokenPoolClient = tokenPoolManager.getTokenPoolClient(TokenPoolType.BURN_MINT); - - // Get current global config to show current value - this.logger.info(""); - this.logger.info("šŸ” CURRENT CONFIGURATION"); - this.logger.info("=========================================="); - try { - const globalConfig = await tokenPoolClient.getGlobalConfigInfo(); - const currentValue = globalConfig.config.self_served_allowed; - this.logger.info(`Current self-served allowed: ${currentValue}`); - - if (currentValue === selfServedAllowed) { - this.logger.info(""); - this.logger.info("āœ… ALREADY UP TO DATE"); - this.logger.info("=========================================="); - this.logger.info("Self-served allowed flag is already set to the desired value"); - this.logger.info("No changes needed"); - return; - } - - this.logger.debug("Current global config details:", { - version: globalConfig.config.version, - selfServedAllowed: currentValue, - router: globalConfig.config.router.toString(), - rmnRemote: globalConfig.config.rmn_remote.toString(), - }); - } catch (error) { - this.logger.warn(`Could not fetch current global config: ${error}`); - this.logger.debug("Global config fetch error:", error); - this.logger.info("Proceeding with update..."); - } - - // Update the self-served allowed flag - this.logger.info(""); - this.logger.info("šŸ”§ UPDATING SELF-SERVED ALLOWED FLAG"); - this.logger.info("=========================================="); - this.logger.info("Updating the program-wide configuration..."); - - this.logger.debug("Calling SDK updateSelfServedAllowed method..."); - this.logger.debug(`Transaction options: skipPreflight=${this.options.skipPreflight}`); - - const signature = await tokenPoolClient.updateSelfServedAllowed({ - selfServedAllowed: selfServedAllowed, - skipPreflight: this.options.skipPreflight, - }); - - this.logger.debug(`Transaction completed with signature: ${signature}`); - - // Display results - this.logger.info(""); - this.logger.info("āœ… SELF-SERVED FLAG UPDATED SUCCESSFULLY"); - this.logger.info("=========================================="); - this.logger.info(`Transaction Signature: ${signature}`); - - // Display explorer URL - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("=========================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, signature)}`); - - // Verify the update - this.logger.info(""); - this.logger.info("šŸ” VERIFYING UPDATE"); - this.logger.info("=========================================="); - - try { - const updatedGlobalConfig = await tokenPoolClient.getGlobalConfigInfo(); - const updatedValue = updatedGlobalConfig.config.self_served_allowed; - - if (updatedValue === selfServedAllowed) { - this.logger.info("āœ… Update verified successfully!"); - this.logger.info(`Updated value: ${updatedValue}`); - - this.logger.debug("Update verification details:", { - newValue: updatedValue, - version: updatedGlobalConfig.config.version, - }); - } else { - this.logger.warn("Update completed but verification shows different value"); - this.logger.warn(`Expected: ${selfServedAllowed}`); - this.logger.warn(`Actual: ${updatedValue}`); - } - } catch (error) { - this.logger.warn(`Update transaction succeeded but verification failed: ${error}`); - this.logger.debug("Verification error details:", error); - this.logger.info("This may be due to network delays - the flag should be updated shortly"); - } - - // Display impact summary - this.logger.info(""); - this.logger.info("šŸ“‹ UPDATE IMPACT"); - this.logger.info("=========================================="); - - if (selfServedAllowed) { - this.logger.info("Effect: Token holders with mint authority can now create pools"); - this.logger.info("Security: Ensure only trusted token mints use this feature"); - } else { - this.logger.info("Effect: Only program upgrade authority can create new pools"); - this.logger.info("Security: Maximum control over pool creation"); - } - - this.logger.info(""); - this.logger.info("šŸŽ‰ Self-Served Flag Update Complete!"); - this.logger.info("āœ… Global configuration has been updated"); - - } catch (error) { - // Handle specific error cases - if (error instanceof Error) { - if (error.message.includes("Unauthorized")) { - this.logger.error(""); - this.logger.error("🚨 AUTHORIZATION ERROR"); - this.logger.error("=========================================="); - this.logger.error("The wallet is not the program upgrade authority for this program."); - this.logger.error("Only the program upgrade authority can update global config settings."); - throw error; - } - } - - this.logger.error( - `āŒ Failed to update self-served allowed flag: ${error instanceof Error ? error.message : String(error)}` - ); - - if (error instanceof Error && error.stack) { - this.logger.debug("\nError stack:"); - this.logger.debug(error.stack); - } - - throw error; - } - } -} - -// Create and run the command -const command = new UpdateSelfServedAllowedCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/receiver/get-latest-message.ts b/ccip-scripts/svm/receiver/get-latest-message.ts index e8dc838d..3526056a 100644 --- a/ccip-scripts/svm/receiver/get-latest-message.ts +++ b/ccip-scripts/svm/receiver/get-latest-message.ts @@ -249,9 +249,9 @@ class GetLatestMessageCommand extends CCIPCommand { this.logger.info("1. Initialize the receiver program:"); this.logger.info(" yarn svm:receiver:initialize"); this.logger.info("2. Send a message to trigger storage creation:"); - this.logger.info(" yarn ccip:send"); - this.logger.info(" yarn ccip:message"); - this.logger.info(" yarn ccip:data-tokens"); + this.logger.info(" yarn svm:token-transfer"); + this.logger.info(" yarn svm:arbitrary-messaging"); + this.logger.info(" yarn svm:data-and-tokens"); return; } @@ -278,9 +278,9 @@ class GetLatestMessageCommand extends CCIPCommand { this.logger.info(""); this.logger.info("šŸ“‹ NEXT STEPS:"); this.logger.info("Send a message using one of these commands:"); - this.logger.info("• yarn ccip:send (token transfer)"); - this.logger.info("• yarn ccip:message (arbitrary messaging)"); - this.logger.info("• yarn ccip:data-tokens (data + tokens)"); + this.logger.info("• yarn svm:token-transfer (token transfer)"); + this.logger.info("• yarn svm:arbitrary-messaging (arbitrary messaging)"); + this.logger.info("• yarn svm:data-and-tokens (data + tokens)"); return; } diff --git a/ccip-scripts/svm/receiver/initialize.ts b/ccip-scripts/svm/receiver/initialize.ts index fab12dc9..91bb7b90 100644 --- a/ccip-scripts/svm/receiver/initialize.ts +++ b/ccip-scripts/svm/receiver/initialize.ts @@ -295,9 +295,9 @@ class InitializeCommand extends CCIPCommand { this.logger.info("2. Test message reception:"); this.logger.info(" yarn svm:receiver:get-latest-message"); this.logger.info("3. Send messages using router scripts:"); - this.logger.info(" yarn ccip:send"); - this.logger.info(" yarn ccip:message"); - this.logger.info(" yarn ccip:data-tokens"); + this.logger.info(" yarn svm:token-transfer"); + this.logger.info(" yarn svm:arbitrary-messaging"); + this.logger.info(" yarn svm:data-and-tokens"); this.logger.info(""); this.logger.info("šŸŽ‰ Initialization Complete!"); diff --git a/ccip-scripts/svm/router/1_token-transfer.ts b/ccip-scripts/svm/router/1_token-transfer.ts index af5bbe86..f4e019d3 100644 --- a/ccip-scripts/svm/router/1_token-transfer.ts +++ b/ccip-scripts/svm/router/1_token-transfer.ts @@ -76,16 +76,16 @@ class TokenTransferCommand extends CCIPCommand { "šŸš€ CCIP Token Transfer\\\\n\\\\nSends tokens from Solana to Ethereum using Chainlink CCIP (Cross-Chain Interoperability Protocol). Demonstrates cross-chain token transfers with comprehensive fee calculation and transaction monitoring.", examples: [ "# Basic token transfer (uses BnM token from config)", - "yarn ccip:send", + "yarn svm:token-transfer", "", "# Transfer with LINK token as fee payment", - "yarn ccip:send --fee-token link", + "yarn svm:token-transfer --fee-token link", "", "# Transfer custom token with custom amount", - "yarn ccip:send --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --token-amount 50000000", + "yarn svm:token-transfer --token-mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU --token-amount 50000000", "", "# Transfer to custom receiver address", - "yarn ccip:send --receiver-address 0x1234567890123456789012345678901234567890 --token-amount 25000000", + "yarn svm:token-transfer --receiver-address 0x1234567890123456789012345678901234567890 --token-amount 25000000", ], notes: [ `Default destination: ${TOKEN_TRANSFER_CONFIG.defaultDestinationChain}`, diff --git a/ccip-scripts/svm/router/2_arbitrary-messaging.ts b/ccip-scripts/svm/router/2_arbitrary-messaging.ts index d83926bc..5371c522 100644 --- a/ccip-scripts/svm/router/2_arbitrary-messaging.ts +++ b/ccip-scripts/svm/router/2_arbitrary-messaging.ts @@ -77,16 +77,16 @@ class ArbitraryMessagingCommand extends CCIPCommand { "šŸ“Ø CCIP Arbitrary Messaging\\\\n\\\\nSends arbitrary messages from Solana to Ethereum using Chainlink CCIP (Cross-Chain Interoperability Protocol). Demonstrates cross-chain messaging with custom data payloads.", examples: [ "# Basic message sending (uses default 'Hello World')", - "yarn ccip:message", + "yarn svm:arbitrary-messaging", "", "# Send custom message with LINK fee token", - 'yarn ccip:message --message \\"Custom cross-chain message\\" --fee-token link', + 'yarn svm:arbitrary-messaging --message \\"Custom cross-chain message\\" --fee-token link', "", "# Send message with custom gas limit", - 'yarn ccip:message --message \\"High gas message\\" --gas-limit 500000', + 'yarn svm:arbitrary-messaging --message \\"High gas message\\" --gas-limit 500000', "", "# Send message to custom receiver address", - 'yarn ccip:message --receiver-address 0x1234567890123456789012345678901234567890 --message \\"Hello custom receiver!\\"', + 'yarn svm:arbitrary-messaging --receiver-address 0x1234567890123456789012345678901234567890 --message \\"Hello custom receiver!\\"', ], notes: [ `Default destination: ${ARBITRARY_MESSAGING_CONFIG.defaultDestinationChain}`, diff --git a/ccip-scripts/svm/router/get-ccip-fee.ts b/ccip-scripts/svm/router/get-ccip-fee.ts index d8421bfb..c10ac313 100644 --- a/ccip-scripts/svm/router/get-ccip-fee.ts +++ b/ccip-scripts/svm/router/get-ccip-fee.ts @@ -74,16 +74,16 @@ class GetCcipFeeCommand extends CCIPCommand { description: "šŸ’° CCIP Fee Calculator\\n\\nEstimates fees for CCIP cross-chain transactions without actually sending any messages or tokens. Useful for planning and budgeting cross-chain operations.", examples: [ "# Basic fee calculation (uses all defaults)", - "yarn ccip:fee", + "yarn svm:fee", "", "# Calculate fee with LINK token as fee payment", - "yarn ccip:fee --fee-token link", + "yarn svm:fee --fee-token link", "", "# Calculate fee for custom token amount", - "yarn ccip:fee --token-amount 50000000 --gas-limit 300000", + "yarn svm:fee --token-amount 50000000 --gas-limit 300000", "", "# Calculate fee for custom receiver and message", - "yarn ccip:fee --receiver-address 0x1234567890123456789012345678901234567890 --message-data \"Custom message data\"" + "yarn svm:fee --receiver-address 0x1234567890123456789012345678901234567890 --message-data \"Custom message data\"" ], notes: [ `Default destination: ${FEE_CALC_CONFIG.defaultDestinationChain}`, diff --git a/ccip-scripts/svm/token/create-token-2022.ts b/ccip-scripts/svm/token/create-token-2022.ts deleted file mode 100644 index 41bb57b4..00000000 --- a/ccip-scripts/svm/token/create-token-2022.ts +++ /dev/null @@ -1,296 +0,0 @@ -/** - * SPL Token-2022 Creation Script (CLI Framework Version) - * - * This script creates a new SPL Token-2022 token with Metaplex metadata support. - * Token-2022 is the newer token standard that provides enhanced functionality - * including native metadata support. - */ - -import { LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { - TokenCreationUtils, - Token2022Config, - TokenProgram, - LogLevel, - createLogger, -} from "../../../ccip-lib/svm"; -import { loadKeypair, getKeypairPath } from "../utils"; -import { - ChainId, - getCCIPSVMConfig, - resolveNetworkConfig, - getExplorerUrl, - getExplorerAddressUrl, -} from "../../config"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for token creation operations - */ -const TOKEN_CREATION_CONFIG = { - defaultName: "AEM", - defaultSymbol: "CCIP-AEM", - defaultDecimals: 9, - defaultSellerFeeBasisPoints: 0, - defaultInitialSupply: "1000000000000", - defaultLogLevel: LogLevel.INFO, - minSolRequired: 0.01, - defaultMetadataUri: "https://cyan-pleasant-anteater-613.mypinata.cloud/ipfs/bafkreieirlwjqbtzniqsgcjebzexlcspcmvd4woh3ajvf2p4fuivkenw6i", -}; - -/** - * Options specific to the create-token-2022 command - */ -interface CreateToken2022Options extends BaseCommandOptions { - name?: string; - symbol?: string; - uri?: string; - decimals?: number; - initialSupply?: string; - feeBasisPoints?: number; -} - -/** - * SPL Token-2022 Creation Command - */ -class CreateToken2022Command extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "create-token-2022", - description: "šŸŖ™ SPL Token-2022 Creator with Metadata\n\nCreates a new SPL Token-2022 token with Metaplex metadata support. Token-2022 provides enhanced functionality including native metadata support.", - examples: [ - "# Minimal token creation (uses all defaults)", - "yarn svm:token:create", - "", - "# Token with custom name and symbol", - "yarn svm:token:create --name \"My Token\" --symbol \"MTK\"", - "", - "# Token with custom metadata and supply", - "yarn svm:token:create --name \"My Token\" --symbol \"MTK\" --uri \"https://example.com/metadata.json\" --initial-supply 5000000", - "", - "# Token with all custom parameters", - "yarn svm:token:create --name \"My Token\" --symbol \"MTK\" --decimals 6 --initial-supply 1000000 --fee-basis-points 250" - ], - notes: [ - `Default name: "${TOKEN_CREATION_CONFIG.defaultName}", symbol: "${TOKEN_CREATION_CONFIG.defaultSymbol}"`, - `Default decimals: ${TOKEN_CREATION_CONFIG.defaultDecimals}, initial supply: ${TOKEN_CREATION_CONFIG.defaultInitialSupply}`, - "Uses sample metadata URI by default - override with --uri for production", - "Token name max 32 characters, symbol max 10 characters", - "Decimals range: 0-9, fee basis points range: 0-10000", - "Minimum 0.01 SOL required for transaction fees", - "Creates both mint account and initial token supply" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "name", - required: false, - type: "string", - description: `Token name (max 32 characters, default: "${TOKEN_CREATION_CONFIG.defaultName}")`, - example: "My Token" - }, - { - name: "symbol", - required: false, - type: "string", - description: `Token symbol (max 10 characters, default: "${TOKEN_CREATION_CONFIG.defaultSymbol}")`, - example: "MTK" - }, - { - name: "uri", - required: false, - type: "string", - description: "Metadata URI (uses sample URI if not provided - override recommended for production)", - example: "https://example.com/metadata.json" - }, - { - name: "decimals", - required: false, - type: "number", - description: `Number of decimal places (0-9, default: ${TOKEN_CREATION_CONFIG.defaultDecimals})`, - example: "6" - }, - { - name: "initial-supply", - required: false, - type: "string", - description: `Initial token supply to mint (default: ${TOKEN_CREATION_CONFIG.defaultInitialSupply})`, - example: "1000000" - }, - { - name: "fee-basis-points", - required: false, - type: "number", - description: `Seller fee basis points (0-10000, default: ${TOKEN_CREATION_CONFIG.defaultSellerFeeBasisPoints})`, - example: "250" - } - ]; - } - - /** - * Validate token creation configuration - */ - private validateConfig(): void { - const errors: string[] = []; - - if (this.options.name && this.options.name.length > 32) { - errors.push("Token name must be 32 characters or less"); - } - - if (this.options.symbol && this.options.symbol.length > 10) { - errors.push("Token symbol must be 10 characters or less"); - } - - if (this.options.decimals !== undefined && - (this.options.decimals < 0 || this.options.decimals > 9)) { - errors.push("Decimals must be between 0 and 9"); - } - - if (this.options.feeBasisPoints !== undefined && - (this.options.feeBasisPoints < 0 || this.options.feeBasisPoints > 10000)) { - errors.push("Fee basis points must be between 0 and 10000"); - } - - if (errors.length > 0) { - throw new Error( - `Configuration validation failed:\n${errors.map((e) => ` - ${e}`).join("\n")}` - ); - } - } - - /** - * Create token configuration from command line options - */ - private createTokenConfig(): Token2022Config { - const name = this.options.name || TOKEN_CREATION_CONFIG.defaultName; - const symbol = this.options.symbol || TOKEN_CREATION_CONFIG.defaultSymbol; - const uri = this.options.uri || TOKEN_CREATION_CONFIG.defaultMetadataUri; - - const initialSupply = this.options.initialSupply - ? BigInt(this.options.initialSupply) - : BigInt(TOKEN_CREATION_CONFIG.defaultInitialSupply); - - return { - name: name, - symbol: symbol, - uri: uri, - decimals: this.options.decimals ?? TOKEN_CREATION_CONFIG.defaultDecimals, - initialSupply: initialSupply, - sellerFeeBasisPoints: this.options.feeBasisPoints ?? TOKEN_CREATION_CONFIG.defaultSellerFeeBasisPoints, - tokenProgram: TokenProgram.TOKEN_2022, - }; - } - - protected async execute(): Promise { - this.logger.info("SPL Token-2022 Creator with Metadata"); - this.logger.info("======================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("======================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalanceDisplay = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalanceDisplay.toFixed(9)} SOL)`); - - if (solBalanceDisplay < TOKEN_CREATION_CONFIG.minSolRequired) { - throw new Error( - `Insufficient SOL balance. Need at least ${TOKEN_CREATION_CONFIG.minSolRequired} SOL for transaction fees. ` + - `Current balance: ${solBalanceDisplay.toFixed(9)} SOL` - ); - } - - // Validate configuration - this.validateConfig(); - - // Create token configuration - const tokenConfig = this.createTokenConfig(); - - this.logger.info(""); - this.logger.info("āš™ļø TOKEN CONFIGURATION"); - this.logger.info("======================================="); - this.logger.info(`Name: ${tokenConfig.name}${!this.options.name ? " (default)" : ""}`); - this.logger.info(`Symbol: ${tokenConfig.symbol}${!this.options.symbol ? " (default)" : ""}`); - this.logger.info(`Decimals: ${tokenConfig.decimals}${this.options.decimals === undefined ? " (default)" : ""}`); - this.logger.info(`URI: ${tokenConfig.uri}${!this.options.uri ? " (default)" : ""}`); - this.logger.info(`Initial Supply: ${tokenConfig.initialSupply?.toString() || "0"}${!this.options.initialSupply ? " (default)" : ""}`); - this.logger.info(`Seller Fee Basis Points: ${tokenConfig.sellerFeeBasisPoints || 0}${this.options.feeBasisPoints === undefined ? " (default)" : ""}`); - - // Warn if using defaults - if (!this.options.name || !this.options.symbol) { - this.logger.warn( - "\nāš ļø Using default token name/symbol. Consider providing your own with --name and --symbol for production tokens." - ); - } - if (!this.options.uri) { - this.logger.warn( - "\nāš ļø Using default metadata URI. Consider providing your own with --uri for production tokens." - ); - } - - // Initialize TokenCreationUtils - const tokenUtils = new TokenCreationUtils( - config.connection, - walletKeypair, - this.options.logLevel ?? TOKEN_CREATION_CONFIG.defaultLogLevel - ); - - // Create the token - this.logger.info(""); - this.logger.info("šŸ­ CREATING TOKEN"); - this.logger.info("======================================="); - const result = await tokenUtils.createTokenWithMetadata(tokenConfig, { - skipPreflight: this.options.skipPreflight, - commitment: "finalized", - }); - - // Display results - this.logger.info(""); - this.logger.info("āœ… TOKEN CREATED SUCCESSFULLY"); - this.logger.info("======================================="); - this.logger.info(`Mint Address: ${result.mint.toString()}`); - this.logger.info(`Transaction Signature: ${result.signature}`); - if (result.tokenAccount) { - this.logger.info(`Token Account: ${result.tokenAccount.toString()}`); - } - - // Display explorer URLs - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("======================================="); - this.logger.info(`Mint: ${getExplorerAddressUrl(config.id, result.mint.toString())}`); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, result.signature)}`); - if (result.tokenAccount) { - this.logger.info( - `Token Account: ${getExplorerAddressUrl(config.id, result.tokenAccount.toString())}` - ); - } - - this.logger.info(""); - this.logger.info("šŸŽ‰ Token creation completed successfully!"); - this.logger.info(""); - this.logger.info("šŸ’” You can now use this mint address for token operations:"); - this.logger.info(` Mint Address: ${result.mint.toString()}`); - } -} - -// Create and run the command -const command = new CreateToken2022Command(); -command.run().catch((error) => { - process.exit(1); -}); diff --git a/ccip-scripts/svm/token/create-token-metaplex.ts b/ccip-scripts/svm/token/create-token-metaplex.ts deleted file mode 100644 index 18781600..00000000 --- a/ccip-scripts/svm/token/create-token-metaplex.ts +++ /dev/null @@ -1,299 +0,0 @@ -/** - * SPL Token Creation Script with Metaplex Metadata (CLI Framework Version) - * - * This script creates a new SPL Token (legacy token program) with Metaplex metadata support. - * This is the traditional SPL Token program, as opposed to Token-2022. - */ - -import { LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { - TokenCreationUtils, - SplTokenConfig, - TokenProgram, - LogLevel, - createLogger, -} from "../../../ccip-lib/svm"; -import { loadKeypair, getKeypairPath } from "../utils"; -import { - ChainId, - getCCIPSVMConfig, - resolveNetworkConfig, - getExplorerUrl, - getExplorerAddressUrl, -} from "../../config"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for SPL token creation operations - */ -const TOKEN_CREATION_CONFIG = { - defaultName: "AEM", - defaultSymbol: "CCIP-AEM", - defaultDecimals: 9, - defaultSellerFeeBasisPoints: 0, - defaultInitialSupply: "1000000000000", - defaultLogLevel: LogLevel.INFO, - minSolRequired: 0.01, - defaultMetadataUri: "https://cyan-pleasant-anteater-613.mypinata.cloud/ipfs/bafkreieirlwjqbtzniqsgcjebzexlcspcmvd4woh3ajvf2p4fuivkenw6i", -}; - -/** - * Options specific to the create-token-metaplex command - */ -interface CreateTokenMetaplexOptions extends BaseCommandOptions { - name?: string; - symbol?: string; - uri?: string; - decimals?: number; - initialSupply?: string; - feeBasisPoints?: number; -} - -/** - * SPL Token Creation Command with Metaplex Metadata - */ -class CreateTokenMetaplexCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "create-token-metaplex", - description: "šŸŖ™ SPL Token Creator with Metaplex Metadata\\n\\nCreates a new SPL Token (legacy token program) with Metaplex metadata support. This uses the traditional SPL Token program, not Token-2022.", - examples: [ - "# Minimal token creation (uses all defaults)", - "yarn svm:token:create-spl", - "", - "# Token with custom name and symbol", - "yarn svm:token:create-spl --name \"My Token\" --symbol \"MTK\"", - "", - "# Token with custom metadata and supply", - "yarn svm:token:create-spl --name \"My Token\" --symbol \"MTK\" --uri \"https://example.com/metadata.json\" --initial-supply 5000000", - "", - "# Token with all custom parameters", - "yarn svm:token:create-spl --name \"My Token\" --symbol \"MTK\" --decimals 6 --initial-supply 1000000 --fee-basis-points 250" - ], - notes: [ - `Default name: "${TOKEN_CREATION_CONFIG.defaultName}", symbol: "${TOKEN_CREATION_CONFIG.defaultSymbol}"`, - `Default decimals: ${TOKEN_CREATION_CONFIG.defaultDecimals}, initial supply: ${TOKEN_CREATION_CONFIG.defaultInitialSupply}`, - "Uses sample metadata URI by default - override with --uri for production", - "Token name max 32 characters, symbol max 10 characters", - "Decimals range: 0-9, fee basis points range: 0-10000", - "Minimum 0.01 SOL required for transaction fees", - "Creates legacy SPL Token (not Token-2022)", - "Creates both mint account and initial token supply" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "name", - required: false, - type: "string", - description: `Token name (max 32 characters, default: "${TOKEN_CREATION_CONFIG.defaultName}")`, - example: "My Token" - }, - { - name: "symbol", - required: false, - type: "string", - description: `Token symbol (max 10 characters, default: "${TOKEN_CREATION_CONFIG.defaultSymbol}")`, - example: "MTK" - }, - { - name: "uri", - required: false, - type: "string", - description: "Metadata URI (uses sample URI if not provided - override recommended for production)", - example: "https://example.com/metadata.json" - }, - { - name: "decimals", - required: false, - type: "number", - description: `Number of decimal places (0-9, default: ${TOKEN_CREATION_CONFIG.defaultDecimals})`, - example: "6" - }, - { - name: "initial-supply", - required: false, - type: "string", - description: `Initial token supply to mint (default: ${TOKEN_CREATION_CONFIG.defaultInitialSupply})`, - example: "1000000" - }, - { - name: "fee-basis-points", - required: false, - type: "number", - description: `Seller fee basis points (0-10000, default: ${TOKEN_CREATION_CONFIG.defaultSellerFeeBasisPoints})`, - example: "250" - } - ]; - } - - /** - * Validate token creation configuration - */ - private validateConfig(): void { - const errors: string[] = []; - - if (this.options.name && this.options.name.length > 32) { - errors.push("Token name must be 32 characters or less"); - } - - if (this.options.symbol && this.options.symbol.length > 10) { - errors.push("Token symbol must be 10 characters or less"); - } - - if (this.options.decimals !== undefined && - (this.options.decimals < 0 || this.options.decimals > 9)) { - errors.push("Decimals must be between 0 and 9"); - } - - if (this.options.feeBasisPoints !== undefined && - (this.options.feeBasisPoints < 0 || this.options.feeBasisPoints > 10000)) { - errors.push("Fee basis points must be between 0 and 10000"); - } - - if (errors.length > 0) { - throw new Error( - `Configuration validation failed:\\n${errors.map((e) => ` - ${e}`).join("\\n")}` - ); - } - } - - /** - * Create token configuration from command line options - */ - private createTokenConfig(): SplTokenConfig { - const name = this.options.name || TOKEN_CREATION_CONFIG.defaultName; - const symbol = this.options.symbol || TOKEN_CREATION_CONFIG.defaultSymbol; - const uri = this.options.uri || TOKEN_CREATION_CONFIG.defaultMetadataUri; - - const initialSupply = this.options.initialSupply - ? BigInt(this.options.initialSupply) - : BigInt(TOKEN_CREATION_CONFIG.defaultInitialSupply); - - return { - name: name, - symbol: symbol, - uri: uri, - decimals: this.options.decimals ?? TOKEN_CREATION_CONFIG.defaultDecimals, - initialSupply: initialSupply, - sellerFeeBasisPoints: this.options.feeBasisPoints ?? TOKEN_CREATION_CONFIG.defaultSellerFeeBasisPoints, - tokenProgram: TokenProgram.SPL_TOKEN, - }; - } - - protected async execute(): Promise { - this.logger.info("SPL Token Creator with Metaplex Metadata"); - this.logger.info("==============================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("==============================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalanceDisplay = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalanceDisplay.toFixed(9)} SOL)`); - - if (solBalanceDisplay < TOKEN_CREATION_CONFIG.minSolRequired) { - throw new Error( - `Insufficient SOL balance. Need at least ${TOKEN_CREATION_CONFIG.minSolRequired} SOL for transaction fees. ` + - `Current balance: ${solBalanceDisplay.toFixed(9)} SOL` - ); - } - - // Validate configuration - this.validateConfig(); - - // Create token configuration - const tokenConfig = this.createTokenConfig(); - - this.logger.info(""); - this.logger.info("āš™ļø SPL TOKEN CONFIGURATION"); - this.logger.info("==============================================="); - this.logger.info(`Name: ${tokenConfig.name}${!this.options.name ? " (default)" : ""}`); - this.logger.info(`Symbol: ${tokenConfig.symbol}${!this.options.symbol ? " (default)" : ""}`); - this.logger.info(`Decimals: ${tokenConfig.decimals}${this.options.decimals === undefined ? " (default)" : ""}`); - this.logger.info(`URI: ${tokenConfig.uri}${!this.options.uri ? " (default)" : ""}`); - this.logger.info(`Initial Supply: ${tokenConfig.initialSupply?.toString() || "0"}${!this.options.initialSupply ? " (default)" : ""}`); - this.logger.info(`Seller Fee Basis Points: ${tokenConfig.sellerFeeBasisPoints || 0}${this.options.feeBasisPoints === undefined ? " (default)" : ""}`); - this.logger.info(`Token Program: SPL Token (legacy)`); - - // Warn if using defaults - if (!this.options.name || !this.options.symbol) { - this.logger.warn( - "\\nāš ļø Using default token name/symbol. Consider providing your own with --name and --symbol for production tokens." - ); - } - if (!this.options.uri) { - this.logger.warn( - "\\nāš ļø Using default metadata URI. Consider providing your own with --uri for production tokens." - ); - } - - // Initialize TokenCreationUtils - const tokenUtils = new TokenCreationUtils( - config.connection, - walletKeypair, - this.options.logLevel ?? TOKEN_CREATION_CONFIG.defaultLogLevel - ); - - // Create the token - this.logger.info(""); - this.logger.info("šŸ­ CREATING SPL TOKEN"); - this.logger.info("==============================================="); - const result = await tokenUtils.createTokenWithMetadata(tokenConfig, { - skipPreflight: this.options.skipPreflight, - commitment: "finalized", - }); - - // Display results - this.logger.info(""); - this.logger.info("āœ… SPL TOKEN CREATED SUCCESSFULLY"); - this.logger.info("==============================================="); - this.logger.info(`Mint Address: ${result.mint.toString()}`); - this.logger.info(`Transaction Signature: ${result.signature}`); - if (result.tokenAccount) { - this.logger.info(`Token Account: ${result.tokenAccount.toString()}`); - } - - // Display explorer URLs - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("==============================================="); - this.logger.info(`Mint: ${getExplorerAddressUrl(config.id, result.mint.toString())}`); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, result.signature)}`); - if (result.tokenAccount) { - this.logger.info( - `Token Account: ${getExplorerAddressUrl(config.id, result.tokenAccount.toString())}` - ); - } - - this.logger.info(""); - this.logger.info("šŸŽ‰ SPL Token creation completed successfully!"); - this.logger.info(""); - this.logger.info("šŸ’” You can now use this mint address for token operations:"); - this.logger.info(` Mint Address: ${result.mint.toString()}`); - this.logger.info(""); - this.logger.info("ā„¹ļø Note: This is a legacy SPL Token. For newer features, consider using Token-2022."); - } -} - -// Create and run the command -const command = new CreateTokenMetaplexCommand(); -command.run().catch((error) => { - process.exit(1); -}); \ No newline at end of file diff --git a/ccip-scripts/svm/token/mint-tokens.ts b/ccip-scripts/svm/token/mint-tokens.ts deleted file mode 100644 index 7a01c114..00000000 --- a/ccip-scripts/svm/token/mint-tokens.ts +++ /dev/null @@ -1,346 +0,0 @@ -/** - * SPL Token Minting Script (CLI Framework Version) - * - * This script mints tokens to a specified recipient's associated token account. - * If the associated token account doesn't exist, it will be created automatically. - * Works with any SPL Token or Token-2022 mint where you have minting authority. - */ - -import { PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js"; -import { - TokenManager, - TokenManagerOptions, - LogLevel, - createLogger, -} from "../../../ccip-lib/svm"; -import { loadKeypair, getKeypairPath } from "../utils"; -import { - ChainId, - getCCIPSVMConfig, - resolveNetworkConfig, - getExplorerUrl, - getExplorerAddressUrl, -} from "../../config"; -import { CCIPCommand, ArgumentDefinition, CommandMetadata, BaseCommandOptions } from "../utils/cli-framework"; - -/** - * Configuration for token minting operations - */ -const TOKEN_MINTING_CONFIG = { - minSolRequired: 0.005, - defaultLogLevel: LogLevel.INFO, -}; - -/** - * Options specific to the mint-tokens command - */ -interface MintTokensOptions extends BaseCommandOptions { - mint: string; - amount: string; - recipient?: string; -} - -/** - * Token information interface - */ -interface TokenInfo { - decimals: number; - supply: string; -} - -/** - * SPL Token Minting Command - */ -class MintTokensCommand extends CCIPCommand { - constructor() { - const metadata: CommandMetadata = { - name: "mint-tokens", - description: "šŸŖ™ SPL Token Minting Tool\n\nMints tokens to a specified recipient's associated token account. Works with SPL Token and Token-2022 mints where you have minting authority.", - examples: [ - "# Mint 1000 tokens to your wallet", - "yarn svm:token:mint --mint 9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM --amount 1000", - "", - "# Mint 500 tokens to another wallet", - "yarn svm:token:mint --mint 9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM --amount 500 --recipient 5vXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", - "", - "# Mint with debugging enabled", - "yarn svm:token:mint --mint 9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM --amount 100 --log-level DEBUG", - "", - "# Mint fractional amounts", - "yarn svm:token:mint --mint 9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM --amount 1.5" - ], - notes: [ - "You must be the mint authority of the token to mint new tokens", - "Associated Token Accounts (ATAs) are created automatically if they don't exist", - "Transaction fees are paid from your wallet's SOL balance", - "Amounts are specified in token units (e.g., 1.5 tokens, not raw amounts)", - "Supports both SPL Token and Token-2022 programs", - "Minimum 0.005 SOL required for transaction fees" - ] - }; - - super(metadata); - } - - protected defineArguments(): ArgumentDefinition[] { - return [ - { - name: "mint", - required: true, - type: "string", - description: "Token mint address", - example: "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM" - }, - { - name: "amount", - required: true, - type: "string", - description: "Amount to mint in token units", - example: "1000" - }, - { - name: "recipient", - required: false, - type: "string", - description: "Recipient wallet address (defaults to your wallet if not provided)", - example: "5vXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - } - ]; - } - - /** - * Validate token minting configuration - */ - private validateConfig(): void { - const errors: string[] = []; - - // Validate mint address - try { - new PublicKey(this.options.mint); - } catch { - errors.push("Invalid mint address format"); - } - - // Validate amount - const amount = parseFloat(this.options.amount); - if (isNaN(amount) || amount <= 0) { - errors.push("Amount must be a positive number"); - } - - // Validate recipient if provided - if (this.options.recipient) { - try { - new PublicKey(this.options.recipient); - } catch { - errors.push("Invalid recipient address format"); - } - } - - if (errors.length > 0) { - throw new Error( - `Configuration validation failed:\n${errors.map((e) => ` - ${e}`).join("\n")}` - ); - } - } - - /** - * Get token information from mint address - */ - private async getTokenInfo(mint: PublicKey, config: any): Promise { - try { - const mintInfo = await config.connection.getParsedAccountInfo(mint); - - if (!mintInfo.value || !mintInfo.value.data || typeof mintInfo.value.data === "string") { - throw new Error("Invalid mint account or unable to parse mint data"); - } - - const data = mintInfo.value.data as any; - if (data.program !== "spl-token-2022" && data.program !== "spl-token") { - throw new Error("Account is not a valid SPL token mint"); - } - - return { - decimals: data.parsed.info.decimals, - supply: data.parsed.info.supply, - }; - } catch (error) { - throw new Error( - `Failed to get token info: ${error instanceof Error ? error.message : String(error)}` - ); - } - } - - /** - * Convert amount from token units to raw token amount - */ - private convertToRawAmount(amount: string, decimals: number): bigint { - const amountFloat = parseFloat(amount); - const multiplier = Math.pow(10, decimals); - const rawAmount = Math.floor(amountFloat * multiplier); - return BigInt(rawAmount); - } - - /** - * Format raw token amount to human-readable units - */ - private formatTokenAmount(rawAmount: string, decimals: number): string { - const amount = BigInt(rawAmount); - const divisor = BigInt(Math.pow(10, decimals)); - const wholePart = amount / divisor; - const fractionalPart = amount % divisor; - - if (fractionalPart === BigInt(0)) { - return wholePart.toString(); - } - - const fractionalStr = fractionalPart.toString().padStart(decimals, "0"); - const trimmedFractional = fractionalStr.replace(/0+$/, ""); - - return trimmedFractional ? `${wholePart}.${trimmedFractional}` : wholePart.toString(); - } - - protected async execute(): Promise { - this.logger.info("SPL Token Minting Tool"); - this.logger.info("================================="); - - // Resolve network configuration - const config = resolveNetworkConfig(this.options); - - // Load wallet - const keypairPath = getKeypairPath(this.options); - const walletKeypair = loadKeypair(keypairPath); - - this.logger.info(`Network: ${config.id}`); - this.logger.info(`Wallet: ${walletKeypair.publicKey.toString()}`); - - // Check SOL balance - this.logger.info(""); - this.logger.info("šŸ’° WALLET BALANCE"); - this.logger.info("================================="); - const balance = await config.connection.getBalance(walletKeypair.publicKey); - const solBalanceDisplay = balance / LAMPORTS_PER_SOL; - this.logger.info(`SOL Balance: ${balance} lamports (${solBalanceDisplay.toFixed(9)} SOL)`); - - if (solBalanceDisplay < TOKEN_MINTING_CONFIG.minSolRequired) { - throw new Error( - `Insufficient SOL balance. Need at least ${TOKEN_MINTING_CONFIG.minSolRequired} SOL for transaction fees. ` + - `Current balance: ${solBalanceDisplay.toFixed(9)} SOL` - ); - } - - // Validate configuration - this.validateConfig(); - - const mintAddress = new PublicKey(this.options.mint); - const recipientAddress = this.options.recipient - ? new PublicKey(this.options.recipient) - : walletKeypair.publicKey; - - // Get token information - this.logger.info(""); - this.logger.info("šŸŖ™ TOKEN INFORMATION"); - this.logger.info("================================="); - const tokenInfo = await this.getTokenInfo(mintAddress, config); - this.logger.info(`Mint Address: ${mintAddress.toString()}`); - this.logger.info(`Token Decimals: ${tokenInfo.decimals}`); - this.logger.info( - `Current Supply: ${this.formatTokenAmount(tokenInfo.supply, tokenInfo.decimals)} tokens` - ); - - // Convert amount to raw token amount - const rawAmount = this.convertToRawAmount(this.options.amount, tokenInfo.decimals); - const formattedAmount = this.formatTokenAmount(rawAmount.toString(), tokenInfo.decimals); - - this.logger.info(""); - this.logger.info("āš™ļø MINTING CONFIGURATION"); - this.logger.info("================================="); - this.logger.info(`Amount to Mint: ${formattedAmount} tokens`); - this.logger.info(`Raw Amount: ${rawAmount.toString()}`); - this.logger.info(`Recipient: ${recipientAddress.toString()}`); - if (recipientAddress.equals(walletKeypair.publicKey)) { - this.logger.info("(Minting to your own wallet)"); - } - - // Initialize TokenManager - const tokenManagerOptions: TokenManagerOptions = { - logLevel: this.options.logLevel ?? TOKEN_MINTING_CONFIG.defaultLogLevel, - skipPreflight: this.options.skipPreflight, - commitment: "finalized", - }; - - const tokenManager = new TokenManager(config, walletKeypair, tokenManagerOptions); - - // Check if ATA exists and get/create it - this.logger.info(""); - this.logger.info("šŸ”— ASSOCIATED TOKEN ACCOUNT"); - this.logger.info("================================="); - const ata = await tokenManager.getOrCreateATA(mintAddress, recipientAddress); - this.logger.info(`Token Account: ${ata.toString()}`); - - // Get current balance before minting - let currentBalance: bigint; - try { - currentBalance = await tokenManager.getTokenBalance(ata); - this.logger.info( - `Current Balance: ${this.formatTokenAmount( - currentBalance.toString(), - tokenInfo.decimals - )} tokens` - ); - } catch { - this.logger.info("Current Balance: 0 tokens (new account)"); - currentBalance = BigInt(0); - } - - // Mint the tokens - this.logger.info(""); - this.logger.info("šŸ­ MINTING TOKENS"); - this.logger.info("================================="); - const result = await tokenManager.mintTokens(mintAddress, rawAmount, recipientAddress); - - // Display results - this.logger.info(""); - this.logger.info("āœ… TOKENS MINTED SUCCESSFULLY"); - this.logger.info("================================="); - this.logger.info(`Transaction Signature: ${result.signature}`); - this.logger.info( - `Amount Minted: ${this.formatTokenAmount( - result.amount.toString(), - tokenInfo.decimals - )} tokens` - ); - this.logger.info( - `New Balance: ${this.formatTokenAmount(result.newBalance, tokenInfo.decimals)} tokens` - ); - this.logger.info(`Token Account: ${result.tokenAccount.toString()}`); - - // Calculate and display the change - const newBalanceBigInt = BigInt(result.newBalance); - const balanceIncrease = newBalanceBigInt - currentBalance; - this.logger.info( - `Balance Increase: +${this.formatTokenAmount( - balanceIncrease.toString(), - tokenInfo.decimals - )} tokens` - ); - - // Display explorer URLs - this.logger.info(""); - this.logger.info("šŸ” EXPLORER URLS"); - this.logger.info("================================="); - this.logger.info(`Transaction: ${getExplorerUrl(config.id, result.signature)}`); - this.logger.info( - `Token Account: ${getExplorerAddressUrl(config.id, result.tokenAccount.toString())}` - ); - this.logger.info(`Mint: ${getExplorerAddressUrl(config.id, mintAddress.toString())}`); - - this.logger.info(""); - this.logger.info("šŸŽ‰ Token minting completed successfully!"); - } -} - -// Create and run the command -const command = new MintTokensCommand(); -command.run().catch((error) => { - process.exit(1); -}); diff --git a/package.json b/package.json index be614021..8e1cf45d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "scripts": { - "generate-types": "typechain --target ethers-v6 --out-dir ccip-evm-sdk/types/contracts ccip-evm-sdk/abi/*.json", + "generate-types": "typechain --target ethers-v6 --out-dir ccip-lib/evm/types/contracts ccip-lib/evm/abi/*.json", "read-data": "ts-node ./read-data.ts", "type-check": "tsc --noEmit", "svm:fee": "ts-node ./ccip-scripts/svm/router/get-ccip-fee.ts", @@ -10,34 +10,10 @@ "svm:token:delegate": "ts-node ./ccip-scripts/svm/token/delegate-token-authority.ts", "svm:token:check": "ts-node ./ccip-scripts/svm/token/check-token-approval.ts", "svm:token:wrap": "ts-node ./ccip-scripts/svm/token/wrap-sol.ts", - "svm:token:create": "ts-node ./ccip-scripts/svm/token/create-token-metaplex.ts", - "svm:token:create-2022": "ts-node ./ccip-scripts/svm/token/create-token-2022.ts", - "svm:token:mint": "ts-node ./ccip-scripts/svm/token/mint-tokens.ts", "svm:receiver:initialize": "ts-node ./ccip-scripts/svm/receiver/initialize.ts", "svm:receiver:close": "ts-node ./ccip-scripts/svm/receiver/close-storage.ts", "svm:receiver:get-message": "ts-node ./ccip-scripts/svm/receiver/get-latest-message.ts", "svm:receiver:deploy": "ts-node ./ccip-scripts/svm/receiver/deploy.ts", - "svm:pool:init-global-config": "ts-node ./ccip-scripts/svm/pool/initialize-global-config.ts", - "svm:pool:update-self-served-allowed": "ts-node ./ccip-scripts/svm/pool/update-self-served-allowed.ts", - "svm:pool:initialize": "ts-node ./ccip-scripts/svm/pool/initialize-pool.ts", - "svm:pool:create-token-account": "ts-node ./ccip-scripts/svm/pool/create-pool-token-account.ts", - "svm:pool:get-info": "ts-node ./ccip-scripts/svm/pool/get-pool-info.ts", - "svm:pool:set-router": "ts-node ./ccip-scripts/svm/pool/set-router.ts", - "svm:pool:init-chain-remote-config": "ts-node ./ccip-scripts/svm/pool/init-chain-remote-config.ts", - "svm:pool:edit-chain-remote-config": "ts-node ./ccip-scripts/svm/pool/edit-chain-remote-config.ts", - "svm:pool:get-chain-config": "ts-node ./ccip-scripts/svm/pool/get-chain-config.ts", - "svm:pool:get-pool-signer": "ts-node ./ccip-scripts/svm/pool/get-pool-signer.ts", - "svm:pool:set-rate-limit": "ts-node ./ccip-scripts/svm/pool/set-rate-limit.ts", - "svm:pool:configure-allowlist": "ts-node ./ccip-scripts/svm/pool/configure-allowlist.ts", - "svm:pool:transfer-mint-authority-to-multisig": "ts-node ./ccip-scripts/svm/pool/transfer-mint-authority-to-multisig.ts", - "svm:pool:transfer-ownership": "ts-node ./ccip-scripts/svm/pool/transfer-ownership.ts", - "svm:pool:accept-ownership": "ts-node ./ccip-scripts/svm/pool/accept-ownership.ts", - "svm:admin:propose-administrator": "ts-node ./ccip-scripts/svm/admin/propose-administrator.ts", - "svm:admin:accept-admin-role": "ts-node ./ccip-scripts/svm/admin/accept-admin-role.ts", - "svm:admin:create-alt": "ts-node ./ccip-scripts/svm/admin/create-alt.ts", - "svm:admin:extend-alt": "ts-node ./ccip-scripts/svm/admin/extend-alt.ts", - "svm:admin:set-pool": "ts-node ./ccip-scripts/svm/admin/set-pool.ts", - "svm:admin:inspect-token": "ts-node ./ccip-scripts/svm/admin/inspect-token.ts", "evm:transfer": "ts-node ./ccip-scripts/evm/router/1_token-transfer.ts", "evm:arbitrary-messaging": "ts-node ./ccip-scripts/evm/router/2_arbitrary-messaging.ts", "evm:data-and-tokens": "ts-node ./ccip-scripts/evm/router/3_data-and-tokens.ts", @@ -52,6 +28,7 @@ "@metaplex-foundation/umi": "^1.2.0", "@metaplex-foundation/umi-bundle-defaults": "^1.2.0", "@solana/spl-token": "^0.3.11", + "@solana/web3.js": "^1.98.0", "bn.js": "^5.2.0", "borsh": "^0.7.0", "bs58": "^5.0.0", @@ -72,6 +49,9 @@ "ts-mocha": "^10.0.0", "typechain": "^8.3.2" }, + "overrides": { + "@solana/web3.js": "^1.98.0" + }, "resolutions": { "@solana/web3.js": "^1.98.0" }