1
1
import {
2
2
type AptosAccount ,
3
- // (These below helpers remain as before)
4
3
waitForTransactionReceipt ,
5
4
type AptosPublicAccountInfo
6
5
} from "./transfer.ts"
7
- import { err , type Result } from "neverthrow"
6
+ import { ok , err , type Result } from "neverthrow"
8
7
import { Aptos , Network , AptosConfig , AccountAddress , MoveVector } from "@aptos-labs/ts-sdk"
9
8
import { createClient , fallback , type HttpTransport } from "viem"
10
9
import type { AptosBrowserWallet , AuthAccess } from "./wallet.ts"
11
10
11
+ // Define a unified signer type that always includes an accountAddress.
12
+ export type AptosSigner = AptosAccount | ( AptosBrowserWallet & { accountAddress : string } )
13
+
12
14
export type { AptosAccount , AptosBrowserWallet }
13
15
14
16
export const aptosChainId = [
15
- "2" , // aptos testnet
17
+ "2" , // aptos testnet
16
18
"177" , // movement porto
17
- "250" // movement bardock
19
+ "250" // movement bardock
18
20
] as const
19
21
export type AptosChainId = `${( typeof aptosChainId ) [ number ] } `
20
22
@@ -31,23 +33,25 @@ export type AptosClientParameters = {
31
33
| { account : AptosAccount ; transport : HttpTransport }
32
34
| { account ?: AptosPublicAccountInfo ; transport : AptosWindowTransport }
33
35
)
36
+ export type WalletSigner = AptosBrowserWallet & { accountAddress : string } ;
34
37
35
38
/**
36
39
* Overloads for retrieving an Aptos client.
37
40
*/
38
41
async function getAptosClient (
39
42
parameters : AptosClientParameters & { authAccess : "key" }
40
- ) : Promise < { authAccess : "key" ; aptos : Aptos ; signer : AptosAccount } >
43
+ ) : Promise < { authAccess : "key" ; aptos : Aptos ; signer : AptosSigner ; transport : HttpTransport } > ;
44
+
45
+ async function getAptosClient (
46
+ parameters : AptosClientParameters & { authAccess : "wallet" }
47
+ ) : Promise < { authAccess : "wallet" ; aptos : Aptos ; signer : AptosSigner ; transport : AptosWindowTransport } > ;
41
48
42
- // async function getAptosClient(
43
- // parameters: AptosClientParameters & { authAccess: "wallet" }
44
- // ): Promise<{ authAccess: "wallet"; aptos: Aptos; signer: AptosBrowserWallet }>
45
49
46
50
async function getAptosClient (
47
51
parameters : AptosClientParameters & { authAccess : AuthAccess }
48
52
) : Promise <
49
- | { authAccess : "key" ; aptos : Aptos ; signer : AptosAccount }
50
- | { authAccess : "wallet" ; aptos : Aptos ; signer : AptosBrowserWallet }
53
+ | { authAccess : "key" ; aptos : Aptos ; signer : AptosSigner ; transport : HttpTransport }
54
+ | { authAccess : "wallet" ; aptos : Aptos ; signer : AptosSigner ; transport : AptosWindowTransport }
51
55
> {
52
56
if ( parameters . authAccess === "key" ) {
53
57
if ( typeof parameters . transport !== "function" ) {
@@ -62,7 +66,8 @@ async function getAptosClient(
62
66
return {
63
67
authAccess : "key" ,
64
68
aptos : new Aptos ( config ) ,
65
- signer : parameters . account as AptosAccount
69
+ signer : parameters . account as AptosAccount , // AptosAccount is assumed to have accountAddress
70
+ transport : parameters . transport
66
71
}
67
72
}
68
73
@@ -71,20 +76,36 @@ async function getAptosClient(
71
76
throw new Error ( "Invalid Aptos transport" )
72
77
}
73
78
const networkInfo = await parameters . transport . getNetwork ( )
74
- const network = networkInfo . name . toLowerCase ( ) === "mainnet" ? Network . MAINNET : Network . TESTNET
79
+ const network =
80
+ networkInfo . name . toLowerCase ( ) === "mainnet" ? Network . MAINNET : Network . TESTNET
75
81
const config = new AptosConfig ( { fullnode : networkInfo . url , network } )
82
+
83
+ // Get the connected account
84
+ const account = await parameters . transport . getAccount ?.( ) ||
85
+ { address : "" }
86
+ if ( ! account . address ) {
87
+ throw new Error ( "No account address found from the wallet" )
88
+ }
89
+
90
+ // Create a signer by merging the wallet’s methods with the account address.
91
+ const signer = Object . assign ( { } , parameters . transport , {
92
+ accountAddress : account . address
93
+ } ) as unknown as AptosAccount // <== Force-cast to AptosAccount
94
+
76
95
return {
77
96
authAccess : "wallet" ,
78
97
aptos : new Aptos ( config ) ,
79
- signer : parameters . transport as AptosBrowserWallet
98
+ signer : signer ,
99
+ transport : parameters . transport
80
100
}
81
101
}
102
+
103
+
82
104
throw new Error ( "Invalid Aptos transport" )
83
105
}
84
106
85
107
/**
86
- * New unified transfer parameters for Aptos,
87
- * matching the Cosmos & EVM clients.
108
+ * New unified transfer parameters for Aptos, matching the Cosmos & EVM clients.
88
109
*/
89
110
export interface TransferAssetParameters < AptosChainId > {
90
111
baseAmount : bigint
@@ -102,17 +123,22 @@ export interface TransferAssetParameters<AptosChainId> {
102
123
*/
103
124
export const createAptosClient = ( clientParameters : AptosClientParameters ) => {
104
125
return createClient ( { transport : fallback ( [ ] ) } )
105
- . extend ( _ => ( {
106
- // A helper to get the underlying Aptos client.
107
- // We default to "key" if an account was provided.
108
- getAptosClient : async ( ) => await getAptosClient ( { ...clientParameters , authAccess : "key" } )
109
- // clientParameters.account
110
- // ? await getAptosClient({ ...clientParameters, authAccess: "key" })
111
- // : await getAptosClient({ ...clientParameters, authAccess: "wallet" })
126
+ . extend ( ( ) => ( {
127
+ getAptosClient : async ( ) => {
128
+ console . info ( "create aptos client params:" , clientParameters )
129
+ // Use the transport type to determine which client to create.
130
+ if ( typeof clientParameters . transport === "function" ) {
131
+ console . info ( "returning key-based client" )
132
+ return await getAptosClient ( { ...clientParameters , authAccess : "key" } )
133
+ } else {
134
+ console . info ( "returning wallet-based client" )
135
+ return await getAptosClient ( { ...clientParameters , authAccess : "wallet" } )
136
+ }
137
+ }
112
138
} ) )
113
139
. extend ( client => ( {
114
140
waitForTransactionReceipt : async ( { hash } : { hash : string } ) => {
115
- const { aptos, signer } = await client . getAptosClient ( )
141
+ const { aptos } = await client . getAptosClient ( )
116
142
return await waitForTransactionReceipt ( { aptos, hash } )
117
143
} ,
118
144
@@ -129,47 +155,93 @@ export const createAptosClient = (clientParameters: AptosClientParameters) => {
129
155
sourceChannelId,
130
156
ucs03address
131
157
} : TransferAssetParameters < AptosChainId > ) : Promise < Result < string , Error > > => {
132
- const { aptos, signer } = await client . getAptosClient ( )
133
-
134
- const baseTokenHex = baseToken . startsWith ( "0x" ) ? baseToken . slice ( 2 ) : baseToken // Remove "0x" if it exists
135
- // let my_addr = AccountAddress.fromHex(baseToken)
158
+ const { aptos, signer, authAccess, transport } = await client . getAptosClient ( ) ;
136
159
137
160
const quoteTokenVec = MoveVector . U8 ( quoteToken )
138
161
const receiverVec = MoveVector . U8 ( receiver )
139
162
140
- const rawSalt = new Uint8Array ( 32 )
163
+ const rawSalt = new Uint8Array ( 14 )
141
164
crypto . getRandomValues ( rawSalt )
142
165
const salt = MoveVector . U8 ( rawSalt )
143
166
144
- const payload = await aptos . transaction . build . simple ( {
145
- sender : signer . accountAddress ,
146
- data : {
147
- function : `${ ucs03address } ::ibc_app::transfer` ,
148
- typeArguments : [ ] ,
149
- functionArguments : [
150
- sourceChannelId ,
151
- receiverVec ,
152
- AccountAddress . fromString ( baseToken ) ,
153
- baseAmount ,
154
- quoteTokenVec ,
155
- quoteAmount ,
156
- 18446744073709551615n ,
157
- 18446744073709551615n ,
158
- salt
159
- ]
160
- }
161
- } )
162
-
163
167
try {
164
- const txn = await aptos . signAndSubmitTransaction ( {
165
- signer : signer ,
166
- transaction : payload
167
- } )
168
- const receipt = await waitForTransactionReceipt ( { aptos, hash : txn . hash } )
169
- return receipt
168
+ let txn ;
169
+ if ( authAccess === "key" ) {
170
+ console . info ( "key-based flow" )
171
+ // Key-based flow using the full AptosAccount
172
+ const payload = await aptos . transaction . build . simple ( {
173
+ sender : signer . accountAddress ,
174
+ data : {
175
+ function : `${ ucs03address } ::ibc_app::transfer` ,
176
+ typeArguments : [ ] ,
177
+ functionArguments : [
178
+ sourceChannelId ,
179
+ receiverVec ,
180
+ AccountAddress . fromString ( baseToken ) ,
181
+ baseAmount ,
182
+ quoteTokenVec ,
183
+ quoteAmount ,
184
+ 18446744073709551615n ,
185
+ 18446744073709551615n ,
186
+ salt
187
+ ]
188
+ }
189
+ } )
190
+
191
+ txn = await aptos . signAndSubmitTransaction ( {
192
+ signer : signer as AptosAccount ,
193
+ transaction : payload
194
+ } ) ;
195
+ const receipt = await waitForTransactionReceipt ( { aptos, hash : txn . hash } ) ;
196
+ return receipt ;
197
+ } else {
198
+
199
+ const saltHex = toHex ( new Uint8Array ( 14 ) ) ;
200
+ // 14 bytes + 0x 2 bytes and that walletPayload encodes it in it
201
+ // so it becomes 32 byte.
202
+ const walletPayload = {
203
+ function : `${ ucs03address } ::ibc_app::transfer` ,
204
+ type_arguments : [ ] ,
205
+ arguments : [
206
+ sourceChannelId . toString ( ) ,
207
+ hexToAscii ( receiver ) , // It is hexing again in it.
208
+ baseToken ,
209
+ baseAmount . toString ( ) ,
210
+ hexToAscii ( quoteToken ) , // It is hexing again in it.
211
+ quoteAmount . toString ( ) ,
212
+ 18446744073709551615n . toString ( ) ,
213
+ 18446744073709551615n . toString ( ) ,
214
+ saltHex
215
+ ]
216
+ } ;
217
+ try {
218
+ const signedTxn = await transport . signAndSubmitTransaction ( { payload : walletPayload } ) ;
219
+ return ok ( signedTxn . hash ) ; // Wrap the string in a successful Result
220
+ } catch ( error ) {
221
+ return err ( new Error ( "Transaction signing failed" ) ) ;
222
+ }
223
+ }
170
224
} catch ( error ) {
225
+ console . info ( "error is:" , error )
171
226
return err ( new Error ( "failed to execute aptos call" , { cause : error as Error } ) )
172
227
}
173
228
}
174
229
} ) )
175
230
}
231
+ function toHex ( uint8array : Uint8Array ) : string {
232
+ return "0x" + Array . from ( uint8array )
233
+ . map ( b => b . toString ( 16 ) . padStart ( 2 , "0" ) )
234
+ . join ( "" ) ;
235
+ }
236
+
237
+ function hexToAscii ( hexString : string ) : string {
238
+ // Remove the "0x" prefix if present.
239
+ if ( hexString . startsWith ( "0x" ) || hexString . startsWith ( "0X" ) ) {
240
+ hexString = hexString . slice ( 2 ) ;
241
+ }
242
+ let ascii = "" ;
243
+ for ( let i = 0 ; i < hexString . length ; i += 2 ) {
244
+ ascii += String . fromCharCode ( parseInt ( hexString . substr ( i , 2 ) , 16 ) ) ;
245
+ }
246
+ return ascii ;
247
+ }
0 commit comments