Skip to content
This repository was archived by the owner on Jun 16, 2025. It is now read-only.

Commit 2ecd04f

Browse files
committed
deploy: adds register router script for solana matching engine
1 parent e2eccbc commit 2ecd04f

File tree

1 file changed

+193
-0
lines changed

1 file changed

+193
-0
lines changed
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import {
2+
ComputeBudgetProgram,
3+
Connection,
4+
PublicKey,
5+
} from "@solana/web3.js";
6+
import "dotenv/config";
7+
import { MatchingEngineProgram } from "@wormhole-foundation/example-liquidity-layer-solana/matchingEngine";
8+
import { LoggerFn, connectionCommitmentLevel, contracts, getContractAddress, ledgerSignAndSend, runOnSolana } from "../../helpers";
9+
import { ProgramId } from "@wormhole-foundation/example-liquidity-layer-solana/matchingEngine";
10+
import { SolanaLedgerSigner } from "@xlabs-xyz/ledger-signer-solana";
11+
import { Chain, chainToPlatform, circle, toChain, toChainId } from "@wormhole-foundation/sdk-base";
12+
import { toUniversal } from "@wormhole-foundation/sdk-definitions";
13+
import { TokenRouterProgram } from "@wormhole-foundation/example-liquidity-layer-solana/tokenRouter";
14+
15+
16+
runOnSolana("register-routers-matching-engine", async (chain, signer, log) => {
17+
const matchingEngineId = getContractAddress("MatchingEngine", chain.chainId) as ProgramId;
18+
19+
const env = "Mainnet";
20+
const usdcMint = new PublicKey(circle.usdcContract(env, "Solana"));
21+
const connection = new Connection(chain.rpc, connectionCommitmentLevel);
22+
const matchingEngine = new MatchingEngineProgram(connection, matchingEngineId, usdcMint);
23+
24+
const deployedTokenRouters = contracts['TokenRouterProxy'];
25+
26+
for (const router of deployedTokenRouters) {
27+
const circleDomain = circle.toCircleChainId(chain.network, router.chainId);
28+
const routerChain = toChain(router.chainId);
29+
const routerAddress = toUniversal(routerChain, router.address);
30+
31+
// check if it is already registered
32+
33+
if (router.chainId === 0)
34+
throw new Error('Invalid chainId when registering new router endpoint');
35+
36+
37+
if (Number(router.address) === 0)
38+
throw new Error(`Invalid router address for chainId ${router.chainId}`);
39+
40+
const chainName = toChain(chain.chainId);
41+
if (chain.chainId === toChainId("Solana")) {
42+
throw new Error("not implemented");
43+
// await addSolanaCctpRouterEndpoint(matchingEngine, signer, tokenRouter)
44+
} else if (chainToPlatform(chainName) === "Evm") {
45+
await addCctpRouterEndpoint(matchingEngine, signer, chainName, circleDomain, routerAddress.toString(), null, log);
46+
} else {
47+
throw new Error(`Router registrations not implemented for ${chainName}`);
48+
}
49+
log(`Router endpoint added for chainId ${router.chainId}`);
50+
}
51+
});
52+
53+
54+
async function addCctpRouterEndpoint(
55+
matchingEngine: MatchingEngineProgram,
56+
signer: SolanaLedgerSigner,
57+
foreignChain: Chain,
58+
cctpDomain: number,
59+
foreignEmitter: string,
60+
foreignMintRecipient: string | null,
61+
log: LoggerFn,
62+
) {
63+
await matchingEngine.fetchCustodian().catch((_) => {
64+
throw new Error("no custodian found");
65+
});
66+
67+
const connection = matchingEngine.program.provider.connection;
68+
69+
const foreignChainId = toChainId(foreignChain);
70+
const endpoint = matchingEngine.routerEndpointAddress(foreignChainId);
71+
const exists = await connection.getAccountInfo(endpoint).then((acct) => acct != null);
72+
73+
const endpointAddress = Array.from(toUniversal(foreignChain, foreignEmitter).unwrap());
74+
const endpointMintRecipient =
75+
foreignMintRecipient === null
76+
? null
77+
: Array.from(toUniversal(foreignChain, foreignMintRecipient).unwrap());
78+
79+
const signerPubkey = new PublicKey(await signer.getAddress());
80+
81+
const [registerIx, action] = await (async () => {
82+
if (exists) {
83+
const { address, mintRecipient } = await matchingEngine.fetchRouterEndpointInfo(foreignChainId);
84+
if (
85+
Buffer.from(address).equals(Buffer.from(endpointAddress)) &&
86+
Buffer.from(mintRecipient).equals(
87+
Buffer.from(endpointMintRecipient ?? endpointAddress),
88+
)
89+
) {
90+
return [null, "already exists"] as const;
91+
} else {
92+
// TODO: check that signer pubkey is owner
93+
const registerIx = await matchingEngine.updateCctpRouterEndpointIx(
94+
{ owner: signerPubkey },
95+
{
96+
chain: foreignChainId,
97+
address: endpointAddress,
98+
mintRecipient: endpointMintRecipient,
99+
cctpDomain,
100+
},
101+
);
102+
return [registerIx, "updated"] as const;
103+
}
104+
} else {
105+
const registerIx = await matchingEngine.addCctpRouterEndpointIx(
106+
{
107+
ownerOrAssistant: signerPubkey,
108+
},
109+
{
110+
chain: foreignChainId,
111+
address: endpointAddress,
112+
mintRecipient: endpointMintRecipient,
113+
cctpDomain,
114+
},
115+
);
116+
return [registerIx, "added"] as const;
117+
}
118+
})();
119+
120+
if (action === "already exists") {
121+
log(
122+
"endpoint already exists",
123+
foreignChain,
124+
"addr",
125+
foreignEmitter,
126+
"domain",
127+
cctpDomain,
128+
"mintRecipient",
129+
foreignMintRecipient,
130+
);
131+
} else {
132+
const priorityFeeIx = ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 });
133+
const instructions = [registerIx, priorityFeeIx]
134+
const txSig = await ledgerSignAndSend(connection, instructions, []);
135+
log(
136+
`${action} endpoint`,
137+
txSig,
138+
"foreignChain",
139+
foreignChain,
140+
"addr",
141+
foreignEmitter,
142+
"domain",
143+
cctpDomain,
144+
"mintRecipient",
145+
foreignMintRecipient,
146+
);
147+
}
148+
}
149+
150+
async function addSolanaCctpRouterEndpoint(
151+
matchingEngine: MatchingEngineProgram,
152+
signer: SolanaLedgerSigner,
153+
tokenRouter: TokenRouterProgram,
154+
log: LoggerFn,
155+
) {
156+
await matchingEngine.fetchCustodian().catch((_) => {
157+
throw new Error("no custodian found");
158+
});
159+
160+
const connection = matchingEngine.program.provider.connection;
161+
162+
const chain = toChainId("Solana");
163+
const endpoint = matchingEngine.routerEndpointAddress(chain);
164+
const exists = await connection.getAccountInfo(endpoint).then((acct) => acct != null);
165+
166+
const endpointAddress = Array.from(
167+
toUniversal("Solana", tokenRouter.custodianAddress().toString()).unwrap(),
168+
);
169+
const endpointMintRecipient = Array.from(
170+
toUniversal("Solana", tokenRouter.cctpMintRecipientAddress().toString()).unwrap(),
171+
);
172+
173+
if (exists) {
174+
const { address, mintRecipient } = await matchingEngine.fetchRouterEndpointInfo(chain);
175+
if (
176+
Buffer.from(address).equals(Buffer.from(endpointAddress)) &&
177+
Buffer.from(mintRecipient).equals(Buffer.from(endpointMintRecipient ?? endpointAddress))
178+
) {
179+
log("local endpoint already exists", endpoint.toString());
180+
return;
181+
}
182+
}
183+
184+
const signerPubkey = new PublicKey(await signer.getAddress());
185+
const registerIx = await matchingEngine.addLocalRouterEndpointIx({
186+
ownerOrAssistant: signerPubkey,
187+
tokenRouterProgram: tokenRouter.ID,
188+
});
189+
const priorityFeeIx = ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 });
190+
const instructions = [registerIx, priorityFeeIx];
191+
const txSig = await ledgerSignAndSend(connection, instructions, []);
192+
log("added local endpoint", txSig, "router", tokenRouter.ID.toString());
193+
}

0 commit comments

Comments
 (0)