Skip to content

Commit cbd7773

Browse files
authored
feat(svm): codama and solana kit route tests (#915)
Signed-off-by: Pablo Maldonado <pablo@umaproject.org>
1 parent 466127e commit cbd7773

File tree

7 files changed

+468
-331
lines changed

7 files changed

+468
-331
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"generate-svm-clients": "yarn ts-node ./scripts/svm/utils/generate-svm-clients.ts && yarn ts-node ./scripts/svm/utils/rename-clients-imports.ts",
3131
"build-evm": "hardhat compile",
3232
"build-svm": "echo 'Generating IDLs...' && anchor build > /dev/null 2>&1 || true && anchor run generateExternalTypes && anchor build",
33-
"build-ts": "tsc && rsync -a --include '*/' --include '*.d.ts' --exclude '*' ./typechain ./dist/",
33+
"build-ts": "rm -rf ./dist && tsc && rsync -a --include '*/' --include '*.d.ts' --exclude '*' ./typechain ./dist/",
3434
"copy-idl": "mkdir -p dist/src/svm/assets/idl && cp src/svm/assets/idl/*.json dist/src/svm/assets/idl/",
3535
"build": "yarn build-evm && yarn build-svm && yarn generate-svm-assets && yarn build-ts && yarn copy-idl",
3636
"test-evm": "IS_TEST=true hardhat test",
@@ -53,8 +53,8 @@
5353
"@openzeppelin/contracts-upgradeable": "4.9.6",
5454
"@scroll-tech/contracts": "^0.1.0",
5555
"@solana-developers/helpers": "^2.4.0",
56+
"@solana/kit": "^2.1.0",
5657
"@solana/spl-token": "^0.4.6",
57-
"@solana/web3-v2.js": "npm:@solana/web3.js@2",
5858
"@solana/web3.js": "^1.31.0",
5959
"@types/yargs": "^17.0.33",
6060
"@uma/common": "^2.37.3",

scripts/svm/queryEventsV2.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This script queries the events of the spoke pool and prints them in a human readable format.
22
import { AnchorProvider } from "@coral-xyz/anchor";
3-
import { address, createSolanaRpc } from "@solana/web3-v2.js";
3+
import { address, createSolanaRpc } from "@solana/kit";
44
import { stringifyCpiEvent } from "../../src/svm/web3-v1";
55
import { SvmSpokeIdl } from "../../src/svm";
66
import yargs from "yargs";

scripts/svm/utils/rename-clients-imports.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ function replaceInFiles(dir: string): void {
1313
replaceInFiles(filePath);
1414
} else if (file.endsWith(".ts")) {
1515
const fileContent = fs.readFileSync(filePath, "utf8");
16-
const updatedContent = fileContent.replace("@solana/web3.js", "@solana/web3-v2.js");
16+
const updatedContent = fileContent.replace("@solana/web3.js", "@solana/kit");
1717
fs.writeFileSync(filePath, updatedContent);
1818
}
1919
});

src/svm/web3-v2/solanaProgramUtils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import web3, {
66
GetTransactionApi,
77
RpcTransport,
88
Signature,
9-
} from "@solana/web3-v2.js";
9+
} from "@solana/kit";
1010

1111
type GetTransactionReturnType = ReturnType<GetTransactionApi["getTransaction"]>;
1212

test/svm/SvmSpoke.Routes.ts

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
import * as anchor from "@coral-xyz/anchor";
22
import { BN } from "@coral-xyz/anchor";
3+
import {
4+
address,
5+
appendTransactionMessageInstruction,
6+
createKeyPairFromBytes,
7+
createSignerFromKeyPair,
8+
getProgramDerivedAddress,
9+
pipe,
10+
} from "@solana/kit";
311
import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID, createMint, getAccount } from "@solana/spl-token";
4-
import { PublicKey, Keypair } from "@solana/web3.js";
12+
import { Keypair, PublicKey } from "@solana/web3.js";
513
import { assert } from "chai";
6-
import { common } from "./SvmSpoke.common";
14+
import { SvmSpokeClient } from "../../src/svm";
15+
import { SetEnableRouteInput } from "../../src/svm/clients/SvmSpoke";
716
import { readEventsUntilFound } from "../../src/svm/web3-v1";
17+
import { common } from "./SvmSpoke.common";
18+
import { createDefaultSolanaClient, createDefaultTransaction, signAndSendTransaction } from "./utils";
819

920
const { provider, program, owner, initializeState, createRoutePda, getVaultAta } = common;
1021

@@ -116,4 +127,56 @@ describe("svm_spoke.routes", () => {
116127
assert.strictEqual(err.error.errorCode.code, "InvalidMint", "Expected error code InvalidMint");
117128
}
118129
});
130+
131+
describe("codama client and solana kit", () => {
132+
it("Sets and retrieves route enablement with codama", async () => {
133+
const rpcClient = createDefaultSolanaClient();
134+
const signer = await createSignerFromKeyPair(
135+
await createKeyPairFromBytes((anchor.AnchorProvider.env().wallet as anchor.Wallet).payer.secretKey)
136+
);
137+
138+
const [eventAuthority] = await getProgramDerivedAddress({
139+
programAddress: address(program.programId.toString()),
140+
seeds: ["__event_authority"],
141+
});
142+
143+
const input: SetEnableRouteInput = {
144+
signer: signer,
145+
payer: signer,
146+
state: address(state.toString()),
147+
route: address(routePda.toString()),
148+
vault: address(vault.toString()),
149+
originTokenMint: address(tokenMint.toString()),
150+
tokenProgram: address(TOKEN_PROGRAM_ID.toString()),
151+
associatedTokenProgram: address(ASSOCIATED_TOKEN_PROGRAM_ID.toString()),
152+
systemProgram: address(anchor.web3.SystemProgram.programId.toString()),
153+
eventAuthority: address(eventAuthority.toString()),
154+
program: address(program.programId.toString()),
155+
originToken: address(tokenMint.toString()),
156+
destinationChainId: routeChainId.toNumber(),
157+
enabled: true,
158+
};
159+
const instructions = SvmSpokeClient.getSetEnableRouteInstruction(input);
160+
const tx = await pipe(
161+
await createDefaultTransaction(rpcClient, signer),
162+
(tx) => appendTransactionMessageInstruction(instructions, tx),
163+
(tx) => signAndSendTransaction(rpcClient, tx)
164+
);
165+
166+
// Retrieve and verify the route is enabled
167+
let routeAccount = await SvmSpokeClient.fetchRoute(rpcClient.rpc, address(routePda.toString()));
168+
assert.isTrue(routeAccount.data.enabled, "Route should be enabled");
169+
170+
// Verify the enabledDepositRoute event
171+
let events = await readEventsUntilFound(provider.connection, tx, [program]);
172+
let event = events[0].data;
173+
assert.strictEqual(event.originToken.toString(), tokenMint.toString(), "originToken event match");
174+
assert.strictEqual(
175+
event.destinationChainId.toString(),
176+
routeChainId.toString(),
177+
"destinationChainId should match"
178+
);
179+
assert.isTrue(event.enabled, "enabledDepositRoute enabled");
180+
});
181+
});
119182
});

test/svm/utils.ts

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,31 @@
11
import { BN, Program, workspace } from "@coral-xyz/anchor";
2+
import {
3+
airdropFactory,
4+
Commitment,
5+
CompilableTransactionMessage,
6+
createSolanaRpc,
7+
createSolanaRpcSubscriptions,
8+
createTransactionMessage,
9+
generateKeyPairSigner,
10+
getSignatureFromTransaction,
11+
lamports,
12+
pipe,
13+
Rpc,
14+
RpcSubscriptions,
15+
RpcTransport,
16+
sendAndConfirmTransactionFactory,
17+
setTransactionMessageFeePayerSigner,
18+
setTransactionMessageLifetimeUsingBlockhash,
19+
SignatureNotificationsApi,
20+
signTransactionMessageWithSigners,
21+
SlotNotificationsApi,
22+
SolanaRpcApiFromTransport,
23+
TransactionMessageWithBlockhashLifetime,
24+
TransactionSigner,
25+
} from "@solana/kit";
226
import { AccountMeta, Keypair, PublicKey } from "@solana/web3.js";
327
import * as crypto from "crypto";
428
import { BigNumber, ethers } from "ethers";
5-
import { MulticallHandler } from "../../target/types/multicall_handler";
629
import {
730
AcrossPlusMessageCoder,
831
calculateRelayHashUint8Array,
@@ -12,6 +35,8 @@ import {
1235
readProgramEvents,
1336
relayerRefundHashFn,
1437
} from "../../src/svm";
38+
import { MulticallHandler } from "../../target/types/multicall_handler";
39+
1540
import { MerkleTree } from "@uma/common";
1641
import { RelayerRefundLeaf, RelayerRefundLeafType } from "../../src/types/svm";
1742

@@ -143,3 +168,46 @@ export function testAcrossPlusMessage() {
143168
];
144169
return { encodedMessage, fillRemainingAccounts };
145170
}
171+
172+
export const signAndSendTransaction = async (
173+
rpcClient: RpcClient,
174+
transactionMessage: CompilableTransactionMessage & TransactionMessageWithBlockhashLifetime,
175+
commitment: Commitment = "confirmed"
176+
) => {
177+
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
178+
const signature = getSignatureFromTransaction(signedTransaction);
179+
await sendAndConfirmTransactionFactory(rpcClient)(signedTransaction, {
180+
commitment,
181+
});
182+
return signature;
183+
};
184+
185+
export const createDefaultTransaction = async (rpcClient: RpcClient, signer: TransactionSigner) => {
186+
const { value: latestBlockhash } = await rpcClient.rpc.getLatestBlockhash().send();
187+
return pipe(
188+
createTransactionMessage({ version: 0 }),
189+
(tx) => setTransactionMessageFeePayerSigner(signer, tx),
190+
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx)
191+
);
192+
};
193+
194+
export const createDefaultSolanaClient = () => {
195+
const rpc = createSolanaRpc("http://127.0.0.1:8899");
196+
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://127.0.0.1:8900");
197+
return { rpc, rpcSubscriptions };
198+
};
199+
200+
type RpcClient = {
201+
rpc: Rpc<SolanaRpcApiFromTransport<RpcTransport>>;
202+
rpcSubscriptions: RpcSubscriptions<SignatureNotificationsApi & SlotNotificationsApi>;
203+
};
204+
205+
export const generateKeyPairSignerWithSol = async (rpcClient: RpcClient, putativeLamports: bigint = 1_000_000_000n) => {
206+
const signer = await generateKeyPairSigner();
207+
await airdropFactory(rpcClient)({
208+
recipientAddress: signer.address,
209+
lamports: lamports(putativeLamports),
210+
commitment: "confirmed",
211+
});
212+
return signer;
213+
};

0 commit comments

Comments
 (0)