diff --git a/Cargo.lock b/Cargo.lock index 9d0fcbd9a1..441af10269 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7826,6 +7826,7 @@ dependencies = [ "sp-io 38.0.0", "sp-runtime 39.0.0", "sp-std 14.0.0 (git+https://github.com/chainflip-io/polkadot-sdk.git?tag=chainflip-substrate-1.15.2+2)", + "utilities", ] [[package]] diff --git a/bouncer/commands/setup_vaults.ts b/bouncer/commands/setup_vaults.ts index 02cb1f51ee..6febfdd4ed 100755 --- a/bouncer/commands/setup_vaults.ts +++ b/bouncer/commands/setup_vaults.ts @@ -163,7 +163,7 @@ async function main(): Promise { // Confirmation console.log('Waiting for new epoch...'); - await observeEvent('validator:NewEpoch'); + await observeEvent('validator:NewEpoch').event; console.log('=== New Epoch ==='); console.log('=== Vault Setup completed ==='); diff --git a/bouncer/shared/contract_interfaces.ts b/bouncer/shared/contract_interfaces.ts index 4a32e53262..b909d41364 100644 --- a/bouncer/shared/contract_interfaces.ts +++ b/bouncer/shared/contract_interfaces.ts @@ -32,3 +32,6 @@ export const getSolanaVaultIdl = loadContractCached( export const getCfTesterIdl = loadContractCached( `../contract-interfaces/sol-program-idls/${CF_SOL_PROGRAM_IDL_TAG}/cf_tester.json`, ); +export const getSolanaSwapEndpointIdl = loadContractCached( + `../contract-interfaces/sol-program-idls/${CF_SOL_PROGRAM_IDL_TAG}/swap_endpoint.json`, +); diff --git a/bouncer/shared/evm_vault_swap.ts b/bouncer/shared/evm_vault_swap.ts index b18f754df1..d0fb6774bc 100644 --- a/bouncer/shared/evm_vault_swap.ts +++ b/bouncer/shared/evm_vault_swap.ts @@ -1,3 +1,6 @@ +import * as anchor from '@coral-xyz/anchor'; +// import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet'; + import { InternalAsset as Asset, executeSwap, @@ -9,6 +12,8 @@ import { } from '@chainflip/cli'; import { HDNodeWallet } from 'ethers'; import { randomBytes } from 'crypto'; +import { PublicKey, sendAndConfirmTransaction, Keypair } from '@solana/web3.js'; +import { getAssociatedTokenAddressSync, TOKEN_PROGRAM_ID } from '@solana/spl-token'; import { observeBalanceIncrease, getContractAddress, @@ -20,11 +25,23 @@ import { stateChainAssetFromAsset, createEvmWalletAndFund, newAddress, + evmChains, + getSolWhaleKeyPair, + getSolConnection, } from './utils'; import { getBalance } from './get_balance'; import { CcmDepositMetadata, DcaParams, FillOrKillParamsX128 } from './new_swap'; import { SwapContext, SwapStatus } from './swap_context'; +import VaultIdl from '../../contract-interfaces/sol-program-idls/v1.0.0/vault.json'; +import SwapEndpointIdl from '../../contract-interfaces/sol-program-idls/v1.0.0/swap_endpoint.json'; + +import { SwapEndpoint } from '../../contract-interfaces/sol-program-idls/v1.0.0/types/swap_endpoint'; +import { Vault } from '../../contract-interfaces/sol-program-idls/v1.0.0/types/vault'; + +// Workaround because of anchor issue +const { BN } = anchor; + const erc20Assets: Asset[] = ['Flip', 'Usdc', 'Usdt', 'ArbUsdc']; export async function executeVaultSwap( @@ -100,6 +117,120 @@ export async function executeVaultSwap( return receipt; } +// Temporary before the SDK implements this. +export async function executeSolContractSwap( + srcAsset: Asset, + destAsset: Asset, + destAddress: string, + messageMetadata?: CcmDepositMetadata, +) { + const destChain = chainFromAsset(destAsset); + + // const solanaSwapEndpointId = new PublicKey(getContractAddress('Solana', 'SWAP_ENDPOINT')); + const solanaVaultDataAccount = new PublicKey(getContractAddress('Solana', 'DATA_ACCOUNT')); + const swapEndpointDataAccount = new PublicKey( + getContractAddress('Solana', 'SWAP_ENDPOINT_DATA_ACCOUNT'), + ); + const whaleKeypair = getSolWhaleKeyPair(); + + // We should just be able to do this instead but it's not working... + // const wallet = new NodeWallet(whaleKeypair); + // const provider = new anchor.AnchorProvider(connection, wallet, { + // commitment: 'processed', + // }); + // const cfSwapEndpointProgram = new anchor.Program(SwapEndpointIdl, provider); + // const vaultProgram = new anchor.Program(VaultIdl, provider); + + // The current workaround requires having the wallet in a id.json and then set the ANCHOR_WALLET env. + // TODO: Depending on how the SDK is implemented we can remove this. + process.env.ANCHOR_WALLET = 'shared/solana_keypair.json'; + + const connection = getSolConnection(); + const cfSwapEndpointProgram = new anchor.Program(SwapEndpointIdl as SwapEndpoint); + const vaultProgram = new anchor.Program(VaultIdl as Vault); + + const newEventAccountKeypair = Keypair.generate(); + const fetchedDataAccount = await vaultProgram.account.dataAccount.fetch(solanaVaultDataAccount); + const aggKey = fetchedDataAccount.aggKey; + + const tx = + srcAsset === 'Sol' + ? await cfSwapEndpointProgram.methods + .xSwapNative({ + amount: new BN( + amountToFineAmount(defaultAssetAmounts(srcAsset), assetDecimals(srcAsset)), + ), + dstChain: Number(destChain), + dstAddress: Buffer.from(destAddress), + dstToken: Number(stateChainAssetFromAsset(destAsset)), + ccmParameters: messageMetadata + ? { + message: Buffer.from(messageMetadata.message.slice(2), 'hex'), + gasAmount: new BN(messageMetadata.gasBudget), + } + : null, + // TODO: Encode cfParameters from ccmAdditionalData and other vault swap parameters + cfParameters: Buffer.from(messageMetadata?.ccmAdditionalData?.slice(2) ?? '', 'hex'), + }) + .accountsPartial({ + dataAccount: solanaVaultDataAccount, + aggKey, + from: whaleKeypair.publicKey, + eventDataAccount: newEventAccountKeypair.publicKey, + swapEndpointDataAccount, + systemProgram: anchor.web3.SystemProgram.programId, + }) + .signers([whaleKeypair, newEventAccountKeypair]) + .transaction() + : await cfSwapEndpointProgram.methods + .xSwapToken({ + amount: new BN( + amountToFineAmount(defaultAssetAmounts(srcAsset), assetDecimals(srcAsset)), + ), + dstChain: Number(destChain), + dstAddress: Buffer.from(destAddress), + dstToken: Number(stateChainAssetFromAsset(destAsset)), + ccmParameters: messageMetadata + ? { + message: Buffer.from(messageMetadata.message.slice(2), 'hex'), + gasAmount: new BN(messageMetadata.gasBudget), + } + : null, + // TODO: Encode cfParameters from ccmAdditionalData and other vault swap parameters + cfParameters: Buffer.from(messageMetadata?.ccmAdditionalData?.slice(2) ?? '', 'hex'), + decimals: assetDecimals(srcAsset), + }) + .accountsPartial({ + dataAccount: solanaVaultDataAccount, + tokenVaultAssociatedTokenAccount: new PublicKey( + getContractAddress('Solana', 'TOKEN_VAULT_ATA'), + ), + from: whaleKeypair.publicKey, + fromTokenAccount: getAssociatedTokenAddressSync( + new PublicKey(getContractAddress('Solana', 'SolUsdc')), + whaleKeypair.publicKey, + false, + ), + eventDataAccount: newEventAccountKeypair.publicKey, + swapEndpointDataAccount, + tokenSupportedAccount: new PublicKey( + getContractAddress('Solana', 'SolUsdcTokenSupport'), + ), + tokenProgram: TOKEN_PROGRAM_ID, + mint: new PublicKey(getContractAddress('Solana', 'SolUsdc')), + systemProgram: anchor.web3.SystemProgram.programId, + }) + .signers([whaleKeypair, newEventAccountKeypair]) + .transaction(); + const txHash = await sendAndConfirmTransaction(connection, tx, [ + whaleKeypair, + newEventAccountKeypair, + ]); + + console.log('tx', txHash); + return txHash; +} + export type VaultSwapParams = { sourceAsset: Asset; destAsset: Asset; @@ -122,11 +253,21 @@ export async function performVaultSwap( ): Promise { const tag = swapTag ?? ''; const amountToSwap = amount ?? defaultAssetAmounts(sourceAsset); + const srcChain = chainFromAsset(sourceAsset); try { - // Generate a new wallet for each vault swap to prevent nonce issues when running in parallel - // with other swaps via deposit channels. - const wallet = await createEvmWalletAndFund(sourceAsset); + let wallet; + let txHash: string; + let sourceAddress: string; + + if (evmChains.includes(srcChain)) { + // Generate a new wallet for each vault swap to prevent nonce issues when running in parallel + // with other swaps via deposit channels. + wallet = await createEvmWalletAndFund(sourceAsset); + sourceAddress = wallet!.address.toLowerCase(); + } else { + sourceAddress = getSolWhaleKeyPair().publicKey.toBase58(); + } const oldBalance = await getBalance(destAsset, destAddress); if (log) { @@ -136,30 +277,32 @@ export async function performVaultSwap( ); } - // To uniquely identify the VaultSwap, we need to use the TX hash. This is only known - // after sending the transaction, so we send it first and observe the events afterwards. - // There are still multiple blocks of safety margin inbetween before the event is emitted - const receipt = await executeVaultSwap( - sourceAsset, - destAsset, - destAddress, - messageMetadata, - amountToSwap, - boostFeeBps, - fillOrKillParams, - dcaParams, - wallet, - ); + // TODO: Temporary before the SDK implements this. + if (evmChains.includes(srcChain)) { + // To uniquely identify the VaultSwap, we need to use the TX hash. This is only known + // after sending the transaction, so we send it first and observe the events afterwards. + // There are still multiple blocks of safety margin inbetween before the event is emitted + const receipt = await executeVaultSwap( + sourceAsset, + destAsset, + destAddress, + messageMetadata, + amountToSwap, + boostFeeBps, + fillOrKillParams, + dcaParams, + wallet, + ); + txHash = receipt.hash; + sourceAddress = wallet!.address.toLowerCase(); + } else { + txHash = await executeSolContractSwap(sourceAsset, destAsset, destAddress, messageMetadata); + sourceAddress = getSolWhaleKeyPair().publicKey.toBase58(); + } swapContext?.updateStatus(swapTag, SwapStatus.VaultContractExecuted); const ccmEventEmitted = messageMetadata - ? observeCcmReceived( - sourceAsset, - destAsset, - destAddress, - messageMetadata, - wallet.address.toLowerCase(), - ) + ? observeCcmReceived(sourceAsset, destAsset, destAddress, messageMetadata, sourceAddress) : Promise.resolve(); const [newBalance] = await Promise.all([ @@ -174,7 +317,7 @@ export async function performVaultSwap( sourceAsset, destAsset, destAddress, - txHash: receipt.hash, + txHash, }; } catch (err) { console.error('err:', err); diff --git a/bouncer/shared/initialize_new_chains.ts b/bouncer/shared/initialize_new_chains.ts index 344d9acf26..732dbd8809 100644 --- a/bouncer/shared/initialize_new_chains.ts +++ b/bouncer/shared/initialize_new_chains.ts @@ -210,10 +210,7 @@ export async function initializeSolanaPrograms(solClient: Connection, solKey: st const solUsdcMintPubkey = new PublicKey(getContractAddress('Solana', 'SolUsdc')); - const [tokenSupportedAccount] = PublicKey.findProgramAddressSync( - [Buffer.from('supported_token'), solUsdcMintPubkey.toBuffer()], - solanaVaultProgramId, - ); + const tokenSupportedAccount = new PublicKey(getContractAddress('Solana', 'SolUsdcTokenSupport')); tx.add( new TransactionInstruction({ diff --git a/bouncer/shared/solana_keypair.json b/bouncer/shared/solana_keypair.json new file mode 100644 index 0000000000..dd9f7fa84f --- /dev/null +++ b/bouncer/shared/solana_keypair.json @@ -0,0 +1,6 @@ +[ + 6, 151, 150, 20, 145, 210, 176, 113, 98, 200, 192, 80, 73, 63, 133, 232, 208, 124, 81, 213, 117, + 199, 196, 243, 219, 33, 79, 217, 157, 69, 205, 140, 247, 157, 94, 2, 111, 18, 237, 198, 68, 58, + 83, 75, 44, 221, 80, 114, 35, 57, 137, 180, 21, 215, 89, 101, 115, 231, 67, 243, 229, 179, 134, + 251 +] diff --git a/bouncer/shared/utils.ts b/bouncer/shared/utils.ts index 073626d3af..39a147c904 100644 --- a/bouncer/shared/utils.ts +++ b/bouncer/shared/utils.ts @@ -45,6 +45,7 @@ export const brokerMutex = new Mutex(); export const snowWhiteMutex = new Mutex(); export const ccmSupportedChains = ['Ethereum', 'Arbitrum', 'Solana'] as Chain[]; +export const evmChains = ['Ethereum', 'Arbitrum'] as Chain[]; export type Asset = SDKAsset; export type Chain = SDKChain; @@ -114,14 +115,26 @@ export function getContractAddress(chain: Chain, contract: string): string { return '8inHGLHXegST3EPLcpisQe9D1hDT9r7DJjS395L3yuYf'; case 'TOKEN_VAULT_PDA': return '7B13iu7bUbBX88eVBqTZkQqrErnTMazPmGLdE5RqdyKZ'; + case 'TOKEN_VAULT_ATA': + return '9CGLwcPknpYs3atgwtjMX7RhgvBgaqK8wwCvXnmjEoL9'; case 'DATA_ACCOUNT': return 'BttvFNSRKrkHugwDP6SpnBejCKKskHowJif1HGgBtTfG'; case 'SolUsdc': return process.env.SOL_USDC_ADDRESS ?? '24PNhTaNtomHhoy3fTRaMhAFCRj4uHqhZEEoWrKDbR5p'; + case 'SolUsdcTokenSupport': + return PublicKey.findProgramAddressSync( + [ + Buffer.from('supported_token'), + new PublicKey(getContractAddress('Solana', 'SolUsdc')).toBuffer(), + ], + new PublicKey(getContractAddress('Solana', 'VAULT')), + )[0].toBase58(); case 'CFTESTER': return '8pBPaVfTAcjLeNfC187Fkvi9b1XEFhRNJ95BQXXVksmH'; case 'SWAP_ENDPOINT': return '35uYgHdfZQT4kHkaaXQ6ZdCkK5LFrsk43btTLbGCRCNT'; + case 'SWAP_ENDPOINT_DATA_ACCOUNT': + return '2tmtGLQcBd11BMiE9B1tAkQXwmPNgR79Meki2Eme4Ec9'; default: throw new Error(`Unsupported contract: ${contract}`); } diff --git a/contract-interfaces/sol-program-idls/download-sol-program-idls.sh b/contract-interfaces/sol-program-idls/download-sol-program-idls.sh index 15f85cd8af..a6f892928e 100755 --- a/contract-interfaces/sol-program-idls/download-sol-program-idls.sh +++ b/contract-interfaces/sol-program-idls/download-sol-program-idls.sh @@ -31,6 +31,7 @@ gh release download \ unzip -u ${ZIP_FILE} \ 'vault.json' \ 'cf_tester.json' \ + 'swap_endpoint.json' \ -d $TARGET_DIR rm ${ZIP_FILE} \ No newline at end of file diff --git a/contract-interfaces/sol-program-idls/v1.0.0/swap_endpoint.json b/contract-interfaces/sol-program-idls/v1.0.0/swap_endpoint.json new file mode 100644 index 0000000000..19f570dfd6 --- /dev/null +++ b/contract-interfaces/sol-program-idls/v1.0.0/swap_endpoint.json @@ -0,0 +1,655 @@ +{ + "address": "35uYgHdfZQT4kHkaaXQ6ZdCkK5LFrsk43btTLbGCRCNT", + "metadata": { + "name": "swap_endpoint", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "close_event_accounts", + "discriminator": [ + 165, + 102, + 61, + 1, + 185, + 77, + 189, + 121 + ], + "accounts": [ + { + "name": "data_account" + }, + { + "name": "agg_key", + "writable": true, + "signer": true + }, + { + "name": "swap_endpoint_data_account", + "writable": true + } + ], + "args": [] + }, + { + "name": "initialize", + "discriminator": [ + 175, + 175, + 109, + 31, + 13, + 152, + 155, + 237 + ], + "accounts": [ + { + "name": "swap_endpoint_data_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 100, + 97, + 116, + 97 + ] + } + ] + } + }, + { + "name": "signer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "x_swap_native", + "discriminator": [ + 163, + 38, + 92, + 226, + 243, + 105, + 141, + 196 + ], + "accounts": [ + { + "name": "data_account" + }, + { + "name": "agg_key", + "writable": true + }, + { + "name": "from", + "writable": true, + "signer": true + }, + { + "name": "event_data_account", + "writable": true, + "signer": true + }, + { + "name": "swap_endpoint_data_account", + "writable": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "swap_native_params", + "type": { + "defined": { + "name": "SwapNativeParams" + } + } + } + ] + }, + { + "name": "x_swap_token", + "discriminator": [ + 69, + 50, + 252, + 99, + 229, + 83, + 119, + 235 + ], + "accounts": [ + { + "name": "data_account" + }, + { + "name": "token_vault_associated_token_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "data_account.token_vault_pda", + "account": "DataAccount" + }, + { + "kind": "const", + "value": [ + 6, + 221, + 246, + 225, + 215, + 101, + 161, + 147, + 217, + 203, + 225, + 70, + 206, + 235, + 121, + 172, + 28, + 180, + 133, + 237, + 95, + 91, + 55, + 145, + 58, + 140, + 245, + 133, + 126, + 255, + 0, + 169 + ] + }, + { + "kind": "account", + "path": "mint" + } + ], + "program": { + "kind": "const", + "value": [ + 140, + 151, + 37, + 143, + 78, + 36, + 137, + 241, + 187, + 61, + 16, + 41, + 20, + 142, + 13, + 131, + 11, + 90, + 19, + 153, + 218, + 255, + 16, + 132, + 4, + 142, + 123, + 216, + 219, + 233, + 248, + 89 + ] + } + } + }, + { + "name": "from", + "writable": true, + "signer": true + }, + { + "name": "from_token_account", + "writable": true + }, + { + "name": "event_data_account", + "writable": true, + "signer": true + }, + { + "name": "swap_endpoint_data_account", + "writable": true + }, + { + "name": "token_supported_account" + }, + { + "name": "token_program", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "mint" + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "swap_token_params", + "type": { + "defined": { + "name": "SwapTokenParams" + } + } + } + ] + } + ], + "accounts": [ + { + "name": "DataAccount", + "discriminator": [ + 85, + 240, + 182, + 158, + 76, + 7, + 18, + 233 + ] + }, + { + "name": "SupportedToken", + "discriminator": [ + 56, + 162, + 96, + 99, + 193, + 245, + 204, + 108 + ] + }, + { + "name": "SwapEndpointDataAccount", + "discriminator": [ + 79, + 152, + 191, + 225, + 128, + 108, + 11, + 139 + ] + }, + { + "name": "SwapEvent", + "discriminator": [ + 150, + 251, + 114, + 94, + 200, + 113, + 248, + 70 + ] + } + ], + "events": [ + { + "name": "CantDeserializeEventAccount", + "discriminator": [ + 248, + 26, + 198, + 175, + 8, + 58, + 229, + 137 + ] + }, + { + "name": "EventAccountNotTracked", + "discriminator": [ + 202, + 29, + 253, + 107, + 20, + 196, + 36, + 210 + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "MathOverflow", + "msg": "Overflow in arithmetic operation" + }, + { + "code": 6001, + "name": "MathUnderflow", + "msg": "Underflow in arithmetic operation" + } + ], + "types": [ + { + "name": "CantDeserializeEventAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "event_account", + "type": "pubkey" + }, + { + "name": "payee", + "type": "pubkey" + } + ] + } + }, + { + "name": "CcmParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "message", + "type": "bytes" + }, + { + "name": "gas_amount", + "type": "u64" + } + ] + } + }, + { + "name": "DataAccount", + "docs": [ + "* ****************************************************************************\n * *************************** IMPORTANT NOTE *********************************\n * ****************************************************************************\n * If the vault is upgraded and the DataAccount struct is modified we need to\n * check the compatibility and ensure there is a proper migration process, given\n * that the Vault bytecode is the only thing being upgraded, not the data account.\n *\n * The easiest approach on upgrade is keeping the DataAccount unchanged and use\n * a new account struct for any new data that is required.\n *\n * DO NOT MODIFY THIS WITHOUT UNDERSTANDING THE CONSEQUENCES!\n * ****************************************************************************\n * ****************************************************************************" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "agg_key", + "type": "pubkey" + }, + { + "name": "gov_key", + "type": "pubkey" + }, + { + "name": "token_vault_pda", + "type": "pubkey" + }, + { + "name": "token_vault_bump", + "type": "u8" + }, + { + "name": "upgrade_signer_pda", + "type": "pubkey" + }, + { + "name": "upgrade_signer_pda_bump", + "type": "u8" + }, + { + "name": "suspended", + "type": "bool" + }, + { + "name": "suspended_legacy_swaps", + "type": "bool" + }, + { + "name": "suspended_event_swaps", + "type": "bool" + }, + { + "name": "min_native_swap_amount", + "type": "u64" + }, + { + "name": "max_dst_address_len", + "type": "u16" + }, + { + "name": "max_ccm_message_len", + "type": "u32" + }, + { + "name": "max_cf_parameters_len", + "type": "u32" + }, + { + "name": "max_event_accounts", + "type": "u32" + } + ] + } + }, + { + "name": "EventAccountNotTracked", + "type": { + "kind": "struct", + "fields": [ + { + "name": "event_account", + "type": "pubkey" + }, + { + "name": "payee", + "type": "pubkey" + } + ] + } + }, + { + "name": "SupportedToken", + "type": { + "kind": "struct", + "fields": [ + { + "name": "token_mint_pubkey", + "type": "pubkey" + }, + { + "name": "min_swap_amount", + "type": "u64" + } + ] + } + }, + { + "name": "SwapEndpointDataAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "historical_number_event_accounts", + "type": "u128" + }, + { + "name": "open_event_accounts", + "type": { + "vec": "pubkey" + } + } + ] + } + }, + { + "name": "SwapEvent", + "type": { + "kind": "struct", + "fields": [ + { + "name": "sender", + "type": "pubkey" + }, + { + "name": "dst_chain", + "type": "u32" + }, + { + "name": "dst_address", + "type": "bytes" + }, + { + "name": "dst_token", + "type": "u32" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "src_token", + "type": { + "option": "pubkey" + } + }, + { + "name": "ccm_parameters", + "type": { + "option": { + "defined": { + "name": "CcmParams" + } + } + } + }, + { + "name": "cf_parameters", + "type": "bytes" + } + ] + } + }, + { + "name": "SwapNativeParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "dst_chain", + "type": "u32" + }, + { + "name": "dst_address", + "type": "bytes" + }, + { + "name": "dst_token", + "type": "u32" + }, + { + "name": "ccm_parameters", + "type": { + "option": { + "defined": { + "name": "CcmParams" + } + } + } + }, + { + "name": "cf_parameters", + "type": "bytes" + } + ] + } + }, + { + "name": "SwapTokenParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "dst_chain", + "type": "u32" + }, + { + "name": "dst_address", + "type": "bytes" + }, + { + "name": "dst_token", + "type": "u32" + }, + { + "name": "ccm_parameters", + "type": { + "option": { + "defined": { + "name": "CcmParams" + } + } + } + }, + { + "name": "cf_parameters", + "type": "bytes" + }, + { + "name": "decimals", + "type": "u8" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/contract-interfaces/sol-program-idls/v1.0.0/types/swap_endpoint.ts b/contract-interfaces/sol-program-idls/v1.0.0/types/swap_endpoint.ts new file mode 100644 index 0000000000..8eae9704d2 --- /dev/null +++ b/contract-interfaces/sol-program-idls/v1.0.0/types/swap_endpoint.ts @@ -0,0 +1,661 @@ +/** + * Program IDL in camelCase format in order to be used in JS/TS. + * + * Note that this is only a type helper and is not the actual IDL. The original + * IDL can be found at `target/idl/swap_endpoint.json`. + */ +export type SwapEndpoint = { + "address": "35uYgHdfZQT4kHkaaXQ6ZdCkK5LFrsk43btTLbGCRCNT", + "metadata": { + "name": "swapEndpoint", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "closeEventAccounts", + "discriminator": [ + 165, + 102, + 61, + 1, + 185, + 77, + 189, + 121 + ], + "accounts": [ + { + "name": "dataAccount" + }, + { + "name": "aggKey", + "writable": true, + "signer": true + }, + { + "name": "swapEndpointDataAccount", + "writable": true + } + ], + "args": [] + }, + { + "name": "initialize", + "discriminator": [ + 175, + 175, + 109, + 31, + 13, + 152, + 155, + 237 + ], + "accounts": [ + { + "name": "swapEndpointDataAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 100, + 97, + 116, + 97 + ] + } + ] + } + }, + { + "name": "signer", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "xSwapNative", + "discriminator": [ + 163, + 38, + 92, + 226, + 243, + 105, + 141, + 196 + ], + "accounts": [ + { + "name": "dataAccount" + }, + { + "name": "aggKey", + "writable": true + }, + { + "name": "from", + "writable": true, + "signer": true + }, + { + "name": "eventDataAccount", + "writable": true, + "signer": true + }, + { + "name": "swapEndpointDataAccount", + "writable": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "swapNativeParams", + "type": { + "defined": { + "name": "swapNativeParams" + } + } + } + ] + }, + { + "name": "xSwapToken", + "discriminator": [ + 69, + 50, + 252, + 99, + 229, + 83, + 119, + 235 + ], + "accounts": [ + { + "name": "dataAccount" + }, + { + "name": "tokenVaultAssociatedTokenAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "data_account.token_vault_pda", + "account": "dataAccount" + }, + { + "kind": "const", + "value": [ + 6, + 221, + 246, + 225, + 215, + 101, + 161, + 147, + 217, + 203, + 225, + 70, + 206, + 235, + 121, + 172, + 28, + 180, + 133, + 237, + 95, + 91, + 55, + 145, + 58, + 140, + 245, + 133, + 126, + 255, + 0, + 169 + ] + }, + { + "kind": "account", + "path": "mint" + } + ], + "program": { + "kind": "const", + "value": [ + 140, + 151, + 37, + 143, + 78, + 36, + 137, + 241, + 187, + 61, + 16, + 41, + 20, + 142, + 13, + 131, + 11, + 90, + 19, + 153, + 218, + 255, + 16, + 132, + 4, + 142, + 123, + 216, + 219, + 233, + 248, + 89 + ] + } + } + }, + { + "name": "from", + "writable": true, + "signer": true + }, + { + "name": "fromTokenAccount", + "writable": true + }, + { + "name": "eventDataAccount", + "writable": true, + "signer": true + }, + { + "name": "swapEndpointDataAccount", + "writable": true + }, + { + "name": "tokenSupportedAccount" + }, + { + "name": "tokenProgram", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "mint" + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "swapTokenParams", + "type": { + "defined": { + "name": "swapTokenParams" + } + } + } + ] + } + ], + "accounts": [ + { + "name": "dataAccount", + "discriminator": [ + 85, + 240, + 182, + 158, + 76, + 7, + 18, + 233 + ] + }, + { + "name": "supportedToken", + "discriminator": [ + 56, + 162, + 96, + 99, + 193, + 245, + 204, + 108 + ] + }, + { + "name": "swapEndpointDataAccount", + "discriminator": [ + 79, + 152, + 191, + 225, + 128, + 108, + 11, + 139 + ] + }, + { + "name": "swapEvent", + "discriminator": [ + 150, + 251, + 114, + 94, + 200, + 113, + 248, + 70 + ] + } + ], + "events": [ + { + "name": "cantDeserializeEventAccount", + "discriminator": [ + 248, + 26, + 198, + 175, + 8, + 58, + 229, + 137 + ] + }, + { + "name": "eventAccountNotTracked", + "discriminator": [ + 202, + 29, + 253, + 107, + 20, + 196, + 36, + 210 + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "mathOverflow", + "msg": "Overflow in arithmetic operation" + }, + { + "code": 6001, + "name": "mathUnderflow", + "msg": "Underflow in arithmetic operation" + } + ], + "types": [ + { + "name": "cantDeserializeEventAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "eventAccount", + "type": "pubkey" + }, + { + "name": "payee", + "type": "pubkey" + } + ] + } + }, + { + "name": "ccmParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "message", + "type": "bytes" + }, + { + "name": "gasAmount", + "type": "u64" + } + ] + } + }, + { + "name": "dataAccount", + "docs": [ + "* ****************************************************************************\n * *************************** IMPORTANT NOTE *********************************\n * ****************************************************************************\n * If the vault is upgraded and the DataAccount struct is modified we need to\n * check the compatibility and ensure there is a proper migration process, given\n * that the Vault bytecode is the only thing being upgraded, not the data account.\n *\n * The easiest approach on upgrade is keeping the DataAccount unchanged and use\n * a new account struct for any new data that is required.\n *\n * DO NOT MODIFY THIS WITHOUT UNDERSTANDING THE CONSEQUENCES!\n * ****************************************************************************\n * ****************************************************************************" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "aggKey", + "type": "pubkey" + }, + { + "name": "govKey", + "type": "pubkey" + }, + { + "name": "tokenVaultPda", + "type": "pubkey" + }, + { + "name": "tokenVaultBump", + "type": "u8" + }, + { + "name": "upgradeSignerPda", + "type": "pubkey" + }, + { + "name": "upgradeSignerPdaBump", + "type": "u8" + }, + { + "name": "suspended", + "type": "bool" + }, + { + "name": "suspendedLegacySwaps", + "type": "bool" + }, + { + "name": "suspendedEventSwaps", + "type": "bool" + }, + { + "name": "minNativeSwapAmount", + "type": "u64" + }, + { + "name": "maxDstAddressLen", + "type": "u16" + }, + { + "name": "maxCcmMessageLen", + "type": "u32" + }, + { + "name": "maxCfParametersLen", + "type": "u32" + }, + { + "name": "maxEventAccounts", + "type": "u32" + } + ] + } + }, + { + "name": "eventAccountNotTracked", + "type": { + "kind": "struct", + "fields": [ + { + "name": "eventAccount", + "type": "pubkey" + }, + { + "name": "payee", + "type": "pubkey" + } + ] + } + }, + { + "name": "supportedToken", + "type": { + "kind": "struct", + "fields": [ + { + "name": "tokenMintPubkey", + "type": "pubkey" + }, + { + "name": "minSwapAmount", + "type": "u64" + } + ] + } + }, + { + "name": "swapEndpointDataAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "historicalNumberEventAccounts", + "type": "u128" + }, + { + "name": "openEventAccounts", + "type": { + "vec": "pubkey" + } + } + ] + } + }, + { + "name": "swapEvent", + "type": { + "kind": "struct", + "fields": [ + { + "name": "sender", + "type": "pubkey" + }, + { + "name": "dstChain", + "type": "u32" + }, + { + "name": "dstAddress", + "type": "bytes" + }, + { + "name": "dstToken", + "type": "u32" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "srcToken", + "type": { + "option": "pubkey" + } + }, + { + "name": "ccmParameters", + "type": { + "option": { + "defined": { + "name": "ccmParams" + } + } + } + }, + { + "name": "cfParameters", + "type": "bytes" + } + ] + } + }, + { + "name": "swapNativeParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "dstChain", + "type": "u32" + }, + { + "name": "dstAddress", + "type": "bytes" + }, + { + "name": "dstToken", + "type": "u32" + }, + { + "name": "ccmParameters", + "type": { + "option": { + "defined": { + "name": "ccmParams" + } + } + } + }, + { + "name": "cfParameters", + "type": "bytes" + } + ] + } + }, + { + "name": "swapTokenParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "dstChain", + "type": "u32" + }, + { + "name": "dstAddress", + "type": "bytes" + }, + { + "name": "dstToken", + "type": "u32" + }, + { + "name": "ccmParameters", + "type": { + "option": { + "defined": { + "name": "ccmParams" + } + } + } + }, + { + "name": "cfParameters", + "type": "bytes" + }, + { + "name": "decimals", + "type": "u8" + } + ] + } + } + ] +}; diff --git a/contract-interfaces/sol-program-idls/v1.0.0/types/vault.ts b/contract-interfaces/sol-program-idls/v1.0.0/types/vault.ts new file mode 100644 index 0000000000..1bca1885c4 --- /dev/null +++ b/contract-interfaces/sol-program-idls/v1.0.0/types/vault.ts @@ -0,0 +1,2012 @@ +/** + * Program IDL in camelCase format in order to be used in JS/TS. + * + * Note that this is only a type helper and is not the actual IDL. The original + * IDL can be found at `target/idl/vault.json`. + */ +export type Vault = { + "address": "8inHGLHXegST3EPLcpisQe9D1hDT9r7DJjS395L3yuYf", + "metadata": { + "name": "vault", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "disableTokenSupport", + "discriminator": [ + 72, + 4, + 35, + 144, + 194, + 49, + 71, + 64 + ], + "accounts": [ + { + "name": "dataAccount", + "writable": true + }, + { + "name": "govKey", + "writable": true, + "signer": true + }, + { + "name": "tokenSupportedAccount", + "writable": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "enableTokenSupport", + "discriminator": [ + 125, + 160, + 180, + 50, + 26, + 27, + 112, + 153 + ], + "accounts": [ + { + "name": "dataAccount", + "writable": true + }, + { + "name": "govKey", + "writable": true, + "signer": true + }, + { + "name": "tokenSupportedAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 115, + 117, + 112, + 112, + 111, + 114, + 116, + 101, + 100, + 95, + 116, + 111, + 107, + 101, + 110 + ] + }, + { + "kind": "account", + "path": "mint" + } + ] + } + }, + { + "name": "mint" + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "minSwapAmount", + "type": "u64" + } + ] + }, + { + "name": "executeCcmNativeCall", + "discriminator": [ + 125, + 5, + 11, + 227, + 128, + 66, + 224, + 178 + ], + "accounts": [ + { + "name": "dataAccount" + }, + { + "name": "aggKey", + "signer": true + }, + { + "name": "receiverNative", + "writable": true + }, + { + "name": "cfReceiver", + "docs": [ + "the aggregate key signature." + ] + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + }, + { + "name": "instructionSysvar", + "address": "Sysvar1nstructions1111111111111111111111111" + } + ], + "args": [ + { + "name": "sourceChain", + "type": "u32" + }, + { + "name": "sourceAddress", + "type": "bytes" + }, + { + "name": "message", + "type": "bytes" + }, + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "executeCcmTokenCall", + "discriminator": [ + 108, + 184, + 162, + 123, + 159, + 222, + 170, + 35 + ], + "accounts": [ + { + "name": "dataAccount" + }, + { + "name": "aggKey", + "signer": true + }, + { + "name": "receiverTokenAccount", + "writable": true + }, + { + "name": "cfReceiver", + "docs": [ + "without passing the aggregate key signature." + ] + }, + { + "name": "tokenProgram", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "mint" + }, + { + "name": "instructionSysvar", + "address": "Sysvar1nstructions1111111111111111111111111" + } + ], + "args": [ + { + "name": "sourceChain", + "type": "u32" + }, + { + "name": "sourceAddress", + "type": "bytes" + }, + { + "name": "message", + "type": "bytes" + }, + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "fetchNative", + "discriminator": [ + 142, + 36, + 101, + 143, + 108, + 89, + 41, + 140 + ], + "accounts": [ + { + "name": "dataAccount" + }, + { + "name": "aggKey", + "writable": true, + "signer": true + }, + { + "name": "depositChannelPda", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 99, + 104, + 97, + 110, + 110, + 101, + 108 + ] + }, + { + "kind": "arg", + "path": "seed" + } + ] + } + }, + { + "name": "depositChannelHistoricalFetch", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 104, + 105, + 115, + 116, + 95, + 102, + 101, + 116, + 99, + 104 + ] + }, + { + "kind": "account", + "path": "depositChannelPda" + } + ] + } + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "seed", + "type": "bytes" + }, + { + "name": "bump", + "type": "u8" + } + ] + }, + { + "name": "fetchTokens", + "discriminator": [ + 73, + 71, + 16, + 100, + 44, + 176, + 198, + 70 + ], + "accounts": [ + { + "name": "dataAccount" + }, + { + "name": "aggKey", + "writable": true, + "signer": true + }, + { + "name": "depositChannelPda", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 99, + 104, + 97, + 110, + 110, + 101, + 108 + ] + }, + { + "kind": "arg", + "path": "seed" + } + ] + } + }, + { + "name": "depositChannelAssociatedTokenAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "depositChannelPda" + }, + { + "kind": "const", + "value": [ + 6, + 221, + 246, + 225, + 215, + 101, + 161, + 147, + 217, + 203, + 225, + 70, + 206, + 235, + 121, + 172, + 28, + 180, + 133, + 237, + 95, + 91, + 55, + 145, + 58, + 140, + 245, + 133, + 126, + 255, + 0, + 169 + ] + }, + { + "kind": "account", + "path": "mint" + } + ], + "program": { + "kind": "const", + "value": [ + 140, + 151, + 37, + 143, + 78, + 36, + 137, + 241, + 187, + 61, + 16, + 41, + 20, + 142, + 13, + 131, + 11, + 90, + 19, + 153, + 218, + 255, + 16, + 132, + 4, + 142, + 123, + 216, + 219, + 233, + 248, + 89 + ] + } + } + }, + { + "name": "tokenVaultAssociatedTokenAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "data_account.token_vault_pda", + "account": "dataAccount" + }, + { + "kind": "const", + "value": [ + 6, + 221, + 246, + 225, + 215, + 101, + 161, + 147, + 217, + 203, + 225, + 70, + 206, + 235, + 121, + 172, + 28, + 180, + 133, + 237, + 95, + 91, + 55, + 145, + 58, + 140, + 245, + 133, + 126, + 255, + 0, + 169 + ] + }, + { + "kind": "account", + "path": "mint" + } + ], + "program": { + "kind": "const", + "value": [ + 140, + 151, + 37, + 143, + 78, + 36, + 137, + 241, + 187, + 61, + 16, + 41, + 20, + 142, + 13, + 131, + 11, + 90, + 19, + 153, + 218, + 255, + 16, + 132, + 4, + 142, + 123, + 216, + 219, + 233, + 248, + 89 + ] + } + } + }, + { + "name": "mint" + }, + { + "name": "tokenProgram", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "depositChannelHistoricalFetch", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 104, + 105, + 115, + 116, + 95, + 102, + 101, + 116, + 99, + 104 + ] + }, + { + "kind": "account", + "path": "depositChannelAssociatedTokenAccount" + } + ] + } + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "seed", + "type": "bytes" + }, + { + "name": "bump", + "type": "u8" + }, + { + "name": "decimals", + "type": "u8" + } + ] + }, + { + "name": "initialize", + "discriminator": [ + 175, + 175, + 109, + 31, + 13, + 152, + 155, + 237 + ], + "accounts": [ + { + "name": "dataAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 100, + 97, + 116, + 97 + ] + } + ] + } + }, + { + "name": "initializer", + "writable": true, + "signer": true, + "address": "HfasueN6RNPjSM6rKGH5dga6kS2oUF8siGH3m4MXPURp" + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "newAggKey", + "type": "pubkey" + }, + { + "name": "newGovKey", + "type": "pubkey" + }, + { + "name": "expectedTokenVaultPda", + "type": "pubkey" + }, + { + "name": "expectedTokenVaultPdaBump", + "type": "u8" + }, + { + "name": "expectedUpgradeSignerPda", + "type": "pubkey" + }, + { + "name": "expectedUpgradeSignerPdaBump", + "type": "u8" + }, + { + "name": "suspendedVault", + "type": "bool" + }, + { + "name": "suspendedLegacySwaps", + "type": "bool" + }, + { + "name": "suspendedEventSwaps", + "type": "bool" + }, + { + "name": "minNativeSwapAmount", + "type": "u64" + }, + { + "name": "maxDstAddressLen", + "type": "u16" + }, + { + "name": "maxCcmMessageLen", + "type": "u32" + }, + { + "name": "maxCfParametersLen", + "type": "u32" + }, + { + "name": "maxEventAccounts", + "type": "u32" + } + ] + }, + { + "name": "rotateAggKey", + "discriminator": [ + 78, + 81, + 143, + 171, + 221, + 165, + 214, + 139 + ], + "accounts": [ + { + "name": "dataAccount", + "writable": true + }, + { + "name": "aggKey", + "writable": true, + "signer": true + }, + { + "name": "newAggKey", + "writable": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "skipTransferFunds", + "type": "bool" + } + ] + }, + { + "name": "setGovKeyWithAggKey", + "discriminator": [ + 66, + 64, + 58, + 40, + 15, + 75, + 215, + 162 + ], + "accounts": [ + { + "name": "dataAccount", + "writable": true + }, + { + "name": "aggKey", + "signer": true + } + ], + "args": [ + { + "name": "newGovKey", + "type": "pubkey" + } + ] + }, + { + "name": "setGovKeyWithGovKey", + "discriminator": [ + 251, + 142, + 231, + 255, + 111, + 143, + 165, + 106 + ], + "accounts": [ + { + "name": "dataAccount", + "writable": true + }, + { + "name": "govKey", + "signer": true + } + ], + "args": [ + { + "name": "newGovKey", + "type": "pubkey" + } + ] + }, + { + "name": "setProgramSwapsParameters", + "discriminator": [ + 129, + 254, + 31, + 151, + 111, + 149, + 135, + 77 + ], + "accounts": [ + { + "name": "dataAccount", + "writable": true + }, + { + "name": "govKey", + "signer": true + } + ], + "args": [ + { + "name": "minNativeSwapAmount", + "type": "u64" + }, + { + "name": "maxDstAddressLen", + "type": "u16" + }, + { + "name": "maxCcmMessageLen", + "type": "u32" + }, + { + "name": "maxCfParametersLen", + "type": "u32" + }, + { + "name": "maxEventAccounts", + "type": "u32" + } + ] + }, + { + "name": "setSuspendedState", + "discriminator": [ + 145, + 13, + 20, + 161, + 30, + 62, + 226, + 32 + ], + "accounts": [ + { + "name": "dataAccount", + "writable": true + }, + { + "name": "govKey", + "signer": true + } + ], + "args": [ + { + "name": "suspend", + "type": "bool" + }, + { + "name": "suspendLegacySwaps", + "type": "bool" + }, + { + "name": "suspendEventSwaps", + "type": "bool" + } + ] + }, + { + "name": "transferTokens", + "discriminator": [ + 54, + 180, + 238, + 175, + 74, + 85, + 126, + 188 + ], + "accounts": [ + { + "name": "dataAccount" + }, + { + "name": "aggKey", + "signer": true + }, + { + "name": "tokenVaultPda" + }, + { + "name": "tokenVaultAssociatedTokenAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "data_account.token_vault_pda", + "account": "dataAccount" + }, + { + "kind": "const", + "value": [ + 6, + 221, + 246, + 225, + 215, + 101, + 161, + 147, + 217, + 203, + 225, + 70, + 206, + 235, + 121, + 172, + 28, + 180, + 133, + 237, + 95, + 91, + 55, + 145, + 58, + 140, + 245, + 133, + 126, + 255, + 0, + 169 + ] + }, + { + "kind": "account", + "path": "mint" + } + ], + "program": { + "kind": "const", + "value": [ + 140, + 151, + 37, + 143, + 78, + 36, + 137, + 241, + 187, + 61, + 16, + 41, + 20, + 142, + 13, + 131, + 11, + 90, + 19, + 153, + 218, + 255, + 16, + 132, + 4, + 142, + 123, + 216, + 219, + 233, + 248, + 89 + ] + } + } + }, + { + "name": "toTokenAccount", + "writable": true + }, + { + "name": "mint" + }, + { + "name": "tokenProgram", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + } + ] + }, + { + "name": "transferVaultUpgradeAuthority", + "discriminator": [ + 114, + 247, + 72, + 110, + 145, + 65, + 236, + 153 + ], + "accounts": [ + { + "name": "dataAccount" + }, + { + "name": "aggKey", + "signer": true + }, + { + "name": "programDataAddress", + "writable": true + }, + { + "name": "programAddress" + }, + { + "name": "newAuthority" + }, + { + "name": "signerPda", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 115, + 105, + 103, + 110, + 101, + 114 + ] + } + ] + } + }, + { + "name": "bpfLoaderUpgradeable", + "address": "BPFLoaderUpgradeab1e11111111111111111111111" + } + ], + "args": [] + }, + { + "name": "upgradeProgram", + "docs": [ + "* ****************************************************************************\n * *************************** IMPORTANT NOTE *********************************\n * ****************************************************************************\n * The signer_pda is the upgrade authority for the vault program. Changing this\n * logic should be done with caution and understanding the consequences.\n *\n * DO NOT MODIFY THIS WITHOUT UNDERSTANDING THE CONSEQUENCES!\n * ****************************************************************************\n * ****************************************************************************" + ], + "discriminator": [ + 223, + 236, + 39, + 89, + 111, + 204, + 114, + 37 + ], + "accounts": [ + { + "name": "dataAccount" + }, + { + "name": "govKey", + "signer": true + }, + { + "name": "programDataAddress", + "writable": true + }, + { + "name": "programAddress", + "writable": true + }, + { + "name": "bufferAddress", + "writable": true + }, + { + "name": "spillAddress", + "writable": true + }, + { + "name": "sysvarRent", + "address": "SysvarRent111111111111111111111111111111111" + }, + { + "name": "sysvarClock", + "address": "SysvarC1ock11111111111111111111111111111111" + }, + { + "name": "signerPda", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 115, + 105, + 103, + 110, + 101, + 114 + ] + } + ] + } + }, + { + "name": "bpfLoaderUpgradeable", + "address": "BPFLoaderUpgradeab1e11111111111111111111111" + } + ], + "args": [] + }, + { + "name": "xSwapNativeLegacy", + "discriminator": [ + 97, + 21, + 117, + 255, + 21, + 6, + 232, + 176 + ], + "accounts": [ + { + "name": "dataAccount" + }, + { + "name": "aggKey", + "writable": true + }, + { + "name": "from", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + }, + { + "name": "eventAuthority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 95, + 95, + 101, + 118, + 101, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121 + ] + } + ] + } + }, + { + "name": "program" + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "dstChain", + "type": "u32" + }, + { + "name": "dstAddress", + "type": "bytes" + }, + { + "name": "dstToken", + "type": "u32" + }, + { + "name": "ccmParameters", + "type": { + "option": { + "defined": { + "name": "ccmParams" + } + } + } + }, + { + "name": "cfParameters", + "type": "bytes" + } + ] + }, + { + "name": "xSwapTokenLegacy", + "discriminator": [ + 248, + 32, + 195, + 34, + 38, + 180, + 117, + 127 + ], + "accounts": [ + { + "name": "dataAccount" + }, + { + "name": "tokenVaultAssociatedTokenAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "data_account.token_vault_pda", + "account": "dataAccount" + }, + { + "kind": "const", + "value": [ + 6, + 221, + 246, + 225, + 215, + 101, + 161, + 147, + 217, + 203, + 225, + 70, + 206, + 235, + 121, + 172, + 28, + 180, + 133, + 237, + 95, + 91, + 55, + 145, + 58, + 140, + 245, + 133, + 126, + 255, + 0, + 169 + ] + }, + { + "kind": "account", + "path": "mint" + } + ], + "program": { + "kind": "const", + "value": [ + 140, + 151, + 37, + 143, + 78, + 36, + 137, + 241, + 187, + 61, + 16, + 41, + 20, + 142, + 13, + 131, + 11, + 90, + 19, + 153, + 218, + 255, + 16, + 132, + 4, + 142, + 123, + 216, + 219, + 233, + 248, + 89 + ] + } + } + }, + { + "name": "from", + "signer": true + }, + { + "name": "fromTokenAccount", + "writable": true + }, + { + "name": "tokenSupportedAccount" + }, + { + "name": "tokenProgram", + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "mint" + }, + { + "name": "eventAuthority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 95, + 95, + 101, + 118, + 101, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121 + ] + } + ] + } + }, + { + "name": "program" + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "dstChain", + "type": "u32" + }, + { + "name": "dstAddress", + "type": "bytes" + }, + { + "name": "dstToken", + "type": "u32" + }, + { + "name": "ccmParameters", + "type": { + "option": { + "defined": { + "name": "ccmParams" + } + } + } + }, + { + "name": "cfParameters", + "type": "bytes" + }, + { + "name": "decimals", + "type": "u8" + } + ] + } + ], + "accounts": [ + { + "name": "dataAccount", + "discriminator": [ + 85, + 240, + 182, + 158, + 76, + 7, + 18, + 233 + ] + }, + { + "name": "depositChannelHistoricalFetch", + "discriminator": [ + 188, + 68, + 197, + 38, + 48, + 192, + 81, + 100 + ] + }, + { + "name": "supportedToken", + "discriminator": [ + 56, + 162, + 96, + 99, + 193, + 245, + 204, + 108 + ] + } + ], + "events": [ + { + "name": "aggKeyRotated", + "discriminator": [ + 133, + 39, + 145, + 216, + 63, + 154, + 134, + 245 + ] + }, + { + "name": "govKeyRotated", + "discriminator": [ + 71, + 44, + 22, + 197, + 63, + 250, + 150, + 83 + ] + }, + { + "name": "govKeySetByAggKey", + "discriminator": [ + 135, + 202, + 24, + 202, + 91, + 182, + 141, + 24 + ] + }, + { + "name": "govKeySetByGovKey", + "discriminator": [ + 198, + 58, + 153, + 108, + 67, + 162, + 174, + 167 + ] + }, + { + "name": "programSwapsParametersSet", + "discriminator": [ + 173, + 82, + 238, + 223, + 74, + 121, + 243, + 142 + ] + }, + { + "name": "suspended", + "discriminator": [ + 220, + 179, + 163, + 2, + 249, + 252, + 157, + 102 + ] + }, + { + "name": "swapEvent", + "discriminator": [ + 64, + 198, + 205, + 232, + 38, + 8, + 113, + 226 + ] + }, + { + "name": "tokenSupportDisabled", + "discriminator": [ + 35, + 252, + 131, + 176, + 50, + 103, + 135, + 13 + ] + }, + { + "name": "tokenSupportEnabled", + "discriminator": [ + 11, + 203, + 178, + 141, + 170, + 213, + 67, + 234 + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "invalidTokenVaultAccount", + "msg": "Token Vault pda account does not match the expected program id" + }, + { + "code": 6001, + "name": "suspended", + "msg": "Vault program is suspended" + }, + { + "code": 6002, + "name": "invalidRemainingAccount", + "msg": "An invalid account is provided as a remaining account" + }, + { + "code": 6003, + "name": "invalidRemainingAccountSigner", + "msg": "A remaining account can't be a signer" + }, + { + "code": 6004, + "name": "unchangedSuspendedState", + "msg": "Suspended state unchanged" + }, + { + "code": 6005, + "name": "invalidSwapParameters", + "msg": "Invalid swap parameters" + }, + { + "code": 6006, + "name": "invalidTokenVaultBump", + "msg": "Invalid token vault bump" + }, + { + "code": 6007, + "name": "invalidUpgradeSignerPda", + "msg": "Invalid upgrade signer pda" + }, + { + "code": 6008, + "name": "invalidUpgradeSignerPdaBump", + "msg": "Invalid upgrade signer bump" + }, + { + "code": 6009, + "name": "suspendedIxSwaps", + "msg": "Instruction swaps are suspended" + }, + { + "code": 6010, + "name": "suspendedEventSwaps", + "msg": "Event swaps are suspended" + }, + { + "code": 6011, + "name": "nativeAmountBelowMinimumSwapAmount", + "msg": "Native amount below minimum swap amount" + }, + { + "code": 6012, + "name": "tokenAmountBelowMinimumSwapAmount", + "msg": "Token amount below minimum swap amount" + }, + { + "code": 6013, + "name": "destinationAddressExceedsMaxLength", + "msg": "Destination address exceeds max length" + }, + { + "code": 6014, + "name": "cfParametersExceedsMaxLength", + "msg": "Cf Parameters exceeds max length" + }, + { + "code": 6015, + "name": "ccmMessageExceedsMaxLength", + "msg": "Ccm message exceeds max length" + } + ], + "types": [ + { + "name": "aggKeyRotated", + "type": { + "kind": "struct", + "fields": [ + { + "name": "oldAggKey", + "type": "pubkey" + }, + { + "name": "newAggKey", + "type": "pubkey" + } + ] + } + }, + { + "name": "ccmParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "message", + "type": "bytes" + }, + { + "name": "gasAmount", + "type": "u64" + } + ] + } + }, + { + "name": "dataAccount", + "docs": [ + "* ****************************************************************************\n * *************************** IMPORTANT NOTE *********************************\n * ****************************************************************************\n * If the vault is upgraded and the DataAccount struct is modified we need to\n * check the compatibility and ensure there is a proper migration process, given\n * that the Vault bytecode is the only thing being upgraded, not the data account.\n *\n * The easiest approach on upgrade is keeping the DataAccount unchanged and use\n * a new account struct for any new data that is required.\n *\n * DO NOT MODIFY THIS WITHOUT UNDERSTANDING THE CONSEQUENCES!\n * ****************************************************************************\n * ****************************************************************************" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "aggKey", + "type": "pubkey" + }, + { + "name": "govKey", + "type": "pubkey" + }, + { + "name": "tokenVaultPda", + "type": "pubkey" + }, + { + "name": "tokenVaultBump", + "type": "u8" + }, + { + "name": "upgradeSignerPda", + "type": "pubkey" + }, + { + "name": "upgradeSignerPdaBump", + "type": "u8" + }, + { + "name": "suspended", + "type": "bool" + }, + { + "name": "suspendedLegacySwaps", + "type": "bool" + }, + { + "name": "suspendedEventSwaps", + "type": "bool" + }, + { + "name": "minNativeSwapAmount", + "type": "u64" + }, + { + "name": "maxDstAddressLen", + "type": "u16" + }, + { + "name": "maxCcmMessageLen", + "type": "u32" + }, + { + "name": "maxCfParametersLen", + "type": "u32" + }, + { + "name": "maxEventAccounts", + "type": "u32" + } + ] + } + }, + { + "name": "depositChannelHistoricalFetch", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u128" + } + ] + } + }, + { + "name": "govKeyRotated", + "type": { + "kind": "struct", + "fields": [ + { + "name": "oldGovKey", + "type": "pubkey" + }, + { + "name": "newGovKey", + "type": "pubkey" + } + ] + } + }, + { + "name": "govKeySetByAggKey", + "type": { + "kind": "struct", + "fields": [ + { + "name": "oldGovKey", + "type": "pubkey" + }, + { + "name": "newGovKey", + "type": "pubkey" + } + ] + } + }, + { + "name": "govKeySetByGovKey", + "type": { + "kind": "struct", + "fields": [ + { + "name": "oldGovKey", + "type": "pubkey" + }, + { + "name": "newGovKey", + "type": "pubkey" + } + ] + } + }, + { + "name": "programSwapsParametersSet", + "type": { + "kind": "struct", + "fields": [ + { + "name": "oldMinSwapAmount", + "type": "u64" + }, + { + "name": "oldMaxDstAddressLen", + "type": "u16" + }, + { + "name": "oldMaxCcmMessageLen", + "type": "u32" + }, + { + "name": "oldMaxCfParametersLen", + "type": "u32" + }, + { + "name": "oldMaxEventAccounts", + "type": "u32" + }, + { + "name": "newMinSwapAmount", + "type": "u64" + }, + { + "name": "newMaxDstAddressLen", + "type": "u16" + }, + { + "name": "newMaxCcmMessageLen", + "type": "u32" + }, + { + "name": "newMaxCfParametersLen", + "type": "u32" + }, + { + "name": "newMaxEventAccounts", + "type": "u32" + } + ] + } + }, + { + "name": "supportedToken", + "type": { + "kind": "struct", + "fields": [ + { + "name": "tokenMintPubkey", + "type": "pubkey" + }, + { + "name": "minSwapAmount", + "type": "u64" + } + ] + } + }, + { + "name": "suspended", + "type": { + "kind": "struct", + "fields": [ + { + "name": "suspended", + "type": "bool" + }, + { + "name": "suspendedLegacySwaps", + "type": "bool" + }, + { + "name": "suspendedEventSwaps", + "type": "bool" + } + ] + } + }, + { + "name": "swapEvent", + "type": { + "kind": "struct", + "fields": [ + { + "name": "dstChain", + "type": "u32" + }, + { + "name": "dstAddress", + "type": "bytes" + }, + { + "name": "dstToken", + "type": "u32" + }, + { + "name": "srcToken", + "type": { + "option": "pubkey" + } + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "sender", + "type": "pubkey" + }, + { + "name": "ccmParameters", + "type": { + "option": { + "defined": { + "name": "ccmParams" + } + } + } + }, + { + "name": "cfParameters", + "type": "bytes" + } + ] + } + }, + { + "name": "tokenSupportDisabled", + "type": { + "kind": "struct", + "fields": [ + { + "name": "oldTokenSupported", + "type": { + "defined": { + "name": "supportedToken" + } + } + } + ] + } + }, + { + "name": "tokenSupportEnabled", + "type": { + "kind": "struct", + "fields": [ + { + "name": "oldTokenSupported", + "type": { + "defined": { + "name": "supportedToken" + } + } + }, + { + "name": "newTokenSupported", + "type": { + "defined": { + "name": "supportedToken" + } + } + } + ] + } + } + ] +}; diff --git a/state-chain/cf-integration-tests/src/solana.rs b/state-chain/cf-integration-tests/src/solana.rs index d6753189e9..67631fb206 100644 --- a/state-chain/cf-integration-tests/src/solana.rs +++ b/state-chain/cf-integration-tests/src/solana.rs @@ -75,6 +75,8 @@ fn setup_sol_environments() { token_vault_pda_account: sol_test_values::TOKEN_VAULT_PDA_ACCOUNT, usdc_token_mint_pubkey: sol_test_values::USDC_TOKEN_MINT_PUB_KEY, usdc_token_vault_ata: sol_test_values::USDC_TOKEN_VAULT_ASSOCIATED_TOKEN_ACCOUNT, + swap_endpoint_program: sol_test_values::SWAP_ENDPOINT_PROGRAM, + swap_endpoint_program_data_account: sol_test_values::SWAP_ENDPOINT_PROGRAM_DATA_ACCOUNT, }); // Environment::AvailableDurableNonces diff --git a/state-chain/chains/src/sol.rs b/state-chain/chains/src/sol.rs index fa583e5762..7a4d4e8494 100644 --- a/state-chain/chains/src/sol.rs +++ b/state-chain/chains/src/sol.rs @@ -153,6 +153,8 @@ pub mod compute_units_costs { pub const COMPUTE_UNITS_PER_ROTATION: SolComputeLimit = 8_000u32; pub const COMPUTE_UNITS_PER_SET_GOV_KEY: SolComputeLimit = 15_000u32; pub const COMPUTE_UNITS_PER_BUMP_DERIVATION: SolComputeLimit = 2_000u32; + pub const COMPUTE_UNITS_PER_CLOSE_EVENT_ACCOUNTS: SolComputeLimit = 10_000u32; + pub const COMPUTE_UNITS_PER_CLOSE_ACCOUNT: SolComputeLimit = 10_000u32; /// This is equivalent to a priority fee pub const MIN_COMPUTE_PRICE: SolAmount = 10u64; @@ -389,6 +391,10 @@ pub struct SolApiEnvironment { // For Usdc token pub usdc_token_mint_pubkey: SolAddress, pub usdc_token_vault_ata: SolAddress, + + // For program swaps API calls. + pub swap_endpoint_program: SolAddress, + pub swap_endpoint_program_data_account: SolAddress, } impl DepositDetailsToTransactionInId for () {} diff --git a/state-chain/chains/src/sol/api.rs b/state-chain/chains/src/sol/api.rs index 174a959859..543db442d8 100644 --- a/state-chain/chains/src/sol/api.rs +++ b/state-chain/chains/src/sol/api.rs @@ -37,6 +37,7 @@ pub struct ApiEnvironment; pub struct CurrentAggKey; pub type DurableNonceAndAccount = (SolAddress, SolHash); +pub type EventAccountAndSender = (SolAddress, SolAddress); /// Super trait combining all Environment lookups required for the Solana chain. /// Also contains some calls for easy data retrieval. @@ -120,6 +121,7 @@ pub enum SolanaTransactionType { CcmTransfer { fallback: TransferAssetParams, }, + CloseEventAccounts, } /// The Solana Api call. Contains a call_type and the actual Transaction itself. @@ -382,6 +384,34 @@ impl SolanaApi { _phantom: Default::default(), }) } + + pub fn batch_close_event_accounts( + event_accounts: Vec, + ) -> Result { + // Lookup environment variables, such as aggkey and durable nonce. + let agg_key = Environment::current_agg_key()?; + let sol_api_environment = Environment::api_environment()?; + let compute_price = Environment::compute_price()?; + let durable_nonce = Environment::nonce_account()?; + + // Build the transaction + let transaction = SolanaTransactionBuilder::close_event_accounts( + event_accounts, + sol_api_environment.vault_program_data_account, + sol_api_environment.swap_endpoint_program, + sol_api_environment.swap_endpoint_program_data_account, + agg_key, + durable_nonce, + compute_price, + )?; + + Ok(Self { + call_type: SolanaTransactionType::CloseEventAccounts, + transaction, + signer: None, + _phantom: Default::default(), + }) + } } impl ApiCall for SolanaApi { diff --git a/state-chain/chains/src/sol/sol_tx_core.rs b/state-chain/chains/src/sol/sol_tx_core.rs index 14bddb13a8..2cb86ed8c5 100644 --- a/state-chain/chains/src/sol/sol_tx_core.rs +++ b/state-chain/chains/src/sol/sol_tx_core.rs @@ -909,6 +909,56 @@ pub mod sol_test_values { const_address("GUMpVpQFNYJvSbyTtUarZVL7UDUgErKzDTSVJhekUX55"), const_address("AUiHYbzH7qLZSkb3u7nAqtvqC7e41sEzgWjBEvXrpfGv"), ]; + pub const SWAP_ENDPOINT_PROGRAM: SolAddress = + const_address("35uYgHdfZQT4kHkaaXQ6ZdCkK5LFrsk43btTLbGCRCNT"); + pub const SWAP_ENDPOINT_PROGRAM_DATA_ACCOUNT: SolAddress = + const_address("2tmtGLQcBd11BMiE9B1tAkQXwmPNgR79Meki2Eme4Ec9"); + pub const EVENT_AND_SENDER_ACCOUNTS: [(SolAddress, SolAddress); 11] = [ + ( + const_address("2cHcSNtikMpjxJfwwoYL3udpy7hedRExyhakk2eZ6cYA"), + const_address("7tVhSXxGfZyHQem8MdZVB6SoRsrvV4H8h1rX6hwBuvEA"), + ), + ( + const_address("6uuU1NFyThN3KJpU9mYXkGSmd8Qgncmd9aYAWYN71VkC"), + const_address("P3GYr1Z67jdBVimzFjMXQpeuew5TY5txoZ9CvqASpaP"), + ), + ( + const_address("DmAom3kp2ZKk9cnbWEsnbkLHkp3sx9ef1EX6GWj1JRUB"), + const_address("CS7yX5TKX36ugF4bycmVQ5vqB2ZbNVC5tvtrtLP92GDW"), + ), + ( + const_address("CJSdHgxwHLEbTsxKsJk9UyJxUEgku2UC9GXRTzR2ieSh"), + const_address("2taCR53epDtdrFZBxzKcbmv3cb5Umc5x9k2YCjmTDAnH"), + ), + ( + const_address("7DGwjsQEFA7XzZS9z5YbMhYGzWJSh5T78hRrU47RDTd2"), + const_address("FDPzoZj951Hq92jhoFdyzAVyUjyXhL8VEnqBhyjsDhow"), + ), + ( + const_address("A6yYXUmZHa32mcFRnwwq8ZQKCEYUn9ewF1vWn2wsXN5a"), + const_address("9bNNNU9B52VPVGm6zRccwPEexDHD1ntndD2aNu2un3ca"), + ), + ( + const_address("2F3365PULNzt7moa9GgHARy7Lumj5ptDQF7wDt6xeuHK"), + const_address("4m5t38fJsvULKaPyWZKWjzfbvnzBGL86BTRNk5vLLUrh"), + ), + ( + const_address("8sCBWv9tzdf2iC4GNj61UBN6TZpzsLP5Ppv9x1ENX4HT"), + const_address("A3P5kfRU1vgZn7GjNMomS8ye6GHsoHC4JoVNUotMbDPE"), + ), + ( + const_address("3b1FkNvnvKJ4TzKeft7wA47VfYpjkoHPE4ER13ZTNecX"), + const_address("ERwuPnX66dCZqj85kH9QQJmwcVrzcczBnu8onJY2R7tG"), + ), + ( + const_address("Bnrp9X562krXVfaY8FnwJa3Mxp1gbDCrvGNW1qc99rKe"), + const_address("2aoZg41FFnTBnuHpkfHdFsCuPz8DhN4dsUW5386XwE8g"), + ), + ( + const_address("EuLceVgXMaJNPT7C88pnL7DRWcf1poy9BCeWY1GL8Agd"), + const_address("G1iXMtwUU76JGau9cJm6N8wBTmcsvyXuJcC7PtfU1TXZ"), + ), + ]; pub const RAW_KEYPAIR: [u8; 32] = [ 6, 151, 150, 20, 145, 210, 176, 113, 98, 200, 192, 80, 73, 63, 133, 232, 208, 124, 81, 213, 117, 199, 196, 243, 219, 33, 79, 217, 157, 69, 205, 140, diff --git a/state-chain/chains/src/sol/sol_tx_core/program_instructions.rs b/state-chain/chains/src/sol/sol_tx_core/program_instructions.rs index 54bcd4327c..dccf261237 100644 --- a/state-chain/chains/src/sol/sol_tx_core/program_instructions.rs +++ b/state-chain/chains/src/sol/sol_tx_core/program_instructions.rs @@ -629,6 +629,28 @@ solana_program!( } ); +pub mod swap_endpoints { + use super::*; + + solana_program!( + idl_path: concat!( + env!("CF_SOL_PROGRAM_IDL_ROOT"), "/", + env!("CF_SOL_PROGRAM_IDL_TAG"), "/" , + "swap_endpoint.json" + ), + SwapEndpointProgram { + close_event_accounts => CloseEventAccounts { + args: [], + account_metas: [ + data_account: { signer: false, writable: false }, + agg_key: { signer: true, writable: true }, + swap_endpoint_data_account: { signer: false, writable: true }, + ] + }, + } + ); +} + #[cfg(test)] mod idl { use serde::{Deserialize, Serialize}; diff --git a/state-chain/chains/src/sol/transaction_builder.rs b/state-chain/chains/src/sol/transaction_builder.rs index 71ff3a61ac..1bc32d9adc 100644 --- a/state-chain/chains/src/sol/transaction_builder.rs +++ b/state-chain/chains/src/sol/transaction_builder.rs @@ -11,10 +11,11 @@ use sol_prim::consts::{ use crate::{ sol::{ - api::{DurableNonceAndAccount, SolanaTransactionBuildingError}, + api::{DurableNonceAndAccount, EventAccountAndSender, SolanaTransactionBuildingError}, compute_units_costs::{ compute_limit_with_buffer, BASE_COMPUTE_UNITS_PER_TX, - COMPUTE_UNITS_PER_BUMP_DERIVATION, COMPUTE_UNITS_PER_FETCH_NATIVE, + COMPUTE_UNITS_PER_BUMP_DERIVATION, COMPUTE_UNITS_PER_CLOSE_ACCOUNT, + COMPUTE_UNITS_PER_CLOSE_EVENT_ACCOUNTS, COMPUTE_UNITS_PER_FETCH_NATIVE, COMPUTE_UNITS_PER_FETCH_TOKEN, COMPUTE_UNITS_PER_ROTATION, COMPUTE_UNITS_PER_SET_GOV_KEY, COMPUTE_UNITS_PER_TRANSFER_NATIVE, COMPUTE_UNITS_PER_TRANSFER_TOKEN, @@ -22,8 +23,12 @@ use crate::{ sol_tx_core::{ address_derivation::{derive_associated_token_account, derive_fetch_account}, compute_budget::ComputeBudgetInstruction, - program_instructions::{InstructionExt, SystemProgramInstruction, VaultProgram}, + program_instructions::{ + swap_endpoints::SwapEndpointProgram, InstructionExt, SystemProgramInstruction, + VaultProgram, + }, token_instructions::AssociatedTokenAccountInstruction, + AccountMeta, }, AccountBump, SolAddress, SolAmount, SolApiEnvironment, SolAsset, SolCcmAccounts, SolComputeLimit, SolInstruction, SolMessage, SolPubkey, SolTransaction, Solana, @@ -437,6 +442,45 @@ impl SolanaTransactionBuilder { compute_limit_with_buffer(COMPUTE_UNITS_PER_SET_GOV_KEY), ) } + + /// Creates an instruction to close a number of open event swap accounts created via program + /// swap. + pub fn close_event_accounts( + event_accounts: Vec, + vault_program_data_account: SolAddress, + swap_endpoint_program: SolAddress, + swap_endpoint_data_account: SolAddress, + agg_key: SolAddress, + durable_nonce: DurableNonceAndAccount, + compute_price: SolAmount, + ) -> Result { + let number_of_accounts = event_accounts.len(); + let event_and_sender_vec: Vec = event_accounts + .into_iter() + // Both event account and payee should be writable and non-signers + .flat_map(|(event_account, payee)| { + vec![ + AccountMeta::new(event_account.into(), false), + AccountMeta::new(payee.into(), false), + ] + }) + .collect(); + + let instructions = vec![SwapEndpointProgram::with_id(swap_endpoint_program) + .close_event_accounts(vault_program_data_account, agg_key, swap_endpoint_data_account) + .with_remaining_accounts(event_and_sender_vec)]; + + Self::build( + instructions, + durable_nonce, + agg_key.into(), + compute_price, + compute_limit_with_buffer( + COMPUTE_UNITS_PER_CLOSE_EVENT_ACCOUNTS + + COMPUTE_UNITS_PER_CLOSE_ACCOUNT * number_of_accounts as u32, + ), + ) + } } #[cfg(test)] @@ -487,6 +531,8 @@ mod test { token_vault_pda_account: TOKEN_VAULT_PDA_ACCOUNT, usdc_token_mint_pubkey: USDC_TOKEN_MINT_PUB_KEY, usdc_token_vault_ata: USDC_TOKEN_VAULT_ASSOCIATED_TOKEN_ACCOUNT, + swap_endpoint_program: SWAP_ENDPOINT_PROGRAM, + swap_endpoint_program_data_account: SWAP_ENDPOINT_PROGRAM_DATA_ACCOUNT, } } @@ -672,12 +718,54 @@ mod test { ) .unwrap(); - // Serialized tx built in `create_full_rotation` test + // Serialized tx built in `rotate_agg_key` test let expected_serialized_tx = hex_literal::hex!("0180d9ae78d86dbf0895772b959d27110d09d8cb0f9bb388cbc84a53372b568ea56cb9f235f05bf59446a18b9e9babdf61e7194cd6f838d6fd6a741e6f60cc300d01000411f79d5e026f12edc6443a534b2cdd5072233989b415d7596573e743f3e5b386fb0e14940a2247d0a8a33650d7dfe12d269ecabce61c1219b5a6dcdb6961026e0917eb2b10d3377bda2bc7bea65bec6b8372f4fc3463ec2cd6f9fde4b2c633d1926744e9d9790761c45a800a074687b5ff47b449a90c722a3852543be5439900448541f57201f277c5f3ffb631d0212e26e7f47749c26c4808718174a0ab2a09a18cd28baa84f2067bbdf24513c2d44e44bf408f2e6da6e60762e3faa4a62a0adbcd644e45426a41a7cb8369b8a0c1c89bb3f86cf278fdd9cc38b0f69784ad5667e392cd98d3284fd551604be95c14cc8e20123e2940ef9fb784e6b591c7442864e5e1869817a4fd88ddf7ab7a5f7252d7c345b39721769888608592912e8ca9acf0f13460b3fd04b7d53d7421fc874ec00eec769cf36480895e1a407bf1249475f2b2e24122be016983be9369965246cc45e1f621d40fba300c56c7ac50c3874df4f83bd213a59c9785110cf83c718f9486c3484f918593bce20c61dc6a96036afecc89e3b031824af6363174d19bbec12d3a13c4a173e5aeb349b63042bc138f00000000000000000000000000000000000000000000000000000000000000000306466fe5211732ffecadba72c39be7bc8ce5bbc5f7126b2c439b3a4000000006a7d517192c568ee08a845f73d29788cf035c3145b21ab344d8062ea940000072b5d2051d300b10b74314b7e25ace9998ca66eb2c7fbc10ef130dd67028293cc27e9074fac5e8d36cf04f94a0606fdd8ddbb420e99a489c7915ce5699e489000e0d03020f0004040000000e00090340420f00000000000e000502e02e000010040100030d094e518fabdda5d68b000d02020024070000006744e9d9790761c45a800a074687b5ff47b449a90c722a3852543be5439900440d020b0024070000006744e9d9790761c45a800a074687b5ff47b449a90c722a3852543be5439900440d02090024070000006744e9d9790761c45a800a074687b5ff47b449a90c722a3852543be5439900440d020a0024070000006744e9d9790761c45a800a074687b5ff47b449a90c722a3852543be5439900440d02070024070000006744e9d9790761c45a800a074687b5ff47b449a90c722a3852543be5439900440d02060024070000006744e9d9790761c45a800a074687b5ff47b449a90c722a3852543be5439900440d02040024070000006744e9d9790761c45a800a074687b5ff47b449a90c722a3852543be5439900440d020c0024070000006744e9d9790761c45a800a074687b5ff47b449a90c722a3852543be5439900440d02080024070000006744e9d9790761c45a800a074687b5ff47b449a90c722a3852543be5439900440d02050024070000006744e9d9790761c45a800a074687b5ff47b449a90c722a3852543be543990044").to_vec(); test_constructed_transaction(transaction, expected_serialized_tx); } + #[test] + fn can_close_event_accounts() { + let env = api_env(); + let event_accounts = vec![EVENT_AND_SENDER_ACCOUNTS[0]]; + let transaction = SolanaTransactionBuilder::close_event_accounts( + event_accounts, + env.vault_program_data_account, + env.swap_endpoint_program, + env.swap_endpoint_program_data_account, + agg_key(), + durable_nonce(), + compute_price(), + ) + .unwrap(); + + // Serialized tx built in `close_event_accounts` test + let expected_serialized_tx = hex_literal::hex!("01026e2d4bdca9e638b59507a70ea62ad88f098ffb25df028a19288702698fdf6d1cf77618b2123c0205a8e8d272ba8ea645b7e75c606ca3aa4356b65fa52ca20b0100050af79d5e026f12edc6443a534b2cdd5072233989b415d7596573e743f3e5b386fb17e5cc1f4d51a40626e11c783b75a45a4922615ecd7f5320b9d4d46481a196a317eb2b10d3377bda2bc7bea65bec6b8372f4fc3463ec2cd6f9fde4b2c633d1921c1f0efc91eeb48bb80c90cf97775cd5d843a96f16500266cee2c20d053152d2665730decf59d4cd6db8437dab77302287431eb7562b5997601851a0eab6946f00000000000000000000000000000000000000000000000000000000000000000306466fe5211732ffecadba72c39be7bc8ce5bbc5f7126b2c439b3a4000000006a7d517192c568ee08a845f73d29788cf035c3145b21ab344d8062ea94000000e14940a2247d0a8a33650d7dfe12d269ecabce61c1219b5a6dcdb6961026e091ef91c791d2aa8492c90f12540abd10056ce5dd8d9ab08461476c1dcc1622938c27e9074fac5e8d36cf04f94a0606fdd8ddbb420e99a489c7915ce5699e4890004050302070004040000000600090340420f000000000006000502307500000905080003010408a5663d01b94dbd79").to_vec(); + + test_constructed_transaction(transaction, expected_serialized_tx); + } + + #[test] + fn can_close_max_event_accounts() { + let env = api_env(); + + // We can close 11 accounts without reaching the transaction length limit. + let transaction = SolanaTransactionBuilder::close_event_accounts( + EVENT_AND_SENDER_ACCOUNTS.to_vec(), + env.vault_program_data_account, + env.swap_endpoint_program, + env.swap_endpoint_program_data_account, + agg_key(), + durable_nonce(), + compute_price(), + ) + .unwrap(); + + let expected_serialized_tx = hex_literal::hex!("01361c7baab92d2d4599136442ad7d4c1d51fedc6749d44f3a8e8405cc19983862c885526b293ed79d0253d44e174705db9050638d1ffc31b6f7b586b269fea4030100051ef79d5e026f12edc6443a534b2cdd5072233989b415d7596573e743f3e5b386fb05a557a331e51b8bf444d3bacdf6f48d8fd583aa79f9b956dd68f13a67ad096412741ecfad8423dea0c173b354b32309c3e97bb1dc68e0d858c3caebc1a1701a178480c19a99c9f2b95d40ebcb55057a49f0df00e123da6ae5e85a77c282f7c117e5cc1f4d51a40626e11c783b75a45a4922615ecd7f5320b9d4d46481a196a317eb2b10d3377bda2bc7bea65bec6b8372f4fc3463ec2cd6f9fde4b2c633d1921c11d80c98e8c11e79fd97b6c10ad733782bdbe25a710b807bbf14dedaa314861c1f0efc91eeb48bb80c90cf97775cd5d843a96f16500266cee2c20d053152d2266d68abb283ba2f4cecb092e3cfed2cb1774468ebbc264426c268ff405aa5a837de225793278f0575804f7d969e1980caaa5c5ddb2aebfd8496b14e71c9fad657d7f5b3e6c340824caca3b6c34c03e2fe0e636430b2b729ddfe32146ba4b3795c4b1e73c84b8d3f9e006c22fe8b865b9900e296345d88cdaaa7077ef17d9a31665730decf59d4cd6db8437dab77302287431eb7562b5997601851a0eab6946f74dd7ddee33a59ae7431bb31fbeb738cbfd097a66fd6706cffe7fc7efb239ec67fab67806fbb92ffd9504f4411b7f4561a0efb16685e4a22c41373fedc50b4bf86554fe5208d48fc8198310804e59837443fdaab12ea97be0fa38049910da82987410536ffebba5f49e67bafd3aa4b6cc860a594641e801500e058f74bac504da054544b2425f722e18c810bbc6cb6b9045d0db0a62d529af30efde8c37255bda7e867ab720f01897e5ede67fc232e41729d0be2a530391619743822ff6d95bea9dff663e1d13345d96daede8066cd30a1474635f2d64052d1a50ac04aed3f99bd9ce2f9674b65bfaefb62c9b8252fd0080357b1cbff44d0dad8568535dbc230c78bf2e7aee8e16631746542ef634cee3ac9bdc044c491f06862590ff1029865ce904f76d0a0ffedad66f8e2c94bccc731cac372fef8bb12cd2c473d95acf366d33096c9d0fa193639345c07abfe81175fc4d153cf0ab7b5668006538f195382df0e412e53b45bf52f91fa8e70ea872687428e4cb372306b9e6073f8d3c270c400000000000000000000000000000000000000000000000000000000000000000306466fe5211732ffecadba72c39be7bc8ce5bbc5f7126b2c439b3a4000000006a7d517192c568ee08a845f73d29788cf035c3145b21ab344d8062ea94000000e14940a2247d0a8a33650d7dfe12d269ecabce61c1219b5a6dcdb6961026e091ef91c791d2aa8492c90f12540abd10056ce5dd8d9ab08461476c1dcc1622938c27e9074fac5e8d36cf04f94a0606fdd8ddbb420e99a489c7915ce5699e48900041903051b0004040000001a00090340420f00000000001a00050220bf02001d191c0007040c0a01141312060b17100e02090d0f08151103161808a5663d01b94dbd79").to_vec(); + + test_constructed_transaction(transaction, expected_serialized_tx); + } + #[test] fn can_calculate_gas_limit() { const TEST_EGRESS_BUDGET: SolAmount = 500_000; diff --git a/state-chain/node/src/chain_spec.rs b/state-chain/node/src/chain_spec.rs index 126ed02d02..c3b2ec6c9e 100644 --- a/state-chain/node/src/chain_spec.rs +++ b/state-chain/node/src/chain_spec.rs @@ -111,6 +111,8 @@ pub struct StateChainEnvironment { sol_durable_nonces_and_accounts: [DurableNonceAndAccount; 10], /* we inject 10 nonce * accounts * at genesis */ + sol_swap_endpoint_program: SolAddress, + sol_swap_endpoint_program_data_account: SolAddress, } /// Get the values from the State Chain's environment variables. Else set them via the defaults @@ -156,6 +158,12 @@ pub fn get_environment_or_defaults(defaults: StateChainEnvironment) -> StateChai from_env_var!(FromStr::from_str, SOL_TOKEN_VAULT_PDA_ACCOUNT, sol_token_vault_pda_account); from_env_var!(FromStr::from_str, SOL_USDC_TOKEN_MINT_PUBKEY, sol_usdc_token_mint_pubkey); from_env_var!(FromStr::from_str, SOL_USDC_TOKEN_VAULT_ATA, sol_usdc_token_vault_ata); + from_env_var!(FromStr::from_str, SOL_SWAP_ENDPOINT_PROGRAM, sol_swap_endpoint_program); + from_env_var!( + FromStr::from_str, + SOL_SWAP_ENDPOINT_PROGRAM_DATA_ACCOUNT, + sol_swap_endpoint_program_data_account + ); let dot_genesis_hash = match env::var("DOT_GENESIS_HASH") { Ok(s) => hex_decode::<32>(&s).unwrap().into(), @@ -216,6 +224,8 @@ pub fn get_environment_or_defaults(defaults: StateChainEnvironment) -> StateChai sol_token_vault_pda_account, sol_usdc_token_vault_ata, sol_durable_nonces_and_accounts, + sol_swap_endpoint_program, + sol_swap_endpoint_program_data_account, } } @@ -283,6 +293,8 @@ pub fn inner_cf_development_config( sol_token_vault_pda_account, sol_usdc_token_vault_ata, sol_durable_nonces_and_accounts, + sol_swap_endpoint_program, + sol_swap_endpoint_program_data_account, } = get_environment_or_defaults(testnet::ENV); Ok(ChainSpec::builder(wasm_binary, Default::default()) .with_name("CF Develop") @@ -320,6 +332,8 @@ pub fn inner_cf_development_config( usdc_token_mint_pubkey: sol_usdc_token_mint_pubkey, token_vault_pda_account: sol_token_vault_pda_account, usdc_token_vault_ata: sol_usdc_token_vault_ata, + swap_endpoint_program: sol_swap_endpoint_program, + swap_endpoint_program_data_account: sol_swap_endpoint_program_data_account, }, sol_durable_nonces_and_accounts: sol_durable_nonces_and_accounts.to_vec(), network_environment: NetworkEnvironment::Development, @@ -409,6 +423,8 @@ macro_rules! network_spec { sol_token_vault_pda_account, sol_usdc_token_vault_ata, sol_durable_nonces_and_accounts, + sol_swap_endpoint_program, + sol_swap_endpoint_program_data_account, } = env_override.unwrap_or(ENV); let protocol_id = format!( "{}-{}", @@ -478,6 +494,9 @@ macro_rules! network_spec { usdc_token_mint_pubkey: sol_usdc_token_mint_pubkey, token_vault_pda_account: sol_token_vault_pda_account, usdc_token_vault_ata: sol_usdc_token_vault_ata, + swap_endpoint_program: sol_swap_endpoint_program, + swap_endpoint_program_data_account: + sol_swap_endpoint_program_data_account, }, network_environment: NETWORK_ENVIRONMENT, ..Default::default() diff --git a/state-chain/node/src/chain_spec/berghain.rs b/state-chain/node/src/chain_spec/berghain.rs index c14552b4b8..567c4518b5 100644 --- a/state-chain/node/src/chain_spec/berghain.rs +++ b/state-chain/node/src/chain_spec/berghain.rs @@ -106,6 +106,12 @@ pub const ENV: StateChainEnvironment = StateChainEnvironment { const_hash("AEzmj9wq8jp7wF46Lrr3Jc2K7xRP58V5Y3cYRVEqtE5J"), ), ], + sol_swap_endpoint_program: SolAddress(bs58_array( + "BnECXbsDFYPmhxcV57dodaWtJJjtGPE8Le3LAR7qieYb", + )), + sol_swap_endpoint_program_data_account: SolAddress(bs58_array( + "5mFsKrqCH5v9Q9uF5o6qrsUi1GV2myuhc23NAi5YFs4M", + )), }; pub const EPOCH_DURATION_BLOCKS: BlockNumber = 24 * HOURS; diff --git a/state-chain/node/src/chain_spec/perseverance.rs b/state-chain/node/src/chain_spec/perseverance.rs index 2edd780202..4d08adc614 100644 --- a/state-chain/node/src/chain_spec/perseverance.rs +++ b/state-chain/node/src/chain_spec/perseverance.rs @@ -106,6 +106,12 @@ pub const ENV: StateChainEnvironment = StateChainEnvironment { const_hash("FS1PdTqsDSEa9xUrLAS5k471MQsT28H2FW5CpUHiTmGF"), ), ], + sol_swap_endpoint_program: SolAddress(bs58_array( + "FXN1iLmQ47c962nackmzBWZxXE8BR9AXy8mu34oFdKiy", + )), + sol_swap_endpoint_program_data_account: SolAddress(bs58_array( + "4hD7UM6rQtcqQWtzELvrafpmBYReVXvCpssB6qjY1Sg5", + )), }; pub const EPOCH_DURATION_BLOCKS: BlockNumber = 24 * HOURS; diff --git a/state-chain/node/src/chain_spec/sisyphos.rs b/state-chain/node/src/chain_spec/sisyphos.rs index 0bd660c80a..c8a470cd66 100644 --- a/state-chain/node/src/chain_spec/sisyphos.rs +++ b/state-chain/node/src/chain_spec/sisyphos.rs @@ -107,6 +107,12 @@ pub const ENV: StateChainEnvironment = StateChainEnvironment { const_hash("3iiniRfNTFmBn6Y9ZhovefUDaGaJ7buB2vYemnbFoHN3"), ), ], + sol_swap_endpoint_program: SolAddress(bs58_array( + "7G6TxoGDsgaZX3HaKkrKyy28tsdr7ZGmeeMbXpm8R5HZ", + )), + sol_swap_endpoint_program_data_account: SolAddress(bs58_array( + "mYabVW1uMXpGqwgHUBQu4Fg6GT9EMYUzYaGYbi3zgT7", + )), }; pub const BASHFUL_ACCOUNT_ID: &str = "cFLbasoV5juCGacy9LvvwSgkupFiFmwt8RmAuA3xcaY5YmkBe"; diff --git a/state-chain/node/src/chain_spec/testnet.rs b/state-chain/node/src/chain_spec/testnet.rs index d0f1bfc37d..273b6099d9 100644 --- a/state-chain/node/src/chain_spec/testnet.rs +++ b/state-chain/node/src/chain_spec/testnet.rs @@ -102,6 +102,12 @@ pub const ENV: StateChainEnvironment = StateChainEnvironment { const_hash("Hgr7AdqH4nQiau7raNF2ShTZqUfnE3D5AMX2nwYzHuJT"), ), ], + sol_swap_endpoint_program: SolAddress(bs58_array( + "35uYgHdfZQT4kHkaaXQ6ZdCkK5LFrsk43btTLbGCRCNT", + )), + sol_swap_endpoint_program_data_account: SolAddress(bs58_array( + "2tmtGLQcBd11BMiE9B1tAkQXwmPNgR79Meki2Eme4Ec9", + )), }; pub const EPOCH_DURATION_BLOCKS: BlockNumber = 3 * HOURS; diff --git a/state-chain/pallets/cf-environment/Cargo.toml b/state-chain/pallets/cf-environment/Cargo.toml index d46fa6a0e1..61a214f4fa 100644 --- a/state-chain/pallets/cf-environment/Cargo.toml +++ b/state-chain/pallets/cf-environment/Cargo.toml @@ -23,6 +23,7 @@ serde = { workspace = true, features = ["derive", "alloc"] } hex-literal = { workspace = true } log = { workspace = true } cf-runtime-utilities = { workspace = true } +cf-utilities = { workspace = true } # Parity deps codec = { workspace = true, features = ["derive"] } @@ -54,6 +55,7 @@ std = [ "sp-std/std", "log/std", "cf-runtime-utilities/std", + "cf-utilities/std", ] runtime-benchmarks = [ "cf-chains/runtime-benchmarks", diff --git a/state-chain/pallets/cf-environment/src/lib.rs b/state-chain/pallets/cf-environment/src/lib.rs index 600f165278..c970816572 100644 --- a/state-chain/pallets/cf-environment/src/lib.rs +++ b/state-chain/pallets/cf-environment/src/lib.rs @@ -37,7 +37,7 @@ pub mod weights; pub use weights::WeightInfo; pub mod migrations; -pub const PALLET_VERSION: StorageVersion = StorageVersion::new(12); +pub const PALLET_VERSION: StorageVersion = StorageVersion::new(13); const INITIAL_CONSOLIDATION_PARAMETERS: utxo_selection::ConsolidationParameters = utxo_selection::ConsolidationParameters { diff --git a/state-chain/pallets/cf-environment/src/migrations.rs b/state-chain/pallets/cf-environment/src/migrations.rs index c144571bf8..3c7a2aedf7 100644 --- a/state-chain/pallets/cf-environment/src/migrations.rs +++ b/state-chain/pallets/cf-environment/src/migrations.rs @@ -2,12 +2,15 @@ use crate::{Config, Pallet}; #[cfg(feature = "try-runtime")] use crate::{CurrentReleaseVersion, Get}; use cf_runtime_utilities::PlaceholderMigration; -use frame_support::traits::OnRuntimeUpgrade; +use frame_support::{migrations::VersionedMigration, traits::OnRuntimeUpgrade}; #[cfg(feature = "try-runtime")] use frame_support::{pallet_prelude::DispatchError, sp_runtime}; #[cfg(feature = "try-runtime")] use sp_std::vec::Vec; +mod sol_api_environment; +pub use sol_api_environment::SolApiEnvironmentMigration; + pub struct VersionUpdate(sp_std::marker::PhantomData); impl OnRuntimeUpgrade for VersionUpdate { @@ -32,7 +35,17 @@ impl OnRuntimeUpgrade for VersionUpdate { } } -pub type PalletMigration = PlaceholderMigration<12, Pallet>; +// Migration for Updating Solana's Api Environments. +pub type PalletMigration = ( + VersionedMigration< + 12, + 13, + SolApiEnvironmentMigration, + Pallet, + ::DbWeight, + >, + PlaceholderMigration<13, Pallet>, +); #[cfg(test)] mod tests { diff --git a/state-chain/pallets/cf-environment/src/migrations/sol_api_environment.rs b/state-chain/pallets/cf-environment/src/migrations/sol_api_environment.rs new file mode 100644 index 0000000000..5f776cebff --- /dev/null +++ b/state-chain/pallets/cf-environment/src/migrations/sol_api_environment.rs @@ -0,0 +1,91 @@ +use crate::*; + +use frame_support::{pallet_prelude::Weight, traits::UncheckedOnRuntimeUpgrade}; + +use cf_chains::{evm::H256, sol::SolAddress}; +use cf_utilities::bs58_array; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; + +pub mod old { + use super::*; + use cf_chains::sol::SolAddress; + + #[derive(Encode, Decode, TypeInfo)] + pub struct SolApiEnvironment { + pub vault_program: SolAddress, + pub vault_program_data_account: SolAddress, + pub token_vault_pda_account: SolAddress, + pub usdc_token_mint_pubkey: SolAddress, + pub usdc_token_vault_ata: SolAddress, + } +} + +pub struct SolApiEnvironmentMigration(PhantomData); + +impl> UncheckedOnRuntimeUpgrade for SolApiEnvironmentMigration { + fn on_runtime_upgrade() -> Weight { + log::info!("🌮 Running migration for Environment pallet: Updating SolApiEnvironment."); + let _ = SolanaApiEnvironment::::translate::(|old_env| { + old_env.map( + |old::SolApiEnvironment { + vault_program, + vault_program_data_account, + token_vault_pda_account, + usdc_token_mint_pubkey, + usdc_token_vault_ata, + }| { + let (swap_endpoint_program, swap_endpoint_program_data_account) = + match cf_runtime_utilities::genesis_hashes::genesis_hash::() { + cf_runtime_utilities::genesis_hashes::BERGHAIN => ( + SolAddress(bs58_array( + "BnECXbsDFYPmhxcV57dodaWtJJjtGPE8Le3LAR7qieYb", + )), + SolAddress(bs58_array( + "5mFsKrqCH5v9Q9uF5o6qrsUi1GV2myuhc23NAi5YFs4M", + )), + ), + cf_runtime_utilities::genesis_hashes::PERSEVERANCE => ( + SolAddress(bs58_array( + "FXN1iLmQ47c962nackmzBWZxXE8BR9AXy8mu34oFdKiy", + )), + SolAddress(bs58_array( + "4hD7UM6rQtcqQWtzELvrafpmBYReVXvCpssB6qjY1Sg5", + )), + ), + cf_runtime_utilities::genesis_hashes::SISYPHOS => ( + SolAddress(bs58_array( + "7G6TxoGDsgaZX3HaKkrKyy28tsdr7ZGmeeMbXpm8R5HZ", + )), + SolAddress(bs58_array( + "mYabVW1uMXpGqwgHUBQu4Fg6GT9EMYUzYaGYbi3zgT7", + )), + ), + _ => ( + SolAddress(bs58_array( + "35uYgHdfZQT4kHkaaXQ6ZdCkK5LFrsk43btTLbGCRCNT", + )), + SolAddress(bs58_array( + "2tmtGLQcBd11BMiE9B1tAkQXwmPNgR79Meki2Eme4Ec9", + )), + ), + }; + + cf_chains::sol::SolApiEnvironment { + vault_program, + vault_program_data_account, + token_vault_pda_account, + usdc_token_mint_pubkey, + usdc_token_vault_ata, + + // Newly inserted values + swap_endpoint_program, + swap_endpoint_program_data_account, + } + }, + ) + }); + + Weight::zero() + } +}