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