diff --git a/Anchor.toml b/Anchor.toml index 4557fd21e..2659136a9 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -5,8 +5,8 @@ resolution = true skip-lint = false [programs.localnet] -multicall_handler = "Fk1RpqsfeWt8KnFCTW9NQVdVxYvxuqjGn6iPB9wrmM8h" -svm_spoke = "JAZWcGrpSWNPTBj8QtJ9UyQqhJCDhG9GJkDeMf5NQBiq" +multicall_handler = "HaQe51FWtnmaEcuYEfPA7MRCXKrtqptat4oJdJ8zV5Be" +svm_spoke = "DLv3NggMiSaef97YCkew5xKUHDh13tVGZ7tydt3ZeAru" test = "8tsEfDSiE4WUMf97oyyyasLAvWwjeRZb2GByh4w7HckA" [programs.devnet] @@ -14,8 +14,8 @@ multicall_handler = "Fk1RpqsfeWt8KnFCTW9NQVdVxYvxuqjGn6iPB9wrmM8h" svm_spoke = "JAZWcGrpSWNPTBj8QtJ9UyQqhJCDhG9GJkDeMf5NQBiq" [programs.mainnet] -multicall_handler = "Fk1RpqsfeWt8KnFCTW9NQVdVxYvxuqjGn6iPB9wrmM8h" -svm_spoke = "JAZWcGrpSWNPTBj8QtJ9UyQqhJCDhG9GJkDeMf5NQBiq" +multicall_handler = "HaQe51FWtnmaEcuYEfPA7MRCXKrtqptat4oJdJ8zV5Be" +svm_spoke = "DLv3NggMiSaef97YCkew5xKUHDh13tVGZ7tydt3ZeAru" [registry] url = "https://api.apr.dev" diff --git a/README.md b/README.md index d8214d2e8..2d3d9f751 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ export KEYPAIR=~/.config/solana/dev-wallet.json export PROGRAM=svm_spoke # Also repeat the deployment process for multicall_handler export PROGRAM_ID=$(cat target/idl/$PROGRAM.json | jq -r ".address") export MULTISIG= # Export the Squads vault, not the multisig address! +export SOLANA_VERSION=$(grep -A 2 'name = "solana-program"' Cargo.lock | grep 'version' | head -n 1 | cut -d'"' -f2) ``` For the initial deployment also need these: @@ -95,6 +96,7 @@ export SVM_CHAIN_ID=$(cast to-dec $(cast shr $(cast shl $(cast keccak solana-dev export HUB_POOL=0x14224e63716afAcE30C9a417E0542281869f7d9e # This is for sepolia, update for mainnet export DEPOSIT_QUOTE_TIME_BUFFER=3600 export FILL_DEADLINE_BUFFER=21600 +export MAX_LEN=$(( 2 * $(stat -c %s target/deploy/$PROGRAM.so) )) # Reserve twice the size of the program for future upgrades ``` #### Initial deployment @@ -103,11 +105,14 @@ Deploy the program and set the upgrade authority to the multisig: ```shell solana program deploy \ - --url $RPC_URL target/deploy/$PROGRAM.so \ + --url $RPC_URL \ --keypair $KEYPAIR \ --program-id target/deploy/$PROGRAM-keypair.json \ + --max-len $MAX_LEN \ --with-compute-unit-price 50000 \ - --max-sign-attempts 100 + --max-sign-attempts 100 \ + --use-rpc \ + target/deploy/$PROGRAM.so solana program set-upgrade-authority \ --url $RPC_URL \ --keypair $KEYPAIR \ @@ -215,6 +220,7 @@ solana-verify verify-from-repo \ --url $RPC_URL \ --program-id $PROGRAM_ID \ --library-name $PROGRAM \ + --base-image "solanafoundation/solana-verifiable-build:$SOLANA_VERSION" \ https://github.com/across-protocol/contracts ``` @@ -225,6 +231,7 @@ solana-verify export-pda-tx \ --url $RPC_URL \ --program-id $PROGRAM_ID \ --library-name $PROGRAM \ + --base-image "solanafoundation/solana-verifiable-build:$SOLANA_VERSION" \ --uploader $MULTISIG \ https://github.com/across-protocol/contracts ``` diff --git a/deployments/deployments.json b/deployments/deployments.json index e3dd2ac62..e21c275a8 100644 --- a/deployments/deployments.json +++ b/deployments/deployments.json @@ -35,7 +35,7 @@ "Cher_Adapter": { "address": "0x0c9d064523177dBB55CFE52b9D0c485FBFc35FD2", "blockNumber": 21597341 }, "Lens_Adapter": { "address": "0x63AC22131eD457aeCbD63e6c4C7eeC7BBC74fF1F", "blockNumber": 22167069 }, "DoctorWho_Adapter": { "address": "0xFADcC43096756e1527306FD92982FEbBe3c629Fa", "blockNumber": 21773451 }, - "Solana_Adapter": { "address": "0x1E22A3146439C68A2d247448372AcAEe9E201AB1", "blockNumber": 22566473 } + "Solana_Adapter": { "address": "0x9F788694934fD2Ed34D5340B9a76EB34f2bFD7B3", "blockNumber": 22595936 } }, "10": { "SpokePool": { "address": "0x6f26Bf09B1C792e3228e5467807a900A503c0281", "blockNumber": 93903076 }, @@ -226,12 +226,12 @@ }, "34268394551451": { "SvmSpoke": { - "address": "JAZWcGrpSWNPTBj8QtJ9UyQqhJCDhG9GJkDeMf5NQBiq", - "blockNumber": 317101505 + "address": "DLv3NggMiSaef97YCkew5xKUHDh13tVGZ7tydt3ZeAru", + "blockNumber": 349354195 }, "MulticallHandler": { - "address": "Fk1RpqsfeWt8KnFCTW9NQVdVxYvxuqjGn6iPB9wrmM8h", - "blockNumber": 317112562 + "address": "HaQe51FWtnmaEcuYEfPA7MRCXKrtqptat4oJdJ8zV5Be", + "blockNumber": 349358090 }, "MessageTransmitter": { "address": "CCTPmbSD7gX1bxKPAmg77w8oFzNFpaQiQUWD43TKaecd", diff --git a/deployments/mainnet/Solana_Adapter.json b/deployments/mainnet/Solana_Adapter.json index ec7f9a007..74e834fe0 100644 --- a/deployments/mainnet/Solana_Adapter.json +++ b/deployments/mainnet/Solana_Adapter.json @@ -1,5 +1,5 @@ { - "address": "0x1E22A3146439C68A2d247448372AcAEe9E201AB1", + "address": "0x9F788694934fD2Ed34D5340B9a76EB34f2bFD7B3", "abi": [ { "inputs": [ @@ -328,19 +328,19 @@ "type": "function" } ], - "transactionHash": "0x940c1e4bf26e94e657bc1e1344d3c2aea44e80a051837b75812283668a23c3a7", + "transactionHash": "0x5256d567a2ce4cbc96f04cb3b0885fad53fd48d163b67a79d9dfeaaba21f6fc3", "receipt": { "to": null, "from": "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D", - "contractAddress": "0x1E22A3146439C68A2d247448372AcAEe9E201AB1", - "transactionIndex": 72, + "contractAddress": "0x9F788694934fD2Ed34D5340B9a76EB34f2bFD7B3", + "transactionIndex": 22, "gasUsed": "1034334", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "blockHash": "0x66dae79469e26570eb7960c9b1daa884ca592e1085f00879f1012d1e5e309022", - "transactionHash": "0x940c1e4bf26e94e657bc1e1344d3c2aea44e80a051837b75812283668a23c3a7", + "blockHash": "0x60c1b45973d5aba6a92d540aa1c8b879817b8a1a3cafcb9b20ce4ba474c44dd1", + "transactionHash": "0x5256d567a2ce4cbc96f04cb3b0885fad53fd48d163b67a79d9dfeaaba21f6fc3", "logs": [], - "blockNumber": 22566473, - "cumulativeGasUsed": "5278156", + "blockNumber": 22595936, + "cumulativeGasUsed": "4109786", "status": 1, "byzantium": true }, @@ -348,9 +348,9 @@ "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "0xBd3fa81B58Ba92a82136038B25aDec7066af3155", "0x0a992d191deec32afe36203ad87d7d289a738f81", - "0xff09aa2d3eb1bc9da19e82264930e13d3993e1160f3039ef21afd1565376efca", + "0xb7664086de37ee70821c10445b162f2c7ec8795bd0800c1462949e2328d1dd5a", "0xc6fa7af3bedbad3a3d65f36aabc97431b1bbe4c2d2f6e0e47ca60203452f5d61", - "0xe11ef405ee6e9a6497fb8209d04040216281c57264730415648de979f6cec7fa" + "0xf5d9ddc2b5d994277e15ea380117a3f8ef04ce1e37e2c678c3be4d11b2a5d034" ], "numDeployments": 1, "solcInputHash": "335735b51fb84a31677c4bf77e2b5d68", diff --git a/package.json b/package.json index db6897370..a8b25c339 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@across-protocol/contracts", - "version": "4.0.12", + "version": "4.0.14-alpha.3", "author": "UMA Team", "license": "AGPL-3.0-only", "repository": { diff --git a/programs/multicall-handler/src/lib.rs b/programs/multicall-handler/src/lib.rs index 6bc38b264..0349d7645 100644 --- a/programs/multicall-handler/src/lib.rs +++ b/programs/multicall-handler/src/lib.rs @@ -22,7 +22,7 @@ security_txt! { // If changing the program ID, make sure to check that the resulting handler_signer PDA has the highest bump of 255 so // to minimize the compute cost when finding the PDA. -declare_id!("Fk1RpqsfeWt8KnFCTW9NQVdVxYvxuqjGn6iPB9wrmM8h"); +declare_id!("HaQe51FWtnmaEcuYEfPA7MRCXKrtqptat4oJdJ8zV5Be"); #[program] pub mod multicall_handler { diff --git a/programs/svm-spoke/src/common/relay_data.rs b/programs/svm-spoke/src/common/relay_data.rs index 74618c364..0d7a0a632 100644 --- a/programs/svm-spoke/src/common/relay_data.rs +++ b/programs/svm-spoke/src/common/relay_data.rs @@ -7,7 +7,7 @@ pub struct RelayData { pub exclusive_relayer: Pubkey, pub input_token: Pubkey, pub output_token: Pubkey, - pub input_amount: u64, + pub input_amount: [u8; 32], pub output_amount: u64, pub origin_chain_id: u64, pub deposit_id: [u8; 32], diff --git a/programs/svm-spoke/src/error.rs b/programs/svm-spoke/src/error.rs index 55820b089..b02c993f4 100644 --- a/programs/svm-spoke/src/error.rs +++ b/programs/svm-spoke/src/error.rs @@ -33,6 +33,8 @@ pub enum CommonError { InsufficientSpokePoolBalanceToExecuteLeaf, #[msg("Invalid exclusive relayer!")] InvalidExclusiveRelayer, + #[msg("Invalid output token!")] + InvalidOutputToken, } // SVM specific errors. diff --git a/programs/svm-spoke/src/event.rs b/programs/svm-spoke/src/event.rs index 073ca7e77..bfde389de 100644 --- a/programs/svm-spoke/src/event.rs +++ b/programs/svm-spoke/src/event.rs @@ -39,7 +39,7 @@ pub struct FundsDeposited { pub input_token: Pubkey, pub output_token: Pubkey, pub input_amount: u64, - pub output_amount: u64, + pub output_amount: [u8; 32], pub destination_chain_id: u64, pub deposit_id: [u8; 32], pub quote_timestamp: u32, @@ -71,7 +71,7 @@ pub struct RelayExecutionEventInfo { pub struct FilledRelay { pub input_token: Pubkey, pub output_token: Pubkey, - pub input_amount: u64, + pub input_amount: [u8; 32], pub output_amount: u64, pub repayment_chain_id: u64, pub origin_chain_id: u64, @@ -91,7 +91,7 @@ pub struct FilledRelay { pub struct RequestedSlowFill { pub input_token: Pubkey, pub output_token: Pubkey, - pub input_amount: u64, + pub input_amount: [u8; 32], pub output_amount: u64, pub origin_chain_id: u64, pub deposit_id: [u8; 32], diff --git a/programs/svm-spoke/src/instructions/deposit.rs b/programs/svm-spoke/src/instructions/deposit.rs index 5f56aa738..0bd64697f 100644 --- a/programs/svm-spoke/src/instructions/deposit.rs +++ b/programs/svm-spoke/src/instructions/deposit.rs @@ -21,15 +21,7 @@ use crate::{ #[event_cpi] #[derive(Accounts)] -#[instruction( - depositor: Pubkey, - recipient: Pubkey, - input_token: Pubkey, - output_token: Pubkey, - input_amount: u64, - output_amount: u64, - destination_chain_id: u64 -)] +#[instruction(depositor: Pubkey, recipient: Pubkey, input_token: Pubkey)] pub struct Deposit<'info> { #[account(mut)] pub signer: Signer<'info>, @@ -82,7 +74,7 @@ pub fn _deposit( input_token: Pubkey, output_token: Pubkey, input_amount: u64, - output_amount: u64, + output_amount: [u8; 32], destination_chain_id: u64, exclusive_relayer: Pubkey, deposit_id: [u8; 32], @@ -95,6 +87,10 @@ pub fn _deposit( let state = &mut ctx.accounts.state; let current_time = get_current_time(state)?; + if output_token == Pubkey::default() { + return err!(CommonError::InvalidOutputToken); + } + if current_time.checked_sub(quote_timestamp).unwrap_or(u32::MAX) > state.deposit_quote_time_buffer { return err!(CommonError::InvalidQuoteTimestamp); } @@ -156,7 +152,7 @@ pub fn deposit( input_token: Pubkey, output_token: Pubkey, input_amount: u64, - output_amount: u64, + output_amount: [u8; 32], destination_chain_id: u64, exclusive_relayer: Pubkey, quote_timestamp: u32, @@ -208,7 +204,7 @@ pub fn deposit_now( input_token: Pubkey, output_token: Pubkey, input_amount: u64, - output_amount: u64, + output_amount: [u8; 32], destination_chain_id: u64, exclusive_relayer: Pubkey, fill_deadline_offset: u32, @@ -260,7 +256,7 @@ pub fn unsafe_deposit( input_token: Pubkey, output_token: Pubkey, input_amount: u64, - output_amount: u64, + output_amount: [u8; 32], destination_chain_id: u64, exclusive_relayer: Pubkey, deposit_nonce: u64, diff --git a/programs/svm-spoke/src/lib.rs b/programs/svm-spoke/src/lib.rs index 653a00909..8d90393b9 100644 --- a/programs/svm-spoke/src/lib.rs +++ b/programs/svm-spoke/src/lib.rs @@ -14,7 +14,7 @@ security_txt! { auditors: "OpenZeppelin" } -declare_id!("JAZWcGrpSWNPTBj8QtJ9UyQqhJCDhG9GJkDeMf5NQBiq"); +declare_id!("DLv3NggMiSaef97YCkew5xKUHDh13tVGZ7tydt3ZeAru"); // External programs from idls directory (requires anchor run generateExternalTypes). declare_program!(message_transmitter); @@ -217,6 +217,7 @@ pub mod svm_spoke { /// amount will be sent to the relayer on their repayment chain of choice as a refund following an optimistic /// challenge window in the HubPool, less a system fee. /// - output_amount: The amount of output tokens that the relayer will send to the recipient on the destination. + /// This is big-endian encoded as a 32-byte array to match its underlying byte representation on EVM side. /// - destination_chain_id: The destination chain identifier where the fill should be made. /// - exclusive_relayer: The relayer that will be exclusively allowed to fill this deposit before the exclusivity /// deadline timestamp. This must be a valid, non-zero address if the exclusivity deadline is greater than the @@ -238,7 +239,7 @@ pub mod svm_spoke { input_token: Pubkey, output_token: Pubkey, input_amount: u64, - output_amount: u64, + output_amount: [u8; 32], destination_chain_id: u64, exclusive_relayer: Pubkey, quote_timestamp: u32, @@ -272,7 +273,7 @@ pub mod svm_spoke { input_token: Pubkey, output_token: Pubkey, input_amount: u64, - output_amount: u64, + output_amount: [u8; 32], destination_chain_id: u64, exclusive_relayer: Pubkey, fill_deadline_offset: u32, @@ -308,7 +309,7 @@ pub mod svm_spoke { input_token: Pubkey, output_token: Pubkey, input_amount: u64, - output_amount: u64, + output_amount: [u8; 32], destination_chain_id: u64, exclusive_relayer: Pubkey, deposit_nonce: u64, @@ -391,6 +392,7 @@ pub mod svm_spoke { /// token on the repayment chain will be sent as a refund to the caller. /// - output_token: The token that the caller will send to the recipient on this chain. /// - input_amount: This amount, less a system fee, will be sent to the caller on their repayment chain. + /// This is big-endian encoded as a 32-byte array to match its underlying byte representation on EVM side /// - output_amount: The amount of output tokens that the caller will send to the recipient. /// - origin_chain_id: The origin chain identifier. /// - exclusive_relayer: The relayer that will be exclusively allowed to fill this deposit before the @@ -715,6 +717,9 @@ pub mod svm_spoke { /// - proof: Inclusion proof for this leaf in slow relay root in root bundle. /// Note: slow_fill_leaf, _root_bundle_id, and proof are optional parameters. If None for any of these is passed, /// the caller must load them via the instruction_params account. + /// Note: When verifying the slow fill leaf, the relay data is hashed using AnchorSerialize::serialize that encodes + /// output token amounts to little-endian format while input token amount preserves its big-endian encoding as it + /// is passed as [u8; 32] array. pub fn execute_slow_relay_leaf<'info>( ctx: Context<'_, '_, '_, 'info, ExecuteSlowRelayLeaf<'info>>, _relay_hash: [u8; 32], diff --git a/programs/svm-spoke/src/utils/delegate_utils.rs b/programs/svm-spoke/src/utils/delegate_utils.rs index 550e09bfc..d7f476c6d 100644 --- a/programs/svm-spoke/src/utils/delegate_utils.rs +++ b/programs/svm-spoke/src/utils/delegate_utils.rs @@ -13,7 +13,7 @@ pub struct DepositSeedData<'a> { pub input_token: Pubkey, pub output_token: Pubkey, pub input_amount: u64, - pub output_amount: u64, + pub output_amount: [u8; 32], pub destination_chain_id: u64, pub exclusive_relayer: Pubkey, pub quote_timestamp: u32, @@ -29,7 +29,7 @@ pub struct DepositNowSeedData<'a> { pub input_token: Pubkey, pub output_token: Pubkey, pub input_amount: u64, - pub output_amount: u64, + pub output_amount: [u8; 32], pub destination_chain_id: u64, pub exclusive_relayer: Pubkey, pub fill_deadline_offset: u32, diff --git a/scripts/svm/buildHelpers/buildSolanaVerify.sh b/scripts/svm/buildHelpers/buildSolanaVerify.sh index 3c8a926b0..3cd56734a 100644 --- a/scripts/svm/buildHelpers/buildSolanaVerify.sh +++ b/scripts/svm/buildHelpers/buildSolanaVerify.sh @@ -8,6 +8,8 @@ else CARGO_OPTIONS="" fi +SOLANA_VERSION=$(grep -A 2 'name = "solana-program"' Cargo.lock | grep 'version' | head -n 1 | cut -d'"' -f2) + for program in programs/*; do [ -d "$program" ] || continue @@ -15,7 +17,7 @@ for program in programs/*; do program_name=${dir_name//-/_} echo "Running verified build for $program_name" - solana-verify build --library-name "$program_name" -- $CARGO_OPTIONS + solana-verify build --library-name "$program_name" --base-image "solanafoundation/solana-verifiable-build:$SOLANA_VERSION" -- $CARGO_OPTIONS # We don't need keypair files from the verified build and they cause permission issues on CI when Swatinem/rust-cache # tries to delete them. diff --git a/scripts/svm/closeRelayerPdas.ts b/scripts/svm/closeRelayerPdas.ts index 20ef3e82a..5906780e2 100644 --- a/scripts/svm/closeRelayerPdas.ts +++ b/scripts/svm/closeRelayerPdas.ts @@ -65,7 +65,7 @@ async function closeFillPda(eventData: any, seed: BN): Promise { exclusiveRelayer: new PublicKey(eventData.exclusiveRelayer), inputToken: new PublicKey(eventData.inputToken), outputToken: new PublicKey(eventData.outputToken), - inputAmount: new BN(eventData.inputAmount), + inputAmount: eventData.inputAmount, outputAmount: new BN(eventData.outputAmount), originChainId: new BN(eventData.originChainId), depositId: eventData.depositId, diff --git a/scripts/svm/fakeFillWithRandomDistribution.ts b/scripts/svm/fakeFillWithRandomDistribution.ts index 1e08a46ea..4b4ad130b 100644 --- a/scripts/svm/fakeFillWithRandomDistribution.ts +++ b/scripts/svm/fakeFillWithRandomDistribution.ts @@ -20,6 +20,7 @@ import { calculateRelayHashUint8Array, getFillRelayDelegatePda, getSpokePoolProgram, + intToU8Array32, loadFillRelayParams, sendTransactionWithLookupTable, } from "../../src/svm/web3-v1"; @@ -40,10 +41,10 @@ const argv = yargs(hideBin(process.argv)) .option("exclusiveRelayer", { type: "string", demandOption: false, describe: "Exclusive relayer public key" }) .option("inputToken", { type: "string", demandOption: true, describe: "Input token public key" }) .option("outputToken", { type: "string", demandOption: true, describe: "Output token public key" }) - .option("inputAmount", { type: "number", demandOption: true, describe: "Input amount" }) + .option("inputAmount", { type: "string", demandOption: true, describe: "Input amount" }) .option("outputAmount", { type: "number", demandOption: true, describe: "Output amount" }) .option("originChainId", { type: "string", demandOption: true, describe: "Origin chain ID" }) - .option("depositId", { type: "array", demandOption: true, describe: "Deposit ID" }) + .option("depositId", { type: "string", demandOption: true, describe: "Deposit ID" }) .option("fillDeadline", { type: "number", demandOption: false, describe: "Fill deadline" }) .option("exclusivityDeadline", { type: "number", demandOption: false, describe: "Exclusivity deadline" }) .option("repaymentChain", { type: "number", demandOption: false, description: "Repayment chain ID" }) @@ -58,10 +59,10 @@ async function fillRelayToRandom(): Promise { const exclusiveRelayer = new PublicKey(resolvedArgv.exclusiveRelayer || PublicKey.default.toString()); const inputToken = new PublicKey(resolvedArgv.inputToken); const outputToken = new PublicKey(resolvedArgv.outputToken); - const inputAmount = new BN(resolvedArgv.inputAmount); + const inputAmount = intToU8Array32(new BN(resolvedArgv.inputAmount)); const outputAmount = new BN(resolvedArgv.outputAmount); const originChainId = new BN(resolvedArgv.originChainId); - const depositId = (resolvedArgv.depositId as number[]).map((id) => id); // Ensure depositId is an array of BN + const depositId = intToU8Array32(new BN(resolvedArgv.depositId)); const fillDeadline = resolvedArgv.fillDeadline || Math.floor(Date.now() / 1000) + 60; // Current time + 1 minute const exclusivityDeadline = resolvedArgv.exclusivityDeadline || Math.floor(Date.now() / 1000) + 30; // Current time + 30 seconds const repaymentChain = new BN(resolvedArgv.repaymentChain || 1); @@ -171,11 +172,17 @@ async function fillRelayToRandom(): Promise { })) ); - // Delegate state PDA to pull relayer tokens. + // Delegate to pull relayer tokens. + const delegatePda = getFillRelayDelegatePda( + relayHashUint8Array, + repaymentChain, + repaymentAddress, + program.programId + ).pda; const approveInstruction = await createApproveCheckedInstruction( relayerTokenAccount, outputToken, - statePda, + delegatePda, signer.publicKey, BigInt(relayData.outputAmount.toString()), tokenDecimals, @@ -199,7 +206,7 @@ async function fillRelayToRandom(): Promise { const fillAccounts = { state: statePda, signer: signer.publicKey, - delegate: getFillRelayDelegatePda(relayHashUint8Array, repaymentChain, repaymentAddress, program.programId).pda, + delegate: delegatePda, instructionParams, mint: outputToken, relayerTokenAccount, diff --git a/scripts/svm/findFillStatusPdaFromEvent.ts b/scripts/svm/findFillStatusPdaFromEvent.ts index 0490480b9..f28ef61a1 100644 --- a/scripts/svm/findFillStatusPdaFromEvent.ts +++ b/scripts/svm/findFillStatusPdaFromEvent.ts @@ -21,7 +21,12 @@ import { PublicKey } from "@solana/web3.js"; import { BN } from "@coral-xyz/anchor"; import yargs from "yargs"; import { hideBin } from "yargs/helpers"; -import { calculateRelayEventHashUint8Array, getSpokePoolProgram, evmAddressToPublicKey } from "../../src/svm/web3-v1"; +import { + calculateRelayEventHashUint8Array, + getSpokePoolProgram, + evmAddressToPublicKey, + intToU8Array32, +} from "../../src/svm/web3-v1"; // Set up the provider const provider = anchor.AnchorProvider.env(); @@ -53,7 +58,7 @@ async function findFillStatusPda() { exclusiveRelayer: convertAddress(resolvedArgv.exclusive_relayer), inputToken: convertAddress(resolvedArgv.input_token), outputToken: convertAddress(resolvedArgv.output_token), - inputAmount: new BN(resolvedArgv.input_amount), + inputAmount: intToU8Array32(new BN(resolvedArgv.input_amount)), outputAmount: new BN(resolvedArgv.output_amount), originChainId: new BN(resolvedArgv.origin_chain_id), depositId: parseStringToUint8Array(resolvedArgv.deposit_id), diff --git a/scripts/svm/nativeDeposit.ts b/scripts/svm/nativeDeposit.ts index 269822853..145dc8003 100644 --- a/scripts/svm/nativeDeposit.ts +++ b/scripts/svm/nativeDeposit.ts @@ -23,7 +23,14 @@ import { } from "@solana/web3.js"; import yargs from "yargs"; import { hideBin } from "yargs/helpers"; -import { getDepositPda, getDepositSeedHash, getSpokePoolProgram, SOLANA_SPOKE_STATE_SEED } from "../../src/svm/web3-v1"; +import { + getDepositPda, + getDepositSeedHash, + getSpokePoolProgram, + intToU8Array32, + SOLANA_SPOKE_STATE_SEED, + u8Array32ToInt, +} from "../../src/svm/web3-v1"; // Set up the provider const provider = AnchorProvider.env(); @@ -37,7 +44,7 @@ const argv = yargs(hideBin(process.argv)) .option("recipient", { type: "string", demandOption: true, describe: "Recipient public key" }) .option("outputToken", { type: "string", demandOption: true, describe: "Output token public key" }) .option("inputAmount", { type: "number", demandOption: true, describe: "Input amount" }) - .option("outputAmount", { type: "number", demandOption: true, describe: "Output amount" }) + .option("outputAmount", { type: "string", demandOption: true, describe: "Output amount" }) .option("destinationChainId", { type: "string", demandOption: true, describe: "Destination chain ID" }) .option("integratorId", { type: "string", demandOption: false, describe: "integrator ID" }).argv; @@ -48,7 +55,7 @@ async function nativeDeposit(): Promise { const inputToken = NATIVE_MINT; const outputToken = new PublicKey(resolvedArgv.outputToken); const inputAmount = new BN(resolvedArgv.inputAmount); - const outputAmount = new BN(resolvedArgv.outputAmount); + const outputAmount = intToU8Array32(new BN(resolvedArgv.outputAmount)); const destinationChainId = new BN(resolvedArgv.destinationChainId); const exclusiveRelayer = PublicKey.default; const quoteTimestamp = Math.floor(Date.now() / 1000) - 1; @@ -85,7 +92,7 @@ async function nativeDeposit(): Promise { { property: "inputToken", value: inputToken.toString() }, { property: "outputToken", value: outputToken.toString() }, { property: "inputAmount", value: inputAmount.toString() }, - { property: "outputAmount", value: outputAmount.toString() }, + { property: "outputAmount", value: u8Array32ToInt(outputAmount).toString() }, { property: "destinationChainId", value: destinationChainId.toString() }, { property: "quoteTimestamp", value: quoteTimestamp.toString() }, { property: "fillDeadline", value: fillDeadline.toString() }, diff --git a/scripts/svm/queryEvents.ts b/scripts/svm/queryEvents.ts index b91238c38..1359585ca 100644 --- a/scripts/svm/queryEvents.ts +++ b/scripts/svm/queryEvents.ts @@ -41,7 +41,7 @@ async function queryEvents(): Promise { const eventName = argv.eventName || "any"; const events = await readProgramEvents(provider.connection, program, "confirmed"); const filteredEvents = events.filter((event) => (eventName == "any" ? true : event.name == eventName)); - const formattedEvents = filteredEvents.map((event) => stringifyCpiEvent(event)); + const formattedEvents = filteredEvents.map((event) => stringifyCpiEvent(event.data, event.name)); console.log(JSON.stringify(formattedEvents, null, 2)); } diff --git a/scripts/svm/queryEventsV2.ts b/scripts/svm/queryEventsV2.ts index 47ad16683..b5f316d30 100644 --- a/scripts/svm/queryEventsV2.ts +++ b/scripts/svm/queryEventsV2.ts @@ -52,7 +52,7 @@ async function queryEvents(): Promise { const events = await readProgramEvents({ rpc, rpcSubscriptions }, address(programId), SvmSpokeIdl, "confirmed"); const filteredEvents = events.filter((e) => (eventName === "any" ? true : e.name === eventName)); - const formattedEvents = filteredEvents.map(stringifyCpiEvent); + const formattedEvents = filteredEvents.map((event) => stringifyCpiEvent(event.data, event.name)); console.log(JSON.stringify(formattedEvents, null, 2)); } diff --git a/scripts/svm/queryFills.ts b/scripts/svm/queryFills.ts index 2241104d9..0e32086f0 100644 --- a/scripts/svm/queryFills.ts +++ b/scripts/svm/queryFills.ts @@ -50,7 +50,7 @@ async function queryFills(): Promise { console.table([ { Property: "inputToken", Value: strPublicKey(event.data.inputToken) }, { Property: "outputToken", Value: strPublicKey(event.data.outputToken) }, - { Property: "inputAmount", Value: event.data.inputAmount.toString() }, + { Property: "inputAmount", Value: u8Array32ToInt(event.data.inputAmount).toString() }, { Property: "outputAmount", Value: event.data.outputAmount.toString() }, { Property: "repaymentChainId", Value: event.data.repaymentChainId.toString() }, { Property: "originChainId", Value: event.data.originChainId.toString() }, diff --git a/scripts/svm/simpleDeposit.ts b/scripts/svm/simpleDeposit.ts index ed32046aa..577158684 100644 --- a/scripts/svm/simpleDeposit.ts +++ b/scripts/svm/simpleDeposit.ts @@ -18,7 +18,13 @@ import { } from "@solana/web3.js"; import yargs from "yargs"; import { hideBin } from "yargs/helpers"; -import { getDepositPda, getDepositSeedHash, getSpokePoolProgram } from "../../src/svm/web3-v1"; +import { + getDepositPda, + getDepositSeedHash, + getSpokePoolProgram, + intToU8Array32, + u8Array32ToInt, +} from "../../src/svm/web3-v1"; // Set up the provider const provider = AnchorProvider.env(); @@ -34,7 +40,7 @@ const argv = yargs(hideBin(process.argv)) .option("inputToken", { type: "string", demandOption: true, describe: "Input token public key" }) .option("outputToken", { type: "string", demandOption: true, describe: "Output token public key" }) .option("inputAmount", { type: "number", demandOption: true, describe: "Input amount" }) - .option("outputAmount", { type: "number", demandOption: true, describe: "Output amount" }) + .option("outputAmount", { type: "string", demandOption: true, describe: "Output amount" }) .option("destinationChainId", { type: "string", demandOption: true, describe: "Destination chain ID" }) .option("integratorId", { type: "string", demandOption: false, describe: "integrator ID" }).argv; @@ -45,7 +51,7 @@ async function deposit(): Promise { const inputToken = new PublicKey(resolvedArgv.inputToken); const outputToken = new PublicKey(resolvedArgv.outputToken); const inputAmount = new BN(resolvedArgv.inputAmount); - const outputAmount = new BN(resolvedArgv.outputAmount); + const outputAmount = intToU8Array32(new BN(resolvedArgv.outputAmount)); const destinationChainId = new BN(resolvedArgv.destinationChainId); const exclusiveRelayer = PublicKey.default; const quoteTimestamp = Math.floor(Date.now() / 1000) - 1; @@ -79,7 +85,7 @@ async function deposit(): Promise { { property: "inputToken", value: inputToken.toString() }, { property: "outputToken", value: outputToken.toString() }, { property: "inputAmount", value: inputAmount.toString() }, - { property: "outputAmount", value: outputAmount.toString() }, + { property: "outputAmount", value: u8Array32ToInt(outputAmount).toString() }, { property: "destinationChainId", value: destinationChainId.toString() }, { property: "quoteTimestamp", value: quoteTimestamp.toString() }, { property: "fillDeadline", value: fillDeadline.toString() }, diff --git a/scripts/svm/simpleFakeRelayerRepayment.ts b/scripts/svm/simpleFakeRelayerRepayment.ts index caa8b3a0c..b2f2f0dda 100644 --- a/scripts/svm/simpleFakeRelayerRepayment.ts +++ b/scripts/svm/simpleFakeRelayerRepayment.ts @@ -24,7 +24,14 @@ import { import { MerkleTree } from "@uma/common/dist/MerkleTree"; import yargs from "yargs"; import { hideBin } from "yargs/helpers"; -import { getSpokePoolProgram, loadExecuteRelayerRefundLeafParams, relayerRefundHashFn } from "../../src/svm/web3-v1"; +import { + getDepositPda, + getDepositSeedHash, + getSpokePoolProgram, + intToU8Array32, + loadExecuteRelayerRefundLeafParams, + relayerRefundHashFn, +} from "../../src/svm/web3-v1"; import { RelayerRefundLeafSolana, RelayerRefundLeafType } from "../../src/types/svm"; // Set up the provider @@ -79,12 +86,28 @@ async function testBundleLogic(): Promise { // Use program.methods.deposit to send tokens to the spoke. note this is NOT a valid deposit, we just want to // seed tokens into the spoke to test repayment. - // Delegate state PDA to pull depositor tokens. const inputAmount = amounts.reduce((acc, amount) => acc.add(amount), new BN(0)); + + const depositData: Parameters[0] = { + depositor: signer.publicKey, + recipient: signer.publicKey, // recipient is the signer for this example + inputToken, + outputToken: inputToken, // Re-use inputToken as outputToken. does not matter for this deposit. + inputAmount, + outputAmount: intToU8Array32(inputAmount), + destinationChainId: new BN(11155111), + exclusiveRelayer: PublicKey.default, + quoteTimestamp: new BN(Math.floor(Date.now() / 1000) - 1), + fillDeadline: new BN(Math.floor(Date.now() / 1000) + 3600), + exclusivityParameter: new BN(0), + message: Buffer.from([]), + }; + const delegatePda = getDepositPda(depositData, program.programId); + const approveIx = await createApproveCheckedInstruction( userTokenAccount, inputToken, - statePda, + delegatePda, signer.publicKey, BigInt(inputAmount.toString()), tokenDecimals, @@ -93,22 +116,23 @@ async function testBundleLogic(): Promise { ); const depositIx = await ( program.methods.deposit( - signer.publicKey, - signer.publicKey, // recipient is the signer for this example - inputToken, - inputToken, // Re-use inputToken as outputToken. does not matter for this deposit. - inputAmount, - new BN(0), - new BN(11155111), // destinationChainId. - PublicKey.default, // exclusiveRelayer - Math.floor(Date.now() / 1000) - 1, // quoteTimestamp - Math.floor(Date.now() / 1000) + 3600, // fillDeadline - 0, // exclusivityDeadline - Buffer.from([]) // message + depositData.depositor, + depositData.recipient, + depositData.inputToken, + depositData.outputToken, + depositData.inputAmount, + depositData.outputAmount, + depositData.destinationChainId, + depositData.exclusiveRelayer, + depositData.quoteTimestamp.toNumber(), + depositData.fillDeadline.toNumber(), + depositData.exclusivityParameter.toNumber(), + Buffer.from([]) ) as any ) .accounts({ state: statePda, + delegate: delegatePda, signer: signer.publicKey, userTokenAccount: getAssociatedTokenAddressSync(inputToken, signer.publicKey), vault: vault, @@ -164,7 +188,7 @@ async function testBundleLogic(): Promise { const rootBundleId = state.rootBundleId; const rootBundleIdBuffer = Buffer.alloc(4); rootBundleIdBuffer.writeUInt32LE(rootBundleId); - const seeds = [Buffer.from("root_bundle"), statePda.toBuffer(), rootBundleIdBuffer]; + const seeds = [Buffer.from("root_bundle"), seed.toArrayLike(Buffer, "le", 8), rootBundleIdBuffer]; const [rootBundle] = PublicKey.findProgramAddressSync(seeds, programId); console.table([ diff --git a/scripts/svm/simpleFill.ts b/scripts/svm/simpleFill.ts index 80cec8dbe..be83f946f 100644 --- a/scripts/svm/simpleFill.ts +++ b/scripts/svm/simpleFill.ts @@ -36,7 +36,7 @@ const argv = yargs(hideBin(process.argv)) .option("exclusiveRelayer", { type: "string", demandOption: false, describe: "Exclusive relayer public key" }) .option("inputToken", { type: "string", demandOption: true, describe: "Input token public key" }) .option("outputToken", { type: "string", demandOption: true, describe: "Output token public key" }) - .option("inputAmount", { type: "number", demandOption: true, describe: "Input amount" }) + .option("inputAmount", { type: "string", demandOption: true, describe: "Input amount" }) .option("outputAmount", { type: "number", demandOption: true, describe: "Output amount" }) .option("originChainId", { type: "string", demandOption: true, describe: "Origin chain ID" }) .option("depositId", { type: "string", demandOption: true, describe: "Deposit ID" }) @@ -50,7 +50,7 @@ async function fillRelay(): Promise { const exclusiveRelayer = new PublicKey(resolvedArgv.exclusiveRelayer || "11111111111111111111111111111111"); const inputToken = new PublicKey(resolvedArgv.inputToken); const outputToken = new PublicKey(resolvedArgv.outputToken); - const inputAmount = new BN(resolvedArgv.inputAmount); + const inputAmount = intToU8Array32(new BN(resolvedArgv.inputAmount)); const outputAmount = new BN(resolvedArgv.outputAmount); const originChainId = new BN(resolvedArgv.originChainId); const depositId = intToU8Array32(new BN(resolvedArgv.depositId)); diff --git a/src/svm/web3-v1/helpers.ts b/src/svm/web3-v1/helpers.ts index 0f61fe035..d9f12d228 100644 --- a/src/svm/web3-v1/helpers.ts +++ b/src/svm/web3-v1/helpers.ts @@ -43,7 +43,7 @@ export class DepositSeedData { inputToken!: Uint8Array; outputToken!: Uint8Array; inputAmount!: BN; - outputAmount!: BN; + outputAmount!: number[]; destinationChainId!: BN; exclusiveRelayer!: Uint8Array; quoteTimestamp!: BN; @@ -57,7 +57,7 @@ export class DepositSeedData { inputToken: Uint8Array; outputToken: Uint8Array; inputAmount: BN; - outputAmount: BN; + outputAmount: number[]; destinationChainId: BN; exclusiveRelayer: Uint8Array; quoteTimestamp: BN; @@ -80,7 +80,7 @@ const depositSeedSchema = new Map([ ["inputToken", [32]], ["outputToken", [32]], ["inputAmount", "u64"], - ["outputAmount", "u64"], + ["outputAmount", [32]], ["destinationChainId", "u64"], ["exclusiveRelayer", [32]], ["quoteTimestamp", "u32"], @@ -101,7 +101,7 @@ export function getDepositSeedHash(depositData: { inputToken: PublicKey; outputToken: PublicKey; inputAmount: BN; - outputAmount: BN; + outputAmount: number[]; destinationChainId: BN; exclusiveRelayer: PublicKey; quoteTimestamp: BN; @@ -145,7 +145,7 @@ export class DepositNowSeedData { inputToken!: Uint8Array; outputToken!: Uint8Array; inputAmount!: BN; - outputAmount!: BN; + outputAmount!: number[]; destinationChainId!: BN; exclusiveRelayer!: Uint8Array; fillDeadlineOffset!: BN; @@ -158,7 +158,7 @@ export class DepositNowSeedData { inputToken: Uint8Array; outputToken: Uint8Array; inputAmount: BN; - outputAmount: BN; + outputAmount: number[]; destinationChainId: BN; exclusiveRelayer: Uint8Array; fillDeadlineOffset: BN; @@ -180,7 +180,7 @@ const depositNowSeedSchema = new Map([ ["inputToken", [32]], ["outputToken", [32]], ["inputAmount", "u64"], - ["outputAmount", "u64"], + ["outputAmount", [32]], ["destinationChainId", "u64"], ["exclusiveRelayer", [32]], ["fillDeadlineOffset", "u32"], @@ -200,7 +200,7 @@ export function getDepositNowSeedHash(depositData: { inputToken: PublicKey; outputToken: PublicKey; inputAmount: BN; - outputAmount: BN; + outputAmount: number[]; destinationChainId: BN; exclusiveRelayer: PublicKey; fillDeadlineOffset: BN; diff --git a/src/svm/web3-v1/relayHashUtils.ts b/src/svm/web3-v1/relayHashUtils.ts index 2786426b9..553649db5 100644 --- a/src/svm/web3-v1/relayHashUtils.ts +++ b/src/svm/web3-v1/relayHashUtils.ts @@ -13,7 +13,7 @@ export function calculateRelayHashUint8Array(relayData: any, chainId: BN): Uint8 relayData.exclusiveRelayer.toBuffer(), relayData.inputToken.toBuffer(), relayData.outputToken.toBuffer(), - relayData.inputAmount.toArrayLike(Buffer, "le", 8), + Buffer.from(relayData.inputAmount), relayData.outputAmount.toArrayLike(Buffer, "le", 8), relayData.originChainId.toArrayLike(Buffer, "le", 8), Buffer.from(relayData.depositId), @@ -38,7 +38,7 @@ export function calculateRelayEventHashUint8Array(relayEventData: any, chainId: relayEventData.exclusiveRelayer.toBuffer(), relayEventData.inputToken.toBuffer(), relayEventData.outputToken.toBuffer(), - relayEventData.inputAmount.toArrayLike(Buffer, "le", 8), + Buffer.from(relayEventData.inputAmount), relayEventData.outputAmount.toArrayLike(Buffer, "le", 8), relayEventData.originChainId.toArrayLike(Buffer, "le", 8), Buffer.from(relayEventData.depositId), @@ -178,7 +178,7 @@ const slowFillDataSchema = new Map([ ["exclusiveRelayer", [32]], ["inputToken", [32]], ["outputToken", [32]], - ["inputAmount", "u64"], + ["inputAmount", [32]], ["outputAmount", "u64"], ["originChainId", "u64"], ["depositId", [32]], diff --git a/src/svm/web3-v1/solanaProgramUtils.ts b/src/svm/web3-v1/solanaProgramUtils.ts index b3269c40d..c5f7c6763 100644 --- a/src/svm/web3-v1/solanaProgramUtils.ts +++ b/src/svm/web3-v1/solanaProgramUtils.ts @@ -9,7 +9,7 @@ import { } from "@solana/web3.js"; import { deserialize } from "borsh"; import { EventType } from "../../types/svm"; -import { publicKeyToEvmAddress } from "./conversionUtils"; +import { publicKeyToEvmAddress, u8Array32ToInt } from "./conversionUtils"; /** * Finds a program address with a given label and optional extra seeds. @@ -230,7 +230,7 @@ function parseDepositId(value: Uint8Array): string { /** * Stringifies a CPI event. */ -export function stringifyCpiEvent(obj: any): any { +export function stringifyCpiEvent(obj: any, eventName: string): any { if (obj?.constructor?.toString()?.includes("PublicKey")) { if (obj.toString().startsWith("111111111111")) { // First 12 bytes are 0 for EVM addresses. @@ -244,16 +244,28 @@ export function stringifyCpiEvent(obj: any): any { } else if (Array.isArray(obj) && obj.length == 32) { return Buffer.from(obj).toString("hex"); // Hex representation for fixed-length arrays } else if (Array.isArray(obj)) { - return obj.map(stringifyCpiEvent); + return obj.map((obj) => stringifyCpiEvent(obj, eventName)); } else if (obj !== null && typeof obj === "object") { return Object.fromEntries( Object.entries(obj).map(([key, value]) => { - if (key === "depositId" && Array.isArray(value) && value.length === 32) { - // Parse depositId using the helper function - const parsedValue = parseDepositId(new Uint8Array(value)); - return [key, parsedValue]; + if (Array.isArray(value) && value.length === 32) { + if (key === "depositId" || key === "deposit_id") { + // Parse depositId using the helper function + const parsedValue = parseDepositId(new Uint8Array(value)); + return [key, parsedValue]; + } else if ( + eventName.toLowerCase() === "fundsdeposited" && + (key === "outputAmount" || key === "output_amount") + ) { + return [key, u8Array32ToInt(new Uint8Array(value)).toString()]; + } else if ( + (eventName.toLowerCase() === "filledrelay" || eventName.toLowerCase() === "requestedslowfill") && + (key === "inputAmount" || key === "input_amount") + ) { + return [key, u8Array32ToInt(new Uint8Array(value)).toString()]; + } } - return [key, stringifyCpiEvent(value)]; + return [key, stringifyCpiEvent(value, eventName)]; }) ); } diff --git a/src/types/svm.ts b/src/types/svm.ts index f1387e2d2..c0b8830bd 100644 --- a/src/types/svm.ts +++ b/src/types/svm.ts @@ -45,7 +45,7 @@ export type RelayData = { exclusiveRelayer: PublicKey; inputToken: PublicKey; outputToken: PublicKey; - inputAmount: BN; + inputAmount: number[]; outputAmount: BN; originChainId: BN; depositId: number[]; @@ -63,7 +63,7 @@ export interface DepositData { inputToken: PublicKey | null; outputToken: PublicKey; inputAmount: BN; - outputAmount: BN; + outputAmount: number[]; destinationChainId: BN; exclusiveRelayer: PublicKey; quoteTimestamp: BN; @@ -78,7 +78,7 @@ export type DepositDataValues = [ PublicKey, PublicKey, BN, - BN, + number[], BN, PublicKey, number, diff --git a/test/svm/SvmSpoke.Deposit.ts b/test/svm/SvmSpoke.Deposit.ts index 0fcf231ce..e4ed53f2d 100644 --- a/test/svm/SvmSpoke.Deposit.ts +++ b/test/svm/SvmSpoke.Deposit.ts @@ -649,7 +649,11 @@ describe("svm_spoke.deposit", () => { inputToken ); - const nativeDepositData = { ...depositData, inputAmount: new BN(nativeAmount), outputAmount: new BN(nativeAmount) }; + const nativeDepositData = { + ...depositData, + inputAmount: new BN(nativeAmount), + outputAmount: intToU8Array32(nativeAmount), + }; const depositDataValues = Object.values(nativeDepositData) as DepositDataValues; const delegate = getDepositPda(nativeDepositData as DepositDataSeed, program.programId); const approveIx = await createApproveCheckedInstruction( @@ -704,7 +708,11 @@ describe("svm_spoke.deposit", () => { // Sync the user token account with the native balance. const syncIx = createSyncNativeInstruction(depositorTA); - const nativeDepositData = { ...depositData, inputAmount: new BN(nativeAmount), outputAmount: new BN(nativeAmount) }; + const nativeDepositData = { + ...depositData, + inputAmount: new BN(nativeAmount), + outputAmount: intToU8Array32(nativeAmount), + }; const depositDataValues = Object.values(nativeDepositData) as DepositDataValues; const delegate = getDepositPda(nativeDepositData as DepositDataSeed, program.programId); const approveIx = await createApproveCheckedInstruction( @@ -774,6 +782,17 @@ describe("svm_spoke.deposit", () => { assertSE(vaultAccount.amount, depositData.inputAmount, "Vault balance should equal the deposited amount"); }); + it("Output token cannot be zero address", async () => { + const invalidDepositData = { ...depositData, outputToken: new PublicKey("11111111111111111111111111111111") }; + + try { + await approvedDeposit(invalidDepositData); + assert.fail("Should not be able to process deposit with zero output token address"); + } catch (err: any) { + assert.include(err.toString(), "Error Code: InvalidOutputToken", "Expected InvalidOutputToken error"); + } + }); + describe("codama client and solana kit", () => { it("Deposit with with solana kit and codama client", async () => { // typescript is not happy with the depositData object @@ -811,7 +830,7 @@ describe("svm_spoke.deposit", () => { inputToken: address(depositData.inputToken.toString()), outputToken: address(depositData.outputToken.toString()), inputAmount: BigInt(depositData.inputAmount.toString()), - outputAmount: BigInt(depositData.outputAmount.toString()), + outputAmount: new Uint8Array(depositData.outputAmount), destinationChainId: depositData.destinationChainId.toNumber(), exclusiveRelayer: address(depositData.exclusiveRelayer.toString()), quoteTimestamp: depositData.quoteTimestamp.toNumber(), diff --git a/test/svm/SvmSpoke.Fill.AcrossPlus.ts b/test/svm/SvmSpoke.Fill.AcrossPlus.ts index 1287aefd2..296ff734d 100644 --- a/test/svm/SvmSpoke.Fill.AcrossPlus.ts +++ b/test/svm/SvmSpoke.Fill.AcrossPlus.ts @@ -156,7 +156,7 @@ describe("svm_spoke.fill.across_plus", () => { exclusiveRelayer: relayer.publicKey, inputToken: mint, // This is lazy. it should be an encoded token from a separate domain most likely. outputToken: mint, - inputAmount: new BN(relayAmount), + inputAmount: intToU8Array32(relayAmount), outputAmount: new BN(relayAmount), originChainId: new BN(1), depositId: intToU8Array32(Math.floor(Math.random() * 1000000)), // force that we always have a new deposit id. @@ -290,7 +290,7 @@ describe("svm_spoke.fill.across_plus", () => { it("Max token distributions within invoked message call, regular params", async () => { // Larger distribution would exceed message size limits. - const numberOfDistributions = 7; + const numberOfDistributions = 6; await fillTokenDistributions(numberOfDistributions); }); @@ -469,7 +469,7 @@ describe("svm_spoke.fill.across_plus", () => { exclusiveRelayer: address(relayData.exclusiveRelayer.toString()), inputToken: address(relayData.inputToken.toString()), outputToken: address(relayData.outputToken.toString()), - inputAmount: relayData.inputAmount.toNumber(), + inputAmount: new Uint8Array(relayData.inputAmount), outputAmount: relayData.outputAmount.toNumber(), originChainId: relayData.originChainId.toNumber(), depositId: new Uint8Array(relayData.depositId), diff --git a/test/svm/SvmSpoke.Fill.ts b/test/svm/SvmSpoke.Fill.ts index 42f4e035c..5596ca214 100644 --- a/test/svm/SvmSpoke.Fill.ts +++ b/test/svm/SvmSpoke.Fill.ts @@ -191,7 +191,7 @@ describe("svm_spoke.fill", () => { exclusiveRelayer: relayer.publicKey, inputToken: mint, // This is lazy. it should be an encoded token from a separate domain most likely. outputToken: mint, - inputAmount: new BN(relayAmount), + inputAmount: intToU8Array32(relayAmount), outputAmount: new BN(relayAmount), originChainId: new BN(1), depositId: intToU8Array32(Math.floor(Math.random() * 1000000)), // force that we always have a new deposit id. @@ -749,7 +749,7 @@ describe("svm_spoke.fill", () => { exclusiveRelayer: address(relayData.exclusiveRelayer.toString()), inputToken: address(relayData.inputToken.toString()), outputToken: address(relayData.outputToken.toString()), - inputAmount: relayData.inputAmount.toNumber(), + inputAmount: new Uint8Array(relayData.inputAmount), outputAmount: relayData.outputAmount.toNumber(), originChainId: relayData.originChainId.toNumber(), depositId: new Uint8Array(relayData.depositId), @@ -854,7 +854,7 @@ describe("svm_spoke.fill", () => { exclusiveRelayer: address(relayData.exclusiveRelayer.toString()), inputToken: address(relayData.inputToken.toString()), outputToken: address(relayData.outputToken.toString()), - inputAmount: relayData.inputAmount.toNumber(), + inputAmount: new Uint8Array(relayData.inputAmount), outputAmount: relayData.outputAmount.toNumber(), originChainId: relayData.originChainId.toNumber(), depositId: new Uint8Array(relayData.depositId), diff --git a/test/svm/SvmSpoke.SlowFill.AcrossPlus.ts b/test/svm/SvmSpoke.SlowFill.AcrossPlus.ts index 1f036e6f3..16539bb91 100644 --- a/test/svm/SvmSpoke.SlowFill.AcrossPlus.ts +++ b/test/svm/SvmSpoke.SlowFill.AcrossPlus.ts @@ -226,7 +226,7 @@ describe("svm_spoke.slow_fill.across_plus", () => { exclusiveRelayer: relayer.publicKey, inputToken: mint, // This is lazy. it should be an encoded token from a separate domain most likely. outputToken: mint, - inputAmount: new BN(relayAmount), + inputAmount: intToU8Array32(relayAmount), outputAmount: new BN(relayAmount), originChainId: new BN(1), depositId: intToU8Array32(Math.floor(Math.random() * 1000000)), // Unique ID for each test. @@ -272,7 +272,7 @@ describe("svm_spoke.slow_fill.across_plus", () => { // Request and execute slow fill. const { requestIx, executeIx } = await createSlowFillIx(multicallHandlerCoder); await sendAndConfirmTransaction(connection, new Transaction().add(requestIx), [relayer]); - await sendAndConfirmTransaction(connection, new Transaction().add(executeIx), [relayer]); + await sendTransactionWithLookupTable(connection, [executeIx], relayer); // Verify vault's balance after the fill const fVaultBal = (await getAccount(connection, vault)).amount; @@ -383,7 +383,7 @@ describe("svm_spoke.slow_fill.across_plus", () => { it("Max token distributions within invoked message call, regular params", async () => { // Larger distribution would exceed message size limits. - const numberOfDistributions = 6; + const numberOfDistributions = 5; await fillTokenDistributions(numberOfDistributions); }); diff --git a/test/svm/SvmSpoke.SlowFill.ts b/test/svm/SvmSpoke.SlowFill.ts index dd78a6800..f2063079e 100644 --- a/test/svm/SvmSpoke.SlowFill.ts +++ b/test/svm/SvmSpoke.SlowFill.ts @@ -108,7 +108,7 @@ describe("svm_spoke.slow_fill", () => { exclusiveRelayer: relayer.publicKey, inputToken: mint, outputToken: mint, - inputAmount: new BN(relayAmount), + inputAmount: intToU8Array32(relayAmount), outputAmount: new BN(relayAmount), originChainId: new BN(1), depositId: intToU8Array32(Math.floor(Math.random() * 1000000)), // Unique ID for each test. @@ -184,7 +184,7 @@ describe("svm_spoke.slow_fill", () => { exclusiveRelayer: relayer.publicKey, inputToken: mint, // This is lazy. it should be an encoded token from a separate domain most likely. outputToken: mint, - inputAmount: new BN(relayAmount), + inputAmount: intToU8Array32(relayAmount), outputAmount: new BN(relayAmount), originChainId: new BN(1), depositId: intToU8Array32(1), diff --git a/test/svm/SvmSpoke.common.ts b/test/svm/SvmSpoke.common.ts index 1f811b255..eb741d94f 100644 --- a/test/svm/SvmSpoke.common.ts +++ b/test/svm/SvmSpoke.common.ts @@ -5,7 +5,7 @@ import { Keypair, PublicKey, Signer } from "@solana/web3.js"; import { assert } from "chai"; import { randomBytes } from "crypto"; import { ethers } from "ethers"; -import { evmAddressToPublicKey } from "../../src/svm/web3-v1"; +import { evmAddressToPublicKey, intToU8Array32 } from "../../src/svm/web3-v1"; import { DepositData } from "../../src/types/svm"; import { SvmSpoke } from "../../target/types/svm_spoke"; @@ -140,7 +140,7 @@ export const common = { inputToken: null, // Placeholder, to be assigned in the test file outputToken, inputAmount, - outputAmount, + outputAmount: intToU8Array32(outputAmount), destinationChainId, exclusiveRelayer, quoteTimestamp,