@fystack/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +6 -0
- package/dist/index.cjs +962 -0
- package/dist/index.d.cts +611 -0
- package/dist/index.d.mts +611 -0
- package/dist/index.esm.d.ts +611 -0
- package/dist/index.esm.js +941 -0
- package/dist/index.mjs +941 -0
- package/dist/types/index.d.ts +611 -0
- package/package.json +45 -0
- package/src/api.ts +332 -0
- package/src/config.ts +75 -0
- package/src/index.ts +7 -0
- package/src/payment.ts +268 -0
- package/src/sdk.ts +140 -0
- package/src/signer.ts +392 -0
- package/src/solanaSigner.ts +243 -0
- package/src/types.ts +161 -0
- package/src/utils/statusPoller.ts +82 -0
- package/src/utils.ts +101 -0
- package/test.js +76 -0
- package/tsconfig.json +18 -0
- package/vite-env.d.ts +1 -0
- package/vitest.config.js +10 -0
package/src/sdk.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { APIService } from './api'
|
|
2
|
+
import { APICredentials, CreateWalletOptions } from './types'
|
|
3
|
+
import { Environment } from './config'
|
|
4
|
+
import { StatusPoller } from './utils/statusPoller'
|
|
5
|
+
import {
|
|
6
|
+
WalletCreationStatus,
|
|
7
|
+
CreateWalletResponse,
|
|
8
|
+
WalletCreationStatusResponse,
|
|
9
|
+
WalletType,
|
|
10
|
+
WalletAsset,
|
|
11
|
+
AddressType,
|
|
12
|
+
DepositAddressResponse
|
|
13
|
+
} from './types'
|
|
14
|
+
import { validateUUID } from './utils'
|
|
15
|
+
|
|
16
|
+
export interface SDKOptions {
|
|
17
|
+
credentials: APICredentials
|
|
18
|
+
environment?: Environment
|
|
19
|
+
logger?: boolean
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class FystackSDK {
|
|
23
|
+
private apiService: APIService
|
|
24
|
+
private enableLogging: boolean
|
|
25
|
+
|
|
26
|
+
constructor(options: SDKOptions) {
|
|
27
|
+
const { credentials, environment = Environment.Production, logger = false } = options
|
|
28
|
+
this.apiService = new APIService(credentials, environment)
|
|
29
|
+
this.enableLogging = logger
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private log(message: string): void {
|
|
33
|
+
if (this.enableLogging) {
|
|
34
|
+
console.log(`[FystackSDK] ${message}`)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Creates a new wallet
|
|
40
|
+
* @param options Wallet creation options
|
|
41
|
+
* @param waitForCompletion Whether to wait for the wallet creation to complete
|
|
42
|
+
* @returns Promise with wallet ID and status
|
|
43
|
+
*/
|
|
44
|
+
async createWallet(
|
|
45
|
+
options: CreateWalletOptions,
|
|
46
|
+
waitForCompletion: boolean = true
|
|
47
|
+
): Promise<CreateWalletResponse> {
|
|
48
|
+
const { name, walletType = WalletType.Standard } = options
|
|
49
|
+
|
|
50
|
+
const response = await this.apiService.createWallet({
|
|
51
|
+
name,
|
|
52
|
+
walletType
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
if (waitForCompletion && response.status === WalletCreationStatus.Pending) {
|
|
56
|
+
return this.waitForWalletCreation(response.wallet_id)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return response
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Gets the current status of a wallet creation process
|
|
64
|
+
* @param walletId The ID of the wallet being created
|
|
65
|
+
* @returns Promise with wallet creation status details
|
|
66
|
+
*/
|
|
67
|
+
async getWalletCreationStatus(walletId: string): Promise<WalletCreationStatusResponse> {
|
|
68
|
+
const response = await this.apiService.getWalletCreationStatus(walletId)
|
|
69
|
+
return response
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Waits for a wallet to be created and returns the final status
|
|
74
|
+
* @param walletId The ID of the wallet being created
|
|
75
|
+
* @returns Promise with wallet ID and final status
|
|
76
|
+
*/
|
|
77
|
+
private async waitForWalletCreation(walletId: string): Promise<CreateWalletResponse> {
|
|
78
|
+
const poller = new StatusPoller()
|
|
79
|
+
|
|
80
|
+
// Poll for wallet creation status
|
|
81
|
+
const result = await poller.poll<WalletCreationStatusResponse>(
|
|
82
|
+
// Polling function
|
|
83
|
+
async () => {
|
|
84
|
+
this.log('Polling wallet creation status...')
|
|
85
|
+
const response = await this.apiService.getWalletCreationStatus(walletId)
|
|
86
|
+
return response
|
|
87
|
+
},
|
|
88
|
+
// Success condition - when status is either success or error
|
|
89
|
+
(result) =>
|
|
90
|
+
[WalletCreationStatus.Success, WalletCreationStatus.Error].includes(result.status),
|
|
91
|
+
// Error condition - no specific error condition needed, as we're polling until final state
|
|
92
|
+
undefined
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
this.log(`Wallet creation completed with status: ${result.status}`)
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
wallet_id: result.wallet_id,
|
|
99
|
+
status: result.status
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Gets assets associated with a wallet
|
|
105
|
+
* @param walletId The ID of the wallet
|
|
106
|
+
* @returns Promise with wallet assets
|
|
107
|
+
*/
|
|
108
|
+
async getWalletAssets(walletId: string): Promise<WalletAsset[]> {
|
|
109
|
+
if (!walletId || walletId.trim() === '') {
|
|
110
|
+
throw new Error('Invalid wallet ID provided')
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const data = await this.apiService.getWalletAssets(walletId)
|
|
114
|
+
return data
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Gets deposit address for a wallet by address type
|
|
119
|
+
* @param walletId The wallet ID
|
|
120
|
+
* @param addressType The type of address (evm, sol)
|
|
121
|
+
* @returns Promise with deposit address information
|
|
122
|
+
*/
|
|
123
|
+
async getDepositAddress(
|
|
124
|
+
walletId: string,
|
|
125
|
+
addressType: AddressType
|
|
126
|
+
): Promise<DepositAddressResponse> {
|
|
127
|
+
validateUUID(walletId, 'walletId')
|
|
128
|
+
|
|
129
|
+
if (!Object.values(AddressType).includes(addressType)) {
|
|
130
|
+
throw new Error(
|
|
131
|
+
`Invalid address type: ${addressType}. Must be one of: ${Object.values(AddressType).join(
|
|
132
|
+
', '
|
|
133
|
+
)}`
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const depositAddressInfo = await this.apiService.getDepositAddress(walletId, addressType)
|
|
138
|
+
return depositAddressInfo
|
|
139
|
+
}
|
|
140
|
+
}
|
package/src/signer.ts
ADDED
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AbstractSigner,
|
|
3
|
+
TypedDataDomain,
|
|
4
|
+
TypedDataField,
|
|
5
|
+
resolveProperties,
|
|
6
|
+
resolveAddress,
|
|
7
|
+
assertArgument,
|
|
8
|
+
getAddress,
|
|
9
|
+
Transaction,
|
|
10
|
+
TransactionLike,
|
|
11
|
+
assert,
|
|
12
|
+
Provider,
|
|
13
|
+
TransactionResponse,
|
|
14
|
+
TransactionResponseParams,
|
|
15
|
+
Signature
|
|
16
|
+
} from 'ethers'
|
|
17
|
+
import { TransactionRequest } from 'ethers/src.ts/providers'
|
|
18
|
+
import { APIService, WalletDetail, WalletAddressType } from './api'
|
|
19
|
+
import { APICredentials, TransactionStatusResponse, TxStatus, TransactionError } from './types'
|
|
20
|
+
import { Environment } from './config'
|
|
21
|
+
import { StatusPoller, StatusPollerOptions } from './utils/statusPoller'
|
|
22
|
+
|
|
23
|
+
export class ApexSigner extends AbstractSigner {
|
|
24
|
+
private address!: string
|
|
25
|
+
private APICredentials!: APICredentials
|
|
26
|
+
private APIService: APIService
|
|
27
|
+
private walletDetail: WalletDetail
|
|
28
|
+
private environment: Environment
|
|
29
|
+
private pollerOptions?: StatusPollerOptions
|
|
30
|
+
|
|
31
|
+
constructor(
|
|
32
|
+
credentials: APICredentials,
|
|
33
|
+
environment: Environment,
|
|
34
|
+
provider?: null | Provider,
|
|
35
|
+
pollerOptions?: StatusPollerOptions
|
|
36
|
+
) {
|
|
37
|
+
super(provider)
|
|
38
|
+
|
|
39
|
+
this.APICredentials = credentials
|
|
40
|
+
this.APIService = new APIService(credentials, environment)
|
|
41
|
+
this.environment = environment
|
|
42
|
+
this.pollerOptions = pollerOptions
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
setWallet(walletId: string): void {
|
|
46
|
+
if (!walletId || walletId.trim() === '') {
|
|
47
|
+
throw new Error('Invalid wallet ID provided')
|
|
48
|
+
}
|
|
49
|
+
// Set walletId in walletDetail with default values for required properties
|
|
50
|
+
this.walletDetail = {
|
|
51
|
+
WalletID: walletId,
|
|
52
|
+
APIKey: '',
|
|
53
|
+
Name: '',
|
|
54
|
+
AddressType: '',
|
|
55
|
+
Address: ''
|
|
56
|
+
// Other fields will be populated when getAddress is called
|
|
57
|
+
}
|
|
58
|
+
// Reset address cache since we're changing wallets
|
|
59
|
+
this.address = ''
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async getAddress(): Promise<string> {
|
|
63
|
+
if (this.address) {
|
|
64
|
+
return this.address
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!this.APICredentials.apiKey && !this.walletDetail.WalletID) {
|
|
68
|
+
throw new Error('Wallet detail not found, use setWallet(walletId) to set wallet first!')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const detail: WalletDetail = await this.APIService.getWalletDetail(
|
|
72
|
+
WalletAddressType.Evm,
|
|
73
|
+
this.walletDetail?.WalletID
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
this.walletDetail = detail
|
|
77
|
+
if (detail?.Address) {
|
|
78
|
+
// cache the address
|
|
79
|
+
this.address = detail.Address
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!this.address) {
|
|
83
|
+
throw new Error('Address not found')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return this.address
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private async getChainId(): Promise<number> {
|
|
90
|
+
if (!this.provider) {
|
|
91
|
+
throw new Error('Provider is required for signing operations')
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const network = await this.provider.getNetwork()
|
|
96
|
+
return Number(network.chainId)
|
|
97
|
+
} catch (error) {
|
|
98
|
+
throw new Error('Failed to get chainId from provider: ' + error)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
connect(provider: null | Provider): ApexSigner {
|
|
103
|
+
return new ApexSigner(this.APICredentials, this.environment, provider)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private async waitForSignature(walletId: string, transactionId: string): Promise<string> {
|
|
107
|
+
const poller = new StatusPoller(this.pollerOptions)
|
|
108
|
+
const status = await poller.poll(
|
|
109
|
+
// Polling function
|
|
110
|
+
() => this.APIService.getSignStatus(walletId, transactionId),
|
|
111
|
+
// Success condition
|
|
112
|
+
(result) => result.status === TxStatus.Confirmed && result.signature != null,
|
|
113
|
+
// Error condition
|
|
114
|
+
(result) => [TxStatus.Failed, TxStatus.Rejected].includes(result.status)
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
if (!status.signature) {
|
|
118
|
+
throw new Error('Signature not found in successful response')
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return status.signature
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private async waitForTransactonStatus(transactionId: string): Promise<string> {
|
|
125
|
+
const poller = new StatusPoller(this.pollerOptions)
|
|
126
|
+
// Poll for transaction status using signaturePoller
|
|
127
|
+
const result = await poller.poll<TransactionStatusResponse>(
|
|
128
|
+
// Polling function
|
|
129
|
+
() => {
|
|
130
|
+
console.log('Polling status')
|
|
131
|
+
return this.APIService.getTransactionStatus(this.walletDetail.WalletID, transactionId)
|
|
132
|
+
},
|
|
133
|
+
// Success condition
|
|
134
|
+
(result) =>
|
|
135
|
+
(result.status === TxStatus.Confirmed || result.status === TxStatus.Completed) &&
|
|
136
|
+
!!result.hash,
|
|
137
|
+
// Error condition
|
|
138
|
+
(result) => {
|
|
139
|
+
if (result.status === TxStatus.Failed) {
|
|
140
|
+
throw new TransactionError(
|
|
141
|
+
result.failed_reason || 'Transaction failed',
|
|
142
|
+
'TRANSACTION_FAILED',
|
|
143
|
+
result.transaction_id
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
return result.status === TxStatus.Rejected
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
console.log('reulst', result)
|
|
150
|
+
|
|
151
|
+
if (!result.hash) {
|
|
152
|
+
throw new TransactionError(
|
|
153
|
+
'Transaction hash not found in successful response',
|
|
154
|
+
'TRANSACTION_HASH_MISSING',
|
|
155
|
+
result.transaction_id
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return result.hash
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Copied and editted from ethers.js -> Wallet -> BaseWallet
|
|
163
|
+
async signTransaction(tx: TransactionRequest): Promise<string> {
|
|
164
|
+
const startTime = new Date()
|
|
165
|
+
console.log(`[WalletSDK] Transaction started at: ${startTime.toLocaleString()}`)
|
|
166
|
+
|
|
167
|
+
// Replace any Addressable or ENS name with an address
|
|
168
|
+
const { to, from } = await resolveProperties({
|
|
169
|
+
to: tx.to ? resolveAddress(tx.to, this.provider) : undefined,
|
|
170
|
+
from: tx.from ? resolveAddress(tx.from, this.provider) : undefined
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
if (to != null) {
|
|
174
|
+
tx.to = to
|
|
175
|
+
}
|
|
176
|
+
if (from != null) {
|
|
177
|
+
tx.from = from
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (tx.from != null) {
|
|
181
|
+
assertArgument(
|
|
182
|
+
getAddress(<string>tx.from) === this.address,
|
|
183
|
+
'transaction from address mismatch',
|
|
184
|
+
'tx.from',
|
|
185
|
+
tx.from
|
|
186
|
+
)
|
|
187
|
+
delete tx.from
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const fromAddress = this.address
|
|
191
|
+
// Build the transaction
|
|
192
|
+
const btx = Transaction.from(<TransactionLike<string>>tx)
|
|
193
|
+
const data = {
|
|
194
|
+
maxFeePerGas: btx.maxFeePerGas,
|
|
195
|
+
maxPriorityFeePerGas: btx.maxPriorityFeePerGas,
|
|
196
|
+
to: btx.to,
|
|
197
|
+
from: fromAddress,
|
|
198
|
+
nonce: btx.nonce,
|
|
199
|
+
gasLimit: btx.gasLimit,
|
|
200
|
+
data: btx.data,
|
|
201
|
+
value: btx.value,
|
|
202
|
+
chainId: btx.chainId,
|
|
203
|
+
accessList: btx.accessList
|
|
204
|
+
}
|
|
205
|
+
// return unseralized as API signTransaction is an asynchoronous action
|
|
206
|
+
const response = await this.APIService.signTransaction(this.walletDetail.WalletID, data)
|
|
207
|
+
const txHash = await this.waitForTransactonStatus(response.transaction_id)
|
|
208
|
+
|
|
209
|
+
const endTime = new Date()
|
|
210
|
+
const elapsedTimeMs = endTime.getTime() - startTime.getTime()
|
|
211
|
+
console.log(`[WalletSDK] Transaction completed at: ${endTime.toLocaleString()}`)
|
|
212
|
+
console.log(
|
|
213
|
+
`[WalletSDK] Transaction took ${elapsedTimeMs}ms (${(elapsedTimeMs / 1000).toFixed(2)}s)`
|
|
214
|
+
)
|
|
215
|
+
console.log('[WalletSDK] Transaction succeed!')
|
|
216
|
+
|
|
217
|
+
return txHash
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async sendTransaction(tx: TransactionRequest): Promise<TransactionResponse> {
|
|
221
|
+
const startTime = new Date()
|
|
222
|
+
console.log(`[WalletSDK] sendTransaction started at: ${startTime.toLocaleString()}`)
|
|
223
|
+
|
|
224
|
+
if (!this.address) {
|
|
225
|
+
await this.getAddress()
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
checkProvider(this, 'sendTransaction')
|
|
229
|
+
|
|
230
|
+
// Only populate if gas fees are not set
|
|
231
|
+
const hasGasFees =
|
|
232
|
+
tx.gasPrice != null || (tx.maxFeePerGas != null && tx.maxPriorityFeePerGas != null)
|
|
233
|
+
|
|
234
|
+
let populatedTx = tx
|
|
235
|
+
if (!hasGasFees) {
|
|
236
|
+
const populateStartTime = new Date()
|
|
237
|
+
console.log(
|
|
238
|
+
`[WalletSDK] populateTransaction started at: ${populateStartTime.toLocaleString()}`
|
|
239
|
+
)
|
|
240
|
+
populatedTx = await this.populateTransaction(tx)
|
|
241
|
+
const populateEndTime = new Date()
|
|
242
|
+
const populateElapsedMs = populateEndTime.getTime() - populateStartTime.getTime()
|
|
243
|
+
console.log(
|
|
244
|
+
`[WalletSDK] populateTransaction completed in ${(populateElapsedMs / 1000).toFixed(2)}s`
|
|
245
|
+
)
|
|
246
|
+
} else {
|
|
247
|
+
console.log(`[WalletSDK] Skipping transaction population as gas fees are already set`)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
delete populatedTx.from
|
|
251
|
+
|
|
252
|
+
// Ensure all properties are properly resolved to their string representations
|
|
253
|
+
const resolvedTx = (await resolveProperties(populatedTx)) as TransactionLike<string>
|
|
254
|
+
const txObj = Transaction.from(resolvedTx)
|
|
255
|
+
|
|
256
|
+
console.log('txObj', txObj)
|
|
257
|
+
|
|
258
|
+
const txHash = await this.signTransaction(txObj)
|
|
259
|
+
|
|
260
|
+
// Instead of creating a mock response, get the actual transaction from the provider
|
|
261
|
+
const endTime = new Date()
|
|
262
|
+
const totalElapsedMs = endTime.getTime() - startTime.getTime()
|
|
263
|
+
console.log(`[WalletSDK] sendTransaction completed at: ${endTime.toLocaleString()}`)
|
|
264
|
+
console.log(`[WalletSDK] sendTransaction took ${(totalElapsedMs / 1000).toFixed(2)}s`)
|
|
265
|
+
console.log('[WalletSDK] Transaction sent successfully!')
|
|
266
|
+
|
|
267
|
+
const txResponse: TransactionResponseParams = {
|
|
268
|
+
blockNumber: 0, // Default to 0 as this is an async transaction
|
|
269
|
+
blockHash: '0x0000000000000000000000000000000000000000000000000000000000000000', // not available yet
|
|
270
|
+
hash: txHash, // not available yet
|
|
271
|
+
index: 0,
|
|
272
|
+
type: 0,
|
|
273
|
+
to: tx.to as any,
|
|
274
|
+
from: this.address,
|
|
275
|
+
/**
|
|
276
|
+
*
|
|
277
|
+
*/
|
|
278
|
+
nonce: txObj.nonce, // The nonce of the transaction, used for replay protection.
|
|
279
|
+
/**
|
|
280
|
+
* The maximum amount of gas this transaction is authorized to consume.
|
|
281
|
+
*/
|
|
282
|
+
gasLimit: txObj.gasLimit,
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* For legacy transactions, this is the gas price per gas to pay.
|
|
286
|
+
*/
|
|
287
|
+
gasPrice: txObj.gasPrice ? txObj.gasPrice : BigInt(0),
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* For [[link-eip-1559]] transactions, this is the maximum priority
|
|
291
|
+
* fee to allow a producer to claim.
|
|
292
|
+
*/
|
|
293
|
+
maxPriorityFeePerGas: txObj.maxPriorityFeePerGas,
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* For [[link-eip-1559]] transactions, this is the maximum fee that
|
|
297
|
+
* will be paid.
|
|
298
|
+
*/
|
|
299
|
+
maxFeePerGas: txObj.maxFeePerGas,
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* The transaction data.
|
|
303
|
+
*/
|
|
304
|
+
data: txObj.data,
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* The transaction value (in wei).
|
|
308
|
+
*/
|
|
309
|
+
value: txObj.value,
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* The chain ID this transaction is valid on.
|
|
313
|
+
*/
|
|
314
|
+
chainId: txObj.chainId,
|
|
315
|
+
|
|
316
|
+
signature: Signature.from('0x' + '0'.repeat(130)), // length of signature is 65 bytes - 130 hex chars
|
|
317
|
+
/**
|
|
318
|
+
* The transaction access list.
|
|
319
|
+
*/
|
|
320
|
+
accessList: txObj.accessList
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Let the provider create the TransactionResponse using the txHash
|
|
324
|
+
return new TransactionResponse(txResponse, this.provider as Provider)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
async signMessage(message: string | Uint8Array): Promise<string> {
|
|
328
|
+
if (!this.provider) {
|
|
329
|
+
throw new Error('Provider is required for signing operations')
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (!this.address) {
|
|
333
|
+
await this.getAddress()
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (!this.walletDetail) {
|
|
337
|
+
this.walletDetail = await this.APIService.getWalletDetail()
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const chainId = await this.getChainId()
|
|
341
|
+
const messageStr = typeof message === 'string' ? message : Buffer.from(message).toString('hex')
|
|
342
|
+
|
|
343
|
+
const response = await this.APIService.requestSign(this.walletDetail.WalletID, {
|
|
344
|
+
method: 'eth_sign',
|
|
345
|
+
message: messageStr,
|
|
346
|
+
chain_id: chainId
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
return this.waitForSignature(this.walletDetail.WalletID, response.transaction_id)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async signTypedData(
|
|
353
|
+
domain: TypedDataDomain,
|
|
354
|
+
types: Record<string, Array<TypedDataField>>,
|
|
355
|
+
value: Record<string, any>
|
|
356
|
+
): Promise<string> {
|
|
357
|
+
if (!this.provider) {
|
|
358
|
+
throw new Error('Provider is required for signing operations')
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (!this.address) {
|
|
362
|
+
await this.getAddress()
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (!this.walletDetail) {
|
|
366
|
+
this.walletDetail = await this.APIService.getWalletDetail()
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const chainId = await this.getChainId()
|
|
370
|
+
const typedData = JSON.stringify({
|
|
371
|
+
domain,
|
|
372
|
+
types,
|
|
373
|
+
message: value
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
const response = await this.APIService.requestSign(this.walletDetail.WalletID, {
|
|
377
|
+
method: 'eth_signTypedData_v4',
|
|
378
|
+
message: '',
|
|
379
|
+
chain_id: chainId,
|
|
380
|
+
typed_data: typedData
|
|
381
|
+
})
|
|
382
|
+
|
|
383
|
+
return this.waitForSignature(this.walletDetail.WalletID, response.transaction_id)
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function checkProvider(signer: AbstractSigner, operation: string): Provider {
|
|
388
|
+
if (signer.provider) {
|
|
389
|
+
return signer.provider
|
|
390
|
+
}
|
|
391
|
+
assert(false, 'missing provider', 'UNSUPPORTED_OPERATION', { operation })
|
|
392
|
+
}
|