Skip to content

Commit cb2a0e2

Browse files
committed
devnet test sets up sepoolia chains
1 parent eada048 commit cb2a0e2

File tree

2 files changed

+185
-1
lines changed

2 files changed

+185
-1
lines changed

svm/pinocchio/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ Solana programs for the executor quoter system.
99

1010
These programs use the [Pinocchio](https://github.com/febo/pinocchio) framework, but quoter implementations are framework-agnostic. Any program adhering to the CPI interface defined by the router will work.
1111

12+
## Devnet Deployments
13+
14+
| Program | Address |
15+
|---------|---------|
16+
| executor-quoter | `957QU51h6VLbnbAmAPgtXz1kbFE1QhchDmNfgugW9xCc` |
17+
| executor-quoter-router | `5pkyS8pnbbMforEqAR91gkgPeBs5XKhWpiuuuLdw6hbk` |
18+
1219
## Directory Structure
1320

1421
- `programs/executor-quoter/` - Example quoter implementation

svm/tests/executor-quoters.test.ts

Lines changed: 178 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,86 @@ const IX_ROUTER_QUOTE_EXECUTION = 1;
3939
const CHAIN_ID_SOLANA = 1;
4040
const CHAIN_ID_ETHEREUM = 2;
4141

42+
// Testnet chain IDs
43+
const CHAIN_ID_ETH_SEPOLIA = 10002;
44+
const CHAIN_ID_ARBITRUM_SEPOLIA = 10003;
45+
const CHAIN_ID_BASE_SEPOLIA = 10004;
46+
const CHAIN_ID_OPTIMISM_SEPOLIA = 10005;
47+
4248
// Quote calculation constants (must match Rust)
4349
const QUOTE_DECIMALS = 10n;
4450
const SVM_DECIMAL_RESOLUTION = 9n;
4551
const EVM_DECIMAL_RESOLUTION = 18n;
4652

47-
// Test quote parameters
53+
// Test quote parameters for mainnet Ethereum
4854
const TEST_DST_PRICE = 3000n * 10n ** QUOTE_DECIMALS; // ETH $3000
4955
const TEST_SRC_PRICE = 200n * 10n ** QUOTE_DECIMALS; // SOL $200
5056
const TEST_DST_GAS_PRICE = 20n; // 20 gwei (decimals=9)
5157
const TEST_BASE_FEE = 1_000_000n; // 0.001 SOL in lamports
5258
const TEST_GAS_PRICE_DECIMALS = 9; // gwei decimals
5359
const TEST_NATIVE_DECIMALS = 18; // ETH decimals
5460

61+
// Testnet chain configurations with realistic gas prices
62+
// All testnets use ETH as native token (18 decimals)
63+
// Gas prices vary by L2 characteristics
64+
interface ChainConfig {
65+
chainId: number;
66+
name: string;
67+
dstPrice: bigint; // Native token price in QUOTE_DECIMALS
68+
gasPriceDecimals: number;
69+
nativeDecimals: number;
70+
dstGasPrice: bigint; // Gas price in gasPriceDecimals
71+
baseFee: bigint; // Base fee in lamports
72+
}
73+
74+
const TESTNET_CHAINS: ChainConfig[] = [
75+
{
76+
// Ethereum Sepolia - standard L1 gas prices
77+
// All EVM chains store gas price in wei (gasPriceDecimals=18)
78+
// Reference: w7-executor/src/env/testnet.ts
79+
chainId: CHAIN_ID_ETH_SEPOLIA,
80+
name: "Ethereum Sepolia",
81+
dstPrice: 3000n * 10n ** QUOTE_DECIMALS, // ETH ~$3000
82+
gasPriceDecimals: 18, // gas price stored in wei
83+
nativeDecimals: 18,
84+
dstGasPrice: 25_000_000_000n, // 25 gwei in wei
85+
baseFee: 1_000_000n, // 0.001 SOL
86+
},
87+
{
88+
// Arbitrum Sepolia - L2 with lower gas prices
89+
// Arbitrum min gas price floor is 0.01 gwei
90+
chainId: CHAIN_ID_ARBITRUM_SEPOLIA,
91+
name: "Arbitrum Sepolia",
92+
dstPrice: 3000n * 10n ** QUOTE_DECIMALS, // ETH ~$3000
93+
gasPriceDecimals: 18, // gas price stored in wei
94+
nativeDecimals: 18,
95+
dstGasPrice: 100_000_000n, // 0.1 gwei in wei
96+
baseFee: 500_000n, // 0.0005 SOL (lower for L2)
97+
},
98+
{
99+
// Base Sepolia - L2 with very low gas prices
100+
// Base typically has gas prices around 0.001-0.01 gwei
101+
chainId: CHAIN_ID_BASE_SEPOLIA,
102+
name: "Base Sepolia",
103+
dstPrice: 3000n * 10n ** QUOTE_DECIMALS, // ETH ~$3000
104+
gasPriceDecimals: 18, // gas price stored in wei
105+
nativeDecimals: 18,
106+
dstGasPrice: 10_000_000n, // 0.01 gwei in wei
107+
baseFee: 500_000n, // 0.0005 SOL
108+
},
109+
{
110+
// Optimism Sepolia - L2 with low gas prices
111+
// OP typically has gas prices around 0.001-0.05 gwei
112+
chainId: CHAIN_ID_OPTIMISM_SEPOLIA,
113+
name: "Optimism Sepolia",
114+
dstPrice: 3000n * 10n ** QUOTE_DECIMALS, // ETH ~$3000
115+
gasPriceDecimals: 18, // gas price stored in wei
116+
nativeDecimals: 18,
117+
dstGasPrice: 50_000_000n, // 0.05 gwei in wei
118+
baseFee: 500_000n, // 0.0005 SOL
119+
},
120+
];
121+
55122
// Test request parameters
56123
const TEST_GAS_LIMIT = 100_000n;
57124
const TEST_MSG_VALUE = 10n ** 18n; // 1 ETH in wei
@@ -578,6 +645,116 @@ describe("executor-quoter", () => {
578645
});
579646
});
580647

648+
describe("executor-quoter testnet chains", () => {
649+
beforeAll(async () => {
650+
connection = new Connection("https://api.devnet.solana.com", "confirmed");
651+
wallet = loadWallet();
652+
[quoterConfigPda] = deriveQuoterConfigPda();
653+
});
654+
655+
for (const chain of TESTNET_CHAINS) {
656+
test(`updates chain info for ${chain.name} (${chain.chainId})`, async () => {
657+
const [chainInfoPda] = deriveQuoterChainInfoPda(chain.chainId);
658+
659+
const ix = new TransactionInstruction({
660+
programId: QUOTER_PROGRAM_ID,
661+
keys: [
662+
{ pubkey: wallet.publicKey, isSigner: true, isWritable: true },
663+
{ pubkey: wallet.publicKey, isSigner: true, isWritable: false },
664+
{ pubkey: chainInfoPda, isSigner: false, isWritable: true },
665+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
666+
],
667+
data: buildUpdateChainInfoData(
668+
chain.chainId,
669+
1, // enabled
670+
chain.gasPriceDecimals,
671+
chain.nativeDecimals,
672+
),
673+
});
674+
675+
const tx = new Transaction().add(ix);
676+
await sendAndConfirmTransaction(connection, tx, [wallet]);
677+
678+
const accountInfo = await connection.getAccountInfo(chainInfoPda);
679+
expect(accountInfo).not.toBeNull();
680+
console.log(` Chain info PDA for ${chain.name}: ${chainInfoPda.toBase58()}`);
681+
});
682+
683+
test(`updates quote for ${chain.name} (${chain.chainId})`, async () => {
684+
const [quoteBodyPda] = deriveQuoterQuoteBodyPda(chain.chainId);
685+
686+
const ix = new TransactionInstruction({
687+
programId: QUOTER_PROGRAM_ID,
688+
keys: [
689+
{ pubkey: wallet.publicKey, isSigner: true, isWritable: true },
690+
{ pubkey: wallet.publicKey, isSigner: true, isWritable: false },
691+
{ pubkey: quoteBodyPda, isSigner: false, isWritable: true },
692+
{ pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
693+
],
694+
data: buildUpdateQuoteData(
695+
chain.chainId,
696+
chain.dstPrice,
697+
TEST_SRC_PRICE,
698+
chain.dstGasPrice,
699+
chain.baseFee
700+
),
701+
});
702+
703+
const tx = new Transaction().add(ix);
704+
await sendAndConfirmTransaction(connection, tx, [wallet]);
705+
706+
const accountInfo = await connection.getAccountInfo(quoteBodyPda);
707+
expect(accountInfo).not.toBeNull();
708+
console.log(` Quote body PDA for ${chain.name}: ${quoteBodyPda.toBase58()}`);
709+
});
710+
711+
test(`returns correct quote for ${chain.name} (${chain.chainId})`, async () => {
712+
const [chainInfoPda] = deriveQuoterChainInfoPda(chain.chainId);
713+
const [quoteBodyPda] = deriveQuoterQuoteBodyPda(chain.chainId);
714+
715+
const dstAddr = new Uint8Array(32).fill(0xAB);
716+
const refundAddr = new Uint8Array(32);
717+
wallet.publicKey.toBuffer().copy(Buffer.from(refundAddr));
718+
719+
const ix = new TransactionInstruction({
720+
programId: QUOTER_PROGRAM_ID,
721+
keys: [
722+
{ pubkey: quoterConfigPda, isSigner: false, isWritable: false },
723+
{ pubkey: chainInfoPda, isSigner: false, isWritable: false },
724+
{ pubkey: quoteBodyPda, isSigner: false, isWritable: false },
725+
],
726+
data: buildRequestQuoteData(
727+
chain.chainId,
728+
dstAddr,
729+
refundAddr,
730+
new Uint8Array(0),
731+
buildGasRelayInstruction(TEST_GAS_LIMIT, TEST_MSG_VALUE)
732+
),
733+
});
734+
735+
const { returnData } = await simulateInstruction(connection, wallet, ix);
736+
737+
expect(returnData.length).toBe(8);
738+
const payment = returnData.readBigUInt64BE(0);
739+
740+
// Calculate expected quote
741+
const expectedQuote = calculateExpectedQuote(
742+
chain.baseFee,
743+
TEST_SRC_PRICE,
744+
chain.dstPrice,
745+
chain.dstGasPrice,
746+
chain.gasPriceDecimals,
747+
chain.nativeDecimals,
748+
TEST_GAS_LIMIT,
749+
TEST_MSG_VALUE
750+
);
751+
752+
expect(payment).toBe(expectedQuote);
753+
console.log(` Quote for ${chain.name}: ${payment} lamports (${Number(payment) / 1e9} SOL)`);
754+
});
755+
}
756+
});
757+
581758
describe("executor-quoter-router", () => {
582759
beforeAll(async () => {
583760
connection = new Connection("https://api.devnet.solana.com", "confirmed");

0 commit comments

Comments
 (0)