@fystack/sdk 0.1.7 → 0.1.9
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/dist/index.cjs +110 -26
- package/dist/index.d.cts +122 -11
- package/dist/index.d.mts +122 -11
- package/dist/index.esm.d.ts +122 -11
- package/dist/index.esm.js +110 -27
- package/dist/index.mjs +110 -27
- package/dist/types/index.d.ts +122 -11
- package/package.json +1 -1
- package/src/api.ts +61 -9
- package/src/config.ts +5 -1
- package/src/enum.ts +10 -0
- package/src/sdk.ts +53 -1
- package/src/signer.ts +40 -18
- package/src/solanaSigner.ts +41 -17
- package/src/types.ts +67 -1
- package/test.js +76 -0
package/dist/index.esm.js
CHANGED
|
@@ -42,7 +42,9 @@ const createAPI = (env)=>{
|
|
|
42
42
|
getWalletCreationStatus: (walletId)=>withBaseURL(`/wallets/creation-status/${walletId}`),
|
|
43
43
|
getWalletAssets: (walletId)=>withBaseURL(`/wallets/${walletId}/assets`),
|
|
44
44
|
getDepositAddress: (walletId, addressType)=>withBaseURL(`/wallets/${walletId}/deposit-address?address_type=${addressType}`),
|
|
45
|
-
rescanTransaction: ()=>withBaseURL('/networks/rescan-transaction')
|
|
45
|
+
rescanTransaction: ()=>withBaseURL('/networks/rescan-transaction'),
|
|
46
|
+
requestWithdrawal: (walletId)=>withBaseURL(`/wallets/${walletId}/request-withdrawal`),
|
|
47
|
+
getWebhookPublicKey: (workspaceId)=>withBaseURL(`/workspaces/${workspaceId}/webhook-verification-key`)
|
|
46
48
|
}
|
|
47
49
|
};
|
|
48
50
|
};
|
|
@@ -173,8 +175,18 @@ var WalletRole;
|
|
|
173
175
|
WalletRole["Signer"] = "wallet_signer";
|
|
174
176
|
WalletRole["Viewer"] = "wallet_viewer";
|
|
175
177
|
})(WalletRole || (WalletRole = {}));
|
|
178
|
+
var WithdrawalStatus;
|
|
179
|
+
(function(WithdrawalStatus) {
|
|
180
|
+
WithdrawalStatus["Pending"] = "pending";
|
|
181
|
+
WithdrawalStatus["PendingApproval"] = "pending_approval";
|
|
182
|
+
WithdrawalStatus["Approved"] = "approved";
|
|
183
|
+
WithdrawalStatus["Rejected"] = "rejected";
|
|
184
|
+
WithdrawalStatus["Processing"] = "processing";
|
|
185
|
+
WithdrawalStatus["Completed"] = "completed";
|
|
186
|
+
WithdrawalStatus["Failed"] = "failed";
|
|
187
|
+
})(WithdrawalStatus || (WithdrawalStatus = {}));
|
|
176
188
|
|
|
177
|
-
async function composeAPIHeaders(credentials, httpMethod, apiEndpoint, body = {}) {
|
|
189
|
+
async function composeAPIHeaders(credentials, httpMethod, apiEndpoint, body = {}, headers) {
|
|
178
190
|
if (!credentials.apiSecret || credentials.apiSecret === '') {
|
|
179
191
|
// If APISecret is not provided, use authToken
|
|
180
192
|
if (credentials.authToken) {
|
|
@@ -196,12 +208,13 @@ async function composeAPIHeaders(credentials, httpMethod, apiEndpoint, body = {}
|
|
|
196
208
|
body: Object.keys(body).length ? JSON.stringify(body) : ''
|
|
197
209
|
};
|
|
198
210
|
const digest = await computeHMAC(credentials.apiSecret, params);
|
|
199
|
-
const
|
|
211
|
+
const combinedHeaders = {
|
|
200
212
|
'ACCESS-API-KEY': credentials.apiKey,
|
|
201
213
|
'ACCESS-TIMESTAMP': String(currentTimestampInSeconds),
|
|
202
|
-
'ACCESS-SIGN': btoa(digest)
|
|
214
|
+
'ACCESS-SIGN': btoa(digest),
|
|
215
|
+
...headers ?? {}
|
|
203
216
|
};
|
|
204
|
-
return
|
|
217
|
+
return combinedHeaders;
|
|
205
218
|
}
|
|
206
219
|
class APIService {
|
|
207
220
|
async getWallets(workspaceId) {
|
|
@@ -217,9 +230,9 @@ class APIService {
|
|
|
217
230
|
const resp = await get(endpoint + `?address_type=${addressType}`, headers);
|
|
218
231
|
return transformWalletDetail(resp.data);
|
|
219
232
|
}
|
|
220
|
-
async requestSign(walletId, params) {
|
|
233
|
+
async requestSign(walletId, params, options) {
|
|
221
234
|
const endpoint = this.API.endpoints.requestSign(walletId);
|
|
222
|
-
const headers = await composeAPIHeaders(this.credentials, 'POST', endpoint, params);
|
|
235
|
+
const headers = await composeAPIHeaders(this.credentials, 'POST', endpoint, params, options);
|
|
223
236
|
const response = await post(endpoint, params, headers);
|
|
224
237
|
return response.data;
|
|
225
238
|
}
|
|
@@ -229,10 +242,10 @@ class APIService {
|
|
|
229
242
|
const response = await get(endpoint, headers);
|
|
230
243
|
return response.data;
|
|
231
244
|
}
|
|
232
|
-
async signTransaction(walletId, body) {
|
|
245
|
+
async signTransaction(walletId, body, options) {
|
|
233
246
|
const startTime = Date.now();
|
|
234
247
|
const endpoint = this.API.endpoints.signTransaction(walletId);
|
|
235
|
-
const headers = await composeAPIHeaders(this.credentials, 'POST', endpoint, body);
|
|
248
|
+
const headers = await composeAPIHeaders(this.credentials, 'POST', endpoint, body, options);
|
|
236
249
|
const response = await post(endpoint, body, headers);
|
|
237
250
|
const elapsedTime = Date.now() - startTime;
|
|
238
251
|
console.log(`[WalletSDK] Sign transaction completed in ${elapsedTime}ms`);
|
|
@@ -291,6 +304,28 @@ class APIService {
|
|
|
291
304
|
const headers = await composeAPIHeaders(this.credentials, 'POST', endpoint, transformedParams);
|
|
292
305
|
await post(endpoint, transformedParams, headers);
|
|
293
306
|
}
|
|
307
|
+
/**
|
|
308
|
+
* Requests a withdrawal from a wallet
|
|
309
|
+
* @param walletId The wallet ID
|
|
310
|
+
* @param params Withdrawal parameters
|
|
311
|
+
* @returns Withdrawal response with auto_approved status and withdrawal details
|
|
312
|
+
*/ async requestWithdrawal(walletId, params) {
|
|
313
|
+
const endpoint = this.API.endpoints.requestWithdrawal(walletId);
|
|
314
|
+
const transformedParams = transformRequestWithdrawalParams(params);
|
|
315
|
+
const headers = await composeAPIHeaders(this.credentials, 'POST', endpoint, transformedParams);
|
|
316
|
+
const response = await post(endpoint, transformedParams, headers);
|
|
317
|
+
return response.data;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Gets the webhook public key for a workspace
|
|
321
|
+
* @param workspaceId The workspace ID
|
|
322
|
+
* @returns Webhook public key response with base64 encoded ed25519 public key
|
|
323
|
+
*/ async getWebhookPublicKey(workspaceId) {
|
|
324
|
+
const endpoint = this.API.endpoints.getWebhookPublicKey(workspaceId);
|
|
325
|
+
const headers = await composeAPIHeaders(this.credentials, 'GET', endpoint);
|
|
326
|
+
const response = await get(endpoint, headers);
|
|
327
|
+
return response.data;
|
|
328
|
+
}
|
|
294
329
|
constructor(credentials, environment){
|
|
295
330
|
this.credentials = credentials;
|
|
296
331
|
this.Webhook = new WebhookService(credentials);
|
|
@@ -414,6 +449,19 @@ function transformRescanTransactionParams(data) {
|
|
|
414
449
|
network_id: data.networkId
|
|
415
450
|
};
|
|
416
451
|
}
|
|
452
|
+
function transformRequestWithdrawalParams(data) {
|
|
453
|
+
return {
|
|
454
|
+
asset_id: data.assetId,
|
|
455
|
+
amount: data.amount,
|
|
456
|
+
recipient_address: data.recipientAddress,
|
|
457
|
+
...data.notes !== undefined && {
|
|
458
|
+
notes: data.notes
|
|
459
|
+
},
|
|
460
|
+
...data.skipBalanceCheck !== undefined && {
|
|
461
|
+
skip_balance_check: data.skipBalanceCheck
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
}
|
|
417
465
|
BigInt.prototype.toJSON = function() {
|
|
418
466
|
return this.toString();
|
|
419
467
|
};
|
|
@@ -574,6 +622,41 @@ class FystackSDK {
|
|
|
574
622
|
}
|
|
575
623
|
await this.apiService.rescanTransaction(params);
|
|
576
624
|
}
|
|
625
|
+
/**
|
|
626
|
+
* Requests a withdrawal from a wallet
|
|
627
|
+
* @param walletId The ID of the wallet to withdraw from
|
|
628
|
+
* @param params Withdrawal parameters including asset, amount, and recipient
|
|
629
|
+
* @returns Promise with withdrawal response including auto_approved status and withdrawal details
|
|
630
|
+
*/ async requestWithdrawal(walletId, params) {
|
|
631
|
+
validateUUID(walletId, 'walletId');
|
|
632
|
+
validateUUID(params.assetId, 'assetId');
|
|
633
|
+
if (!params.amount || params.amount.trim() === '') {
|
|
634
|
+
throw new Error('Invalid amount provided');
|
|
635
|
+
}
|
|
636
|
+
if (!params.recipientAddress || params.recipientAddress.trim() === '') {
|
|
637
|
+
throw new Error('Invalid recipient address provided');
|
|
638
|
+
}
|
|
639
|
+
if (params.recipientAddress.length > 256) {
|
|
640
|
+
throw new Error('Recipient address exceeds maximum length of 256 characters');
|
|
641
|
+
}
|
|
642
|
+
if (params.notes && params.notes.length > 500) {
|
|
643
|
+
throw new Error('Notes exceed maximum length of 500 characters');
|
|
644
|
+
}
|
|
645
|
+
this.log(`Requesting withdrawal from wallet ${walletId}`);
|
|
646
|
+
const response = await this.apiService.requestWithdrawal(walletId, params);
|
|
647
|
+
this.log(`Withdrawal request completed, auto_approved: ${response.auto_approved}`);
|
|
648
|
+
return response;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Gets the webhook public key for a workspace
|
|
652
|
+
* @param workspaceId The workspace ID
|
|
653
|
+
* @returns Promise with webhook public key (base64 encoded ed25519 public key)
|
|
654
|
+
*/ async getWebhookPublicKey(workspaceId) {
|
|
655
|
+
validateUUID(workspaceId, 'workspaceId');
|
|
656
|
+
this.log(`Getting webhook public key for workspace ${workspaceId}`);
|
|
657
|
+
const response = await this.apiService.getWebhookPublicKey(workspaceId);
|
|
658
|
+
return response;
|
|
659
|
+
}
|
|
577
660
|
constructor(options){
|
|
578
661
|
const { credentials, workspaceId, environment = Environment.Production, logger = false } = options;
|
|
579
662
|
this.apiService = new APIService(credentials, environment);
|
|
@@ -669,14 +752,14 @@ class EtherSigner extends AbstractSigner {
|
|
|
669
752
|
}
|
|
670
753
|
return result.status === TxStatus.Rejected;
|
|
671
754
|
});
|
|
672
|
-
console.log('
|
|
755
|
+
console.log('result', result);
|
|
673
756
|
if (!result.hash) {
|
|
674
757
|
throw new TransactionError('Transaction hash not found in successful response', 'TRANSACTION_HASH_MISSING', result.transaction_id);
|
|
675
758
|
}
|
|
676
759
|
return result.hash;
|
|
677
760
|
}
|
|
678
761
|
// Copied and editted from ethers.js -> Wallet -> BaseWallet
|
|
679
|
-
async signTransaction(tx) {
|
|
762
|
+
async signTransaction(tx, options) {
|
|
680
763
|
const startTime = new Date();
|
|
681
764
|
console.log(`[WalletSDK] Transaction started at: ${startTime.toLocaleString()}`);
|
|
682
765
|
if (!this.address) {
|
|
@@ -716,7 +799,7 @@ class EtherSigner extends AbstractSigner {
|
|
|
716
799
|
accessList: btx.accessList
|
|
717
800
|
};
|
|
718
801
|
// return unseralized as API signTransaction is an asynchoronous action
|
|
719
|
-
const response = await this.APIService.signTransaction(this.walletDetail.WalletID, data);
|
|
802
|
+
const response = await this.APIService.signTransaction(this.walletDetail.WalletID, data, options);
|
|
720
803
|
const txHash = await this.waitForTransactonStatus(response.transaction_id);
|
|
721
804
|
const endTime = new Date();
|
|
722
805
|
const elapsedTimeMs = endTime.getTime() - startTime.getTime();
|
|
@@ -725,7 +808,7 @@ class EtherSigner extends AbstractSigner {
|
|
|
725
808
|
console.log('[WalletSDK] Transaction succeed!');
|
|
726
809
|
return txHash;
|
|
727
810
|
}
|
|
728
|
-
async sendTransaction(tx) {
|
|
811
|
+
async sendTransaction(tx, options) {
|
|
729
812
|
const startTime = new Date();
|
|
730
813
|
console.log(`[WalletSDK] sendTransaction started at: ${startTime.toLocaleString()}`);
|
|
731
814
|
if (!this.address) {
|
|
@@ -753,7 +836,7 @@ class EtherSigner extends AbstractSigner {
|
|
|
753
836
|
const resolvedTx = await resolveProperties(populatedTx);
|
|
754
837
|
const txObj = Transaction.from(resolvedTx);
|
|
755
838
|
console.log('[WalletSDK] Tx Data', txObj);
|
|
756
|
-
const txHash = await this.signTransaction(txObj);
|
|
839
|
+
const txHash = await this.signTransaction(txObj, options);
|
|
757
840
|
// Instead of creating a mock response, get the actual transaction from the provider
|
|
758
841
|
const endTime = new Date();
|
|
759
842
|
const totalElapsedMs = endTime.getTime() - startTime.getTime();
|
|
@@ -802,7 +885,7 @@ class EtherSigner extends AbstractSigner {
|
|
|
802
885
|
// Let the provider create the TransactionResponse using the txHash
|
|
803
886
|
return new TransactionResponse(txResponse, this.provider);
|
|
804
887
|
}
|
|
805
|
-
async signMessage(message) {
|
|
888
|
+
async signMessage(message, options) {
|
|
806
889
|
if (!this.provider) {
|
|
807
890
|
throw new Error('Provider is required for signing operations');
|
|
808
891
|
}
|
|
@@ -818,10 +901,10 @@ class EtherSigner extends AbstractSigner {
|
|
|
818
901
|
method: 'eth_sign',
|
|
819
902
|
message: messageStr,
|
|
820
903
|
chain_id: chainId
|
|
821
|
-
});
|
|
904
|
+
}, options);
|
|
822
905
|
return this.waitForSignature(this.walletDetail.WalletID, response.transaction_id);
|
|
823
906
|
}
|
|
824
|
-
async signTypedData(domain, types, value) {
|
|
907
|
+
async signTypedData(domain, types, value, options) {
|
|
825
908
|
if (!this.provider) {
|
|
826
909
|
throw new Error('Provider is required for signing operations');
|
|
827
910
|
}
|
|
@@ -842,7 +925,7 @@ class EtherSigner extends AbstractSigner {
|
|
|
842
925
|
message: '',
|
|
843
926
|
chain_id: chainId,
|
|
844
927
|
typed_data: typedData
|
|
845
|
-
});
|
|
928
|
+
}, options);
|
|
846
929
|
return this.waitForSignature(this.walletDetail.WalletID, response.transaction_id);
|
|
847
930
|
}
|
|
848
931
|
constructor(credentials, environment, provider, pollerOptions){
|
|
@@ -921,7 +1004,7 @@ class SolanaSigner {
|
|
|
921
1004
|
* Signs a Solana transaction
|
|
922
1005
|
* @param transaction Base64 encoded serialized transaction
|
|
923
1006
|
* @returns Signature as a base58 encoded string
|
|
924
|
-
*/ async signTransaction(transaction) {
|
|
1007
|
+
*/ async signTransaction(transaction, options) {
|
|
925
1008
|
if (!this.address) {
|
|
926
1009
|
await this.getAddress();
|
|
927
1010
|
}
|
|
@@ -936,7 +1019,7 @@ class SolanaSigner {
|
|
|
936
1019
|
tx_method: 'solana_signTransaction'
|
|
937
1020
|
},
|
|
938
1021
|
chainId: '1399811149'
|
|
939
|
-
});
|
|
1022
|
+
}, options);
|
|
940
1023
|
// Wait for the signature
|
|
941
1024
|
return this.waitForTransactionStatus(response.transaction_id);
|
|
942
1025
|
}
|
|
@@ -944,7 +1027,7 @@ class SolanaSigner {
|
|
|
944
1027
|
* Signs a Solana message
|
|
945
1028
|
* @param message The message to sign (string or Uint8Array)
|
|
946
1029
|
* @returns Signature as a base58 encoded string
|
|
947
|
-
*/ async signMessage(message) {
|
|
1030
|
+
*/ async signMessage(message, options) {
|
|
948
1031
|
if (!this.address) {
|
|
949
1032
|
await this.getAddress();
|
|
950
1033
|
}
|
|
@@ -953,14 +1036,14 @@ class SolanaSigner {
|
|
|
953
1036
|
method: 'solana_signMessage',
|
|
954
1037
|
message: messageStr,
|
|
955
1038
|
chain_id: 0 // Not used for Solana but required by API
|
|
956
|
-
});
|
|
1039
|
+
}, options);
|
|
957
1040
|
return this.waitForTransactionStatus(response.transaction_id);
|
|
958
1041
|
}
|
|
959
1042
|
/**
|
|
960
1043
|
* Signs and sends a Solana transaction
|
|
961
1044
|
* @param transaction Base64 encoded serialized transaction
|
|
962
1045
|
* @returns Transaction signature
|
|
963
|
-
*/ async signAndSendTransaction(transaction) {
|
|
1046
|
+
*/ async signAndSendTransaction(transaction, options) {
|
|
964
1047
|
if (!this.address) {
|
|
965
1048
|
await this.getAddress();
|
|
966
1049
|
}
|
|
@@ -969,7 +1052,7 @@ class SolanaSigner {
|
|
|
969
1052
|
from: this.address,
|
|
970
1053
|
method: 'solana_signAndSendTransaction'
|
|
971
1054
|
};
|
|
972
|
-
const response = await this.APIService.signTransaction(this.walletDetail.WalletID, data);
|
|
1055
|
+
const response = await this.APIService.signTransaction(this.walletDetail.WalletID, data, options);
|
|
973
1056
|
const txHash = await this.waitForTransactionStatus(response.transaction_id);
|
|
974
1057
|
console.log('transaction succeed!');
|
|
975
1058
|
return txHash;
|
|
@@ -978,14 +1061,14 @@ class SolanaSigner {
|
|
|
978
1061
|
* Signs multiple Solana transactions
|
|
979
1062
|
* @param transactions Array of base64 encoded serialized transactions
|
|
980
1063
|
* @returns Array of signatures as base58 encoded strings
|
|
981
|
-
*/ async signAllTransactions(transactions) {
|
|
1064
|
+
*/ async signAllTransactions(transactions, options) {
|
|
982
1065
|
if (!this.address) {
|
|
983
1066
|
await this.getAddress();
|
|
984
1067
|
}
|
|
985
1068
|
// We need to get the signatures and then incorporate them into the transactions
|
|
986
1069
|
const signaturePromises = transactions.map(async (transaction)=>{
|
|
987
1070
|
// Get the signature
|
|
988
|
-
const signature = await this.signTransaction(transaction);
|
|
1071
|
+
const signature = await this.signTransaction(transaction, options);
|
|
989
1072
|
// Here you would need to incorporate the signature into the transaction
|
|
990
1073
|
// This is a placeholder - you'll need to implement actual signature incorporation
|
|
991
1074
|
// based on your Solana transaction structure
|
|
@@ -1032,4 +1115,4 @@ class SolanaSigner {
|
|
|
1032
1115
|
}
|
|
1033
1116
|
}
|
|
1034
1117
|
|
|
1035
|
-
export { APIService, AddressType, DEFAULT_POLLER_OPTIONS, DestinationType, Environment, EtherSigner, FystackSDK, PaymentService, SolanaSigner, StatusPoller, TransactionError, TxApprovalStatus, TxStatus, WalletCreationStatus, WalletPurpose, WalletRole, WalletType, WebhookService, createAPI, get, post, transformCreateWalletPayload, transformRescanTransactionParams, transformWalletDetail };
|
|
1118
|
+
export { APIService, AddressType, DEFAULT_POLLER_OPTIONS, DestinationType, Environment, EtherSigner, FystackSDK, PaymentService, SolanaSigner, StatusPoller, TransactionError, TxApprovalStatus, TxStatus, WalletCreationStatus, WalletPurpose, WalletRole, WalletType, WebhookService, WithdrawalStatus, createAPI, get, post, transformCreateWalletPayload, transformRequestWithdrawalParams, transformRescanTransactionParams, transformWalletDetail };
|
package/dist/index.mjs
CHANGED
|
@@ -42,7 +42,9 @@ const createAPI = (env)=>{
|
|
|
42
42
|
getWalletCreationStatus: (walletId)=>withBaseURL(`/wallets/creation-status/${walletId}`),
|
|
43
43
|
getWalletAssets: (walletId)=>withBaseURL(`/wallets/${walletId}/assets`),
|
|
44
44
|
getDepositAddress: (walletId, addressType)=>withBaseURL(`/wallets/${walletId}/deposit-address?address_type=${addressType}`),
|
|
45
|
-
rescanTransaction: ()=>withBaseURL('/networks/rescan-transaction')
|
|
45
|
+
rescanTransaction: ()=>withBaseURL('/networks/rescan-transaction'),
|
|
46
|
+
requestWithdrawal: (walletId)=>withBaseURL(`/wallets/${walletId}/request-withdrawal`),
|
|
47
|
+
getWebhookPublicKey: (workspaceId)=>withBaseURL(`/workspaces/${workspaceId}/webhook-verification-key`)
|
|
46
48
|
}
|
|
47
49
|
};
|
|
48
50
|
};
|
|
@@ -173,8 +175,18 @@ var WalletRole;
|
|
|
173
175
|
WalletRole["Signer"] = "wallet_signer";
|
|
174
176
|
WalletRole["Viewer"] = "wallet_viewer";
|
|
175
177
|
})(WalletRole || (WalletRole = {}));
|
|
178
|
+
var WithdrawalStatus;
|
|
179
|
+
(function(WithdrawalStatus) {
|
|
180
|
+
WithdrawalStatus["Pending"] = "pending";
|
|
181
|
+
WithdrawalStatus["PendingApproval"] = "pending_approval";
|
|
182
|
+
WithdrawalStatus["Approved"] = "approved";
|
|
183
|
+
WithdrawalStatus["Rejected"] = "rejected";
|
|
184
|
+
WithdrawalStatus["Processing"] = "processing";
|
|
185
|
+
WithdrawalStatus["Completed"] = "completed";
|
|
186
|
+
WithdrawalStatus["Failed"] = "failed";
|
|
187
|
+
})(WithdrawalStatus || (WithdrawalStatus = {}));
|
|
176
188
|
|
|
177
|
-
async function composeAPIHeaders(credentials, httpMethod, apiEndpoint, body = {}) {
|
|
189
|
+
async function composeAPIHeaders(credentials, httpMethod, apiEndpoint, body = {}, headers) {
|
|
178
190
|
if (!credentials.apiSecret || credentials.apiSecret === '') {
|
|
179
191
|
// If APISecret is not provided, use authToken
|
|
180
192
|
if (credentials.authToken) {
|
|
@@ -196,12 +208,13 @@ async function composeAPIHeaders(credentials, httpMethod, apiEndpoint, body = {}
|
|
|
196
208
|
body: Object.keys(body).length ? JSON.stringify(body) : ''
|
|
197
209
|
};
|
|
198
210
|
const digest = await computeHMAC(credentials.apiSecret, params);
|
|
199
|
-
const
|
|
211
|
+
const combinedHeaders = {
|
|
200
212
|
'ACCESS-API-KEY': credentials.apiKey,
|
|
201
213
|
'ACCESS-TIMESTAMP': String(currentTimestampInSeconds),
|
|
202
|
-
'ACCESS-SIGN': btoa(digest)
|
|
214
|
+
'ACCESS-SIGN': btoa(digest),
|
|
215
|
+
...headers ?? {}
|
|
203
216
|
};
|
|
204
|
-
return
|
|
217
|
+
return combinedHeaders;
|
|
205
218
|
}
|
|
206
219
|
class APIService {
|
|
207
220
|
async getWallets(workspaceId) {
|
|
@@ -217,9 +230,9 @@ class APIService {
|
|
|
217
230
|
const resp = await get(endpoint + `?address_type=${addressType}`, headers);
|
|
218
231
|
return transformWalletDetail(resp.data);
|
|
219
232
|
}
|
|
220
|
-
async requestSign(walletId, params) {
|
|
233
|
+
async requestSign(walletId, params, options) {
|
|
221
234
|
const endpoint = this.API.endpoints.requestSign(walletId);
|
|
222
|
-
const headers = await composeAPIHeaders(this.credentials, 'POST', endpoint, params);
|
|
235
|
+
const headers = await composeAPIHeaders(this.credentials, 'POST', endpoint, params, options);
|
|
223
236
|
const response = await post(endpoint, params, headers);
|
|
224
237
|
return response.data;
|
|
225
238
|
}
|
|
@@ -229,10 +242,10 @@ class APIService {
|
|
|
229
242
|
const response = await get(endpoint, headers);
|
|
230
243
|
return response.data;
|
|
231
244
|
}
|
|
232
|
-
async signTransaction(walletId, body) {
|
|
245
|
+
async signTransaction(walletId, body, options) {
|
|
233
246
|
const startTime = Date.now();
|
|
234
247
|
const endpoint = this.API.endpoints.signTransaction(walletId);
|
|
235
|
-
const headers = await composeAPIHeaders(this.credentials, 'POST', endpoint, body);
|
|
248
|
+
const headers = await composeAPIHeaders(this.credentials, 'POST', endpoint, body, options);
|
|
236
249
|
const response = await post(endpoint, body, headers);
|
|
237
250
|
const elapsedTime = Date.now() - startTime;
|
|
238
251
|
console.log(`[WalletSDK] Sign transaction completed in ${elapsedTime}ms`);
|
|
@@ -291,6 +304,28 @@ class APIService {
|
|
|
291
304
|
const headers = await composeAPIHeaders(this.credentials, 'POST', endpoint, transformedParams);
|
|
292
305
|
await post(endpoint, transformedParams, headers);
|
|
293
306
|
}
|
|
307
|
+
/**
|
|
308
|
+
* Requests a withdrawal from a wallet
|
|
309
|
+
* @param walletId The wallet ID
|
|
310
|
+
* @param params Withdrawal parameters
|
|
311
|
+
* @returns Withdrawal response with auto_approved status and withdrawal details
|
|
312
|
+
*/ async requestWithdrawal(walletId, params) {
|
|
313
|
+
const endpoint = this.API.endpoints.requestWithdrawal(walletId);
|
|
314
|
+
const transformedParams = transformRequestWithdrawalParams(params);
|
|
315
|
+
const headers = await composeAPIHeaders(this.credentials, 'POST', endpoint, transformedParams);
|
|
316
|
+
const response = await post(endpoint, transformedParams, headers);
|
|
317
|
+
return response.data;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Gets the webhook public key for a workspace
|
|
321
|
+
* @param workspaceId The workspace ID
|
|
322
|
+
* @returns Webhook public key response with base64 encoded ed25519 public key
|
|
323
|
+
*/ async getWebhookPublicKey(workspaceId) {
|
|
324
|
+
const endpoint = this.API.endpoints.getWebhookPublicKey(workspaceId);
|
|
325
|
+
const headers = await composeAPIHeaders(this.credentials, 'GET', endpoint);
|
|
326
|
+
const response = await get(endpoint, headers);
|
|
327
|
+
return response.data;
|
|
328
|
+
}
|
|
294
329
|
constructor(credentials, environment){
|
|
295
330
|
this.credentials = credentials;
|
|
296
331
|
this.Webhook = new WebhookService(credentials);
|
|
@@ -414,6 +449,19 @@ function transformRescanTransactionParams(data) {
|
|
|
414
449
|
network_id: data.networkId
|
|
415
450
|
};
|
|
416
451
|
}
|
|
452
|
+
function transformRequestWithdrawalParams(data) {
|
|
453
|
+
return {
|
|
454
|
+
asset_id: data.assetId,
|
|
455
|
+
amount: data.amount,
|
|
456
|
+
recipient_address: data.recipientAddress,
|
|
457
|
+
...data.notes !== undefined && {
|
|
458
|
+
notes: data.notes
|
|
459
|
+
},
|
|
460
|
+
...data.skipBalanceCheck !== undefined && {
|
|
461
|
+
skip_balance_check: data.skipBalanceCheck
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
}
|
|
417
465
|
BigInt.prototype.toJSON = function() {
|
|
418
466
|
return this.toString();
|
|
419
467
|
};
|
|
@@ -574,6 +622,41 @@ class FystackSDK {
|
|
|
574
622
|
}
|
|
575
623
|
await this.apiService.rescanTransaction(params);
|
|
576
624
|
}
|
|
625
|
+
/**
|
|
626
|
+
* Requests a withdrawal from a wallet
|
|
627
|
+
* @param walletId The ID of the wallet to withdraw from
|
|
628
|
+
* @param params Withdrawal parameters including asset, amount, and recipient
|
|
629
|
+
* @returns Promise with withdrawal response including auto_approved status and withdrawal details
|
|
630
|
+
*/ async requestWithdrawal(walletId, params) {
|
|
631
|
+
validateUUID(walletId, 'walletId');
|
|
632
|
+
validateUUID(params.assetId, 'assetId');
|
|
633
|
+
if (!params.amount || params.amount.trim() === '') {
|
|
634
|
+
throw new Error('Invalid amount provided');
|
|
635
|
+
}
|
|
636
|
+
if (!params.recipientAddress || params.recipientAddress.trim() === '') {
|
|
637
|
+
throw new Error('Invalid recipient address provided');
|
|
638
|
+
}
|
|
639
|
+
if (params.recipientAddress.length > 256) {
|
|
640
|
+
throw new Error('Recipient address exceeds maximum length of 256 characters');
|
|
641
|
+
}
|
|
642
|
+
if (params.notes && params.notes.length > 500) {
|
|
643
|
+
throw new Error('Notes exceed maximum length of 500 characters');
|
|
644
|
+
}
|
|
645
|
+
this.log(`Requesting withdrawal from wallet ${walletId}`);
|
|
646
|
+
const response = await this.apiService.requestWithdrawal(walletId, params);
|
|
647
|
+
this.log(`Withdrawal request completed, auto_approved: ${response.auto_approved}`);
|
|
648
|
+
return response;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Gets the webhook public key for a workspace
|
|
652
|
+
* @param workspaceId The workspace ID
|
|
653
|
+
* @returns Promise with webhook public key (base64 encoded ed25519 public key)
|
|
654
|
+
*/ async getWebhookPublicKey(workspaceId) {
|
|
655
|
+
validateUUID(workspaceId, 'workspaceId');
|
|
656
|
+
this.log(`Getting webhook public key for workspace ${workspaceId}`);
|
|
657
|
+
const response = await this.apiService.getWebhookPublicKey(workspaceId);
|
|
658
|
+
return response;
|
|
659
|
+
}
|
|
577
660
|
constructor(options){
|
|
578
661
|
const { credentials, workspaceId, environment = Environment.Production, logger = false } = options;
|
|
579
662
|
this.apiService = new APIService(credentials, environment);
|
|
@@ -669,14 +752,14 @@ class EtherSigner extends AbstractSigner {
|
|
|
669
752
|
}
|
|
670
753
|
return result.status === TxStatus.Rejected;
|
|
671
754
|
});
|
|
672
|
-
console.log('
|
|
755
|
+
console.log('result', result);
|
|
673
756
|
if (!result.hash) {
|
|
674
757
|
throw new TransactionError('Transaction hash not found in successful response', 'TRANSACTION_HASH_MISSING', result.transaction_id);
|
|
675
758
|
}
|
|
676
759
|
return result.hash;
|
|
677
760
|
}
|
|
678
761
|
// Copied and editted from ethers.js -> Wallet -> BaseWallet
|
|
679
|
-
async signTransaction(tx) {
|
|
762
|
+
async signTransaction(tx, options) {
|
|
680
763
|
const startTime = new Date();
|
|
681
764
|
console.log(`[WalletSDK] Transaction started at: ${startTime.toLocaleString()}`);
|
|
682
765
|
if (!this.address) {
|
|
@@ -716,7 +799,7 @@ class EtherSigner extends AbstractSigner {
|
|
|
716
799
|
accessList: btx.accessList
|
|
717
800
|
};
|
|
718
801
|
// return unseralized as API signTransaction is an asynchoronous action
|
|
719
|
-
const response = await this.APIService.signTransaction(this.walletDetail.WalletID, data);
|
|
802
|
+
const response = await this.APIService.signTransaction(this.walletDetail.WalletID, data, options);
|
|
720
803
|
const txHash = await this.waitForTransactonStatus(response.transaction_id);
|
|
721
804
|
const endTime = new Date();
|
|
722
805
|
const elapsedTimeMs = endTime.getTime() - startTime.getTime();
|
|
@@ -725,7 +808,7 @@ class EtherSigner extends AbstractSigner {
|
|
|
725
808
|
console.log('[WalletSDK] Transaction succeed!');
|
|
726
809
|
return txHash;
|
|
727
810
|
}
|
|
728
|
-
async sendTransaction(tx) {
|
|
811
|
+
async sendTransaction(tx, options) {
|
|
729
812
|
const startTime = new Date();
|
|
730
813
|
console.log(`[WalletSDK] sendTransaction started at: ${startTime.toLocaleString()}`);
|
|
731
814
|
if (!this.address) {
|
|
@@ -753,7 +836,7 @@ class EtherSigner extends AbstractSigner {
|
|
|
753
836
|
const resolvedTx = await resolveProperties(populatedTx);
|
|
754
837
|
const txObj = Transaction.from(resolvedTx);
|
|
755
838
|
console.log('[WalletSDK] Tx Data', txObj);
|
|
756
|
-
const txHash = await this.signTransaction(txObj);
|
|
839
|
+
const txHash = await this.signTransaction(txObj, options);
|
|
757
840
|
// Instead of creating a mock response, get the actual transaction from the provider
|
|
758
841
|
const endTime = new Date();
|
|
759
842
|
const totalElapsedMs = endTime.getTime() - startTime.getTime();
|
|
@@ -802,7 +885,7 @@ class EtherSigner extends AbstractSigner {
|
|
|
802
885
|
// Let the provider create the TransactionResponse using the txHash
|
|
803
886
|
return new TransactionResponse(txResponse, this.provider);
|
|
804
887
|
}
|
|
805
|
-
async signMessage(message) {
|
|
888
|
+
async signMessage(message, options) {
|
|
806
889
|
if (!this.provider) {
|
|
807
890
|
throw new Error('Provider is required for signing operations');
|
|
808
891
|
}
|
|
@@ -818,10 +901,10 @@ class EtherSigner extends AbstractSigner {
|
|
|
818
901
|
method: 'eth_sign',
|
|
819
902
|
message: messageStr,
|
|
820
903
|
chain_id: chainId
|
|
821
|
-
});
|
|
904
|
+
}, options);
|
|
822
905
|
return this.waitForSignature(this.walletDetail.WalletID, response.transaction_id);
|
|
823
906
|
}
|
|
824
|
-
async signTypedData(domain, types, value) {
|
|
907
|
+
async signTypedData(domain, types, value, options) {
|
|
825
908
|
if (!this.provider) {
|
|
826
909
|
throw new Error('Provider is required for signing operations');
|
|
827
910
|
}
|
|
@@ -842,7 +925,7 @@ class EtherSigner extends AbstractSigner {
|
|
|
842
925
|
message: '',
|
|
843
926
|
chain_id: chainId,
|
|
844
927
|
typed_data: typedData
|
|
845
|
-
});
|
|
928
|
+
}, options);
|
|
846
929
|
return this.waitForSignature(this.walletDetail.WalletID, response.transaction_id);
|
|
847
930
|
}
|
|
848
931
|
constructor(credentials, environment, provider, pollerOptions){
|
|
@@ -921,7 +1004,7 @@ class SolanaSigner {
|
|
|
921
1004
|
* Signs a Solana transaction
|
|
922
1005
|
* @param transaction Base64 encoded serialized transaction
|
|
923
1006
|
* @returns Signature as a base58 encoded string
|
|
924
|
-
*/ async signTransaction(transaction) {
|
|
1007
|
+
*/ async signTransaction(transaction, options) {
|
|
925
1008
|
if (!this.address) {
|
|
926
1009
|
await this.getAddress();
|
|
927
1010
|
}
|
|
@@ -936,7 +1019,7 @@ class SolanaSigner {
|
|
|
936
1019
|
tx_method: 'solana_signTransaction'
|
|
937
1020
|
},
|
|
938
1021
|
chainId: '1399811149'
|
|
939
|
-
});
|
|
1022
|
+
}, options);
|
|
940
1023
|
// Wait for the signature
|
|
941
1024
|
return this.waitForTransactionStatus(response.transaction_id);
|
|
942
1025
|
}
|
|
@@ -944,7 +1027,7 @@ class SolanaSigner {
|
|
|
944
1027
|
* Signs a Solana message
|
|
945
1028
|
* @param message The message to sign (string or Uint8Array)
|
|
946
1029
|
* @returns Signature as a base58 encoded string
|
|
947
|
-
*/ async signMessage(message) {
|
|
1030
|
+
*/ async signMessage(message, options) {
|
|
948
1031
|
if (!this.address) {
|
|
949
1032
|
await this.getAddress();
|
|
950
1033
|
}
|
|
@@ -953,14 +1036,14 @@ class SolanaSigner {
|
|
|
953
1036
|
method: 'solana_signMessage',
|
|
954
1037
|
message: messageStr,
|
|
955
1038
|
chain_id: 0 // Not used for Solana but required by API
|
|
956
|
-
});
|
|
1039
|
+
}, options);
|
|
957
1040
|
return this.waitForTransactionStatus(response.transaction_id);
|
|
958
1041
|
}
|
|
959
1042
|
/**
|
|
960
1043
|
* Signs and sends a Solana transaction
|
|
961
1044
|
* @param transaction Base64 encoded serialized transaction
|
|
962
1045
|
* @returns Transaction signature
|
|
963
|
-
*/ async signAndSendTransaction(transaction) {
|
|
1046
|
+
*/ async signAndSendTransaction(transaction, options) {
|
|
964
1047
|
if (!this.address) {
|
|
965
1048
|
await this.getAddress();
|
|
966
1049
|
}
|
|
@@ -969,7 +1052,7 @@ class SolanaSigner {
|
|
|
969
1052
|
from: this.address,
|
|
970
1053
|
method: 'solana_signAndSendTransaction'
|
|
971
1054
|
};
|
|
972
|
-
const response = await this.APIService.signTransaction(this.walletDetail.WalletID, data);
|
|
1055
|
+
const response = await this.APIService.signTransaction(this.walletDetail.WalletID, data, options);
|
|
973
1056
|
const txHash = await this.waitForTransactionStatus(response.transaction_id);
|
|
974
1057
|
console.log('transaction succeed!');
|
|
975
1058
|
return txHash;
|
|
@@ -978,14 +1061,14 @@ class SolanaSigner {
|
|
|
978
1061
|
* Signs multiple Solana transactions
|
|
979
1062
|
* @param transactions Array of base64 encoded serialized transactions
|
|
980
1063
|
* @returns Array of signatures as base58 encoded strings
|
|
981
|
-
*/ async signAllTransactions(transactions) {
|
|
1064
|
+
*/ async signAllTransactions(transactions, options) {
|
|
982
1065
|
if (!this.address) {
|
|
983
1066
|
await this.getAddress();
|
|
984
1067
|
}
|
|
985
1068
|
// We need to get the signatures and then incorporate them into the transactions
|
|
986
1069
|
const signaturePromises = transactions.map(async (transaction)=>{
|
|
987
1070
|
// Get the signature
|
|
988
|
-
const signature = await this.signTransaction(transaction);
|
|
1071
|
+
const signature = await this.signTransaction(transaction, options);
|
|
989
1072
|
// Here you would need to incorporate the signature into the transaction
|
|
990
1073
|
// This is a placeholder - you'll need to implement actual signature incorporation
|
|
991
1074
|
// based on your Solana transaction structure
|
|
@@ -1032,4 +1115,4 @@ class SolanaSigner {
|
|
|
1032
1115
|
}
|
|
1033
1116
|
}
|
|
1034
1117
|
|
|
1035
|
-
export { APIService, AddressType, DEFAULT_POLLER_OPTIONS, DestinationType, Environment, EtherSigner, FystackSDK, PaymentService, SolanaSigner, StatusPoller, TransactionError, TxApprovalStatus, TxStatus, WalletCreationStatus, WalletPurpose, WalletRole, WalletType, WebhookService, createAPI, get, post, transformCreateWalletPayload, transformRescanTransactionParams, transformWalletDetail };
|
|
1118
|
+
export { APIService, AddressType, DEFAULT_POLLER_OPTIONS, DestinationType, Environment, EtherSigner, FystackSDK, PaymentService, SolanaSigner, StatusPoller, TransactionError, TxApprovalStatus, TxStatus, WalletCreationStatus, WalletPurpose, WalletRole, WalletType, WebhookService, WithdrawalStatus, createAPI, get, post, transformCreateWalletPayload, transformRequestWithdrawalParams, transformRescanTransactionParams, transformWalletDetail };
|