@fystack/sdk 0.1.2 → 0.1.4

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/src/api.ts CHANGED
@@ -10,10 +10,10 @@ import {
10
10
  TransactionStatusResponse,
11
11
  CreateWalletResponse,
12
12
  WalletCreationStatusResponse,
13
- WalletType,
14
13
  WalletAsset,
15
- AddressType,
16
- DepositAddressResponse
14
+ DepositAddressResponse,
15
+ RescanTransactionParams,
16
+ WalletByWorkspaceResponse
17
17
  } from './types'
18
18
  import {
19
19
  CreateCheckoutPayload,
@@ -23,6 +23,7 @@ import {
23
23
  GetCheckoutPaymentResponse,
24
24
  GetCheckoutResponse
25
25
  } from './payment'
26
+ import { AddressType, DestinationType, WalletPurpose, WalletType } from './enum'
26
27
 
27
28
  interface APIResponse {
28
29
  data: any
@@ -45,9 +46,18 @@ export interface WalletDetail {
45
46
  Address: string
46
47
  }
47
48
 
49
+ export interface SweepTaskParams {
50
+ minTriggerValueUsd: number
51
+ destinationWalletId: string
52
+ destinationType: DestinationType
53
+ }
54
+
48
55
  export interface CreateWalletPayload {
49
56
  name: string
50
57
  walletType: WalletType
58
+ walletPurpose?: WalletPurpose
59
+ sweepTaskParams?: SweepTaskParams
60
+ sweepTaskId?: string
51
61
  }
52
62
 
53
63
  export interface PaymentServiceParams {
@@ -55,11 +65,6 @@ export interface PaymentServiceParams {
55
65
  environment: Environment
56
66
  }
57
67
 
58
- export enum WalletAddressType {
59
- Evm = 'evm',
60
- Sol = 'sol'
61
- }
62
-
63
68
  async function composeAPIHeaders(
64
69
  credentials: APICredentials,
65
70
  httpMethod: string,
@@ -109,10 +114,14 @@ export class APIService {
109
114
  this.API = createAPI(environment)
110
115
  }
111
116
 
112
- async getWalletDetail(
113
- addressType: WalletAddressType = WalletAddressType.Evm,
114
- walletId?: string
115
- ): Promise<WalletDetail> {
117
+ async getWallets(workspaceId: string): Promise<WalletByWorkspaceResponse[]> {
118
+ const endpoint = this.API.endpoints.getWallets(workspaceId)
119
+ const headers = await composeAPIHeaders(this.credentials, 'GET', endpoint)
120
+ const response = await get(endpoint, headers)
121
+ return response.data
122
+ }
123
+
124
+ async getWalletDetail(addressType = AddressType.Evm, walletId?: string): Promise<WalletDetail> {
116
125
  const endpoint = this.API.endpoints.getWalletDetail(walletId)
117
126
  const headers = await composeAPIHeaders(this.credentials, 'GET', endpoint)
118
127
  console.info('headers', headers)
@@ -201,6 +210,18 @@ export class APIService {
201
210
  const response = await get(endpoint, headers)
202
211
  return response.data
203
212
  }
213
+
214
+ /**
215
+ * Rescans a transaction on a specific network
216
+ * @param params Transaction hash and network ID
217
+ * @returns API response
218
+ */
219
+ async rescanTransaction(params: RescanTransactionParams): Promise<void> {
220
+ const endpoint = this.API.endpoints.rescanTransaction()
221
+ const transformedParams = transformRescanTransactionParams(params)
222
+ const headers = await composeAPIHeaders(this.credentials, 'POST', endpoint, transformedParams)
223
+ await post(endpoint, transformedParams, headers)
224
+ }
204
225
  }
205
226
 
206
227
  export class PaymentService {
@@ -329,7 +350,23 @@ export function transformWalletDetail(data: Record<string, string>): WalletDetai
329
350
  export function transformCreateWalletPayload(data: CreateWalletPayload) {
330
351
  return {
331
352
  name: data.name,
332
- wallet_type: data.walletType
353
+ wallet_type: data.walletType,
354
+ ...(data.walletPurpose !== undefined && { wallet_purpose: data.walletPurpose }),
355
+ ...(data.sweepTaskParams !== undefined && {
356
+ sweep_task_params: {
357
+ min_trigger_value_usd: data.sweepTaskParams?.minTriggerValueUsd,
358
+ destination_wallet_id: data.sweepTaskParams?.destinationWalletId,
359
+ destination_type: data.sweepTaskParams?.destinationType
360
+ }
361
+ }),
362
+ ...(data.sweepTaskId !== undefined && { sweep_task_id: data.sweepTaskId })
363
+ }
364
+ }
365
+
366
+ export function transformRescanTransactionParams(data: RescanTransactionParams) {
367
+ return {
368
+ tx_hash: data.txHash,
369
+ network_id: data.networkId
333
370
  }
334
371
  }
335
372
 
package/src/config.ts CHANGED
@@ -11,6 +11,7 @@ export interface APIEndpoints {
11
11
  getSignStatus: (walletId: string, transactionId: string) => string
12
12
  getTransactionStatus: (walletId: string, transactionId: string) => string
13
13
  getWalletDetail: (walletId?: string) => string
14
+ getWallets: (workspaceId: string) => string
14
15
  createWallet: () => string
15
16
  createCheckout: () => string
16
17
  getCheckout: (checkoutId: string) => string
@@ -19,6 +20,7 @@ export interface APIEndpoints {
19
20
  getWalletCreationStatus: (walletId: string) => string
20
21
  getWalletAssets: (walletId: string) => string
21
22
  getDepositAddress: (walletId: string, addressType: string) => string
23
+ rescanTransaction: () => string
22
24
  }
23
25
 
24
26
  const getBaseURL = (env: Environment): string => {
@@ -26,7 +28,7 @@ const getBaseURL = (env: Environment): string => {
26
28
  case Environment.Local:
27
29
  return 'http://localhost:8150'
28
30
  case Environment.Sandbox:
29
- return 'https://apex.void.exchange'
31
+ return 'https://api-dev.fystack.io'
30
32
  case Environment.Production:
31
33
  return 'https://api.fystack.io'
32
34
  }
@@ -50,6 +52,7 @@ const createAPI = (env: Environment): APIConfig => {
50
52
  walletId
51
53
  ? withBaseURL(`/web3/wallet-detail/${walletId}`)
52
54
  : withBaseURL('/web3/wallet-detail'),
55
+ getWallets: (workspaceId: string) => withBaseURL(`/workspaces/${workspaceId}/wallets`),
53
56
  createWallet: () => withBaseURL('/wallets'),
54
57
  createCheckout: () => withBaseURL('/checkouts'),
55
58
  getCheckout: (checkoutId: string) => withBaseURL(`/checkouts/${checkoutId}`),
@@ -67,7 +70,8 @@ const createAPI = (env: Environment): APIConfig => {
67
70
  withBaseURL(`/wallets/creation-status/${walletId}`),
68
71
  getWalletAssets: (walletId: string) => withBaseURL(`/wallets/${walletId}/assets`),
69
72
  getDepositAddress: (walletId: string, addressType: string) =>
70
- withBaseURL(`/wallets/${walletId}/deposit-address?address_type=${addressType}`)
73
+ withBaseURL(`/wallets/${walletId}/deposit-address?address_type=${addressType}`),
74
+ rescanTransaction: () => withBaseURL('/networks/rescan-transaction')
71
75
  }
72
76
  }
73
77
  }
package/src/enum.ts ADDED
@@ -0,0 +1,52 @@
1
+ // Wallets
2
+ export enum WalletType {
3
+ Standard = 'standard',
4
+ MPC = 'mpc'
5
+ }
6
+
7
+ export enum WalletPurpose {
8
+ General = 'general',
9
+ Gastank = 'gas_tank',
10
+ Deployment = 'deployment',
11
+ Custody = 'custody',
12
+ User = 'user',
13
+ Payment = 'payment'
14
+ }
15
+
16
+ export enum WalletCreationStatus {
17
+ Pending = 'pending',
18
+ Success = 'success',
19
+ Error = 'error'
20
+ }
21
+
22
+ export enum AddressType {
23
+ Evm = 'evm',
24
+ Solana = 'sol',
25
+ Tron = 'tron'
26
+ }
27
+
28
+ export enum DestinationType {
29
+ InternalWallet = 'internal_wallet',
30
+ AddressBook = 'address_book'
31
+ }
32
+
33
+ export enum TxStatus {
34
+ Pending = 'pending',
35
+ Completed = 'completed',
36
+ Confirmed = 'confirmed',
37
+ Failed = 'failed',
38
+ PendingApproval = 'pending_approval',
39
+ Rejected = 'rejected'
40
+ }
41
+
42
+ export enum TxApprovalStatus {
43
+ Pending = 'pending',
44
+ Approved = 'approved',
45
+ Rejected = 'rejected'
46
+ }
47
+
48
+ export enum WalletRole {
49
+ Admin = 'wallet_admin',
50
+ Signer = 'wallet_signer',
51
+ Viewer = 'wallet_viewer'
52
+ }
package/src/index.ts CHANGED
@@ -3,5 +3,6 @@ export * from './signer'
3
3
  export * from './solanaSigner'
4
4
  export * from './api'
5
5
  export * from './types'
6
+ export * from './enum'
6
7
  export * from './config'
7
8
  export * from './utils/statusPoller'
package/src/sdk.ts CHANGED
@@ -1,20 +1,22 @@
1
1
  import { APIService } from './api'
2
- import { APICredentials, CreateWalletOptions } from './types'
3
2
  import { Environment } from './config'
4
3
  import { StatusPoller } from './utils/statusPoller'
5
4
  import {
6
- WalletCreationStatus,
7
5
  CreateWalletResponse,
8
6
  WalletCreationStatusResponse,
9
- WalletType,
10
7
  WalletAsset,
11
- AddressType,
12
- DepositAddressResponse
8
+ DepositAddressResponse,
9
+ APICredentials,
10
+ CreateWalletOptions,
11
+ RescanTransactionParams,
12
+ WalletByWorkspaceResponse
13
13
  } from './types'
14
14
  import { validateUUID } from './utils'
15
+ import { AddressType, WalletCreationStatus, WalletType } from './enum'
15
16
 
16
17
  export interface SDKOptions {
17
18
  credentials: APICredentials
19
+ workspaceId?: string
18
20
  environment?: Environment
19
21
  logger?: boolean
20
22
  }
@@ -22,11 +24,18 @@ export interface SDKOptions {
22
24
  export class FystackSDK {
23
25
  private apiService: APIService
24
26
  private enableLogging: boolean
27
+ private workspaceId?: string
25
28
 
26
29
  constructor(options: SDKOptions) {
27
- const { credentials, environment = Environment.Production, logger = false } = options
30
+ const {
31
+ credentials,
32
+ workspaceId,
33
+ environment = Environment.Production,
34
+ logger = false
35
+ } = options
28
36
  this.apiService = new APIService(credentials, environment)
29
37
  this.enableLogging = logger
38
+ this.workspaceId = workspaceId
30
39
  }
31
40
 
32
41
  private log(message: string): void {
@@ -45,11 +54,20 @@ export class FystackSDK {
45
54
  options: CreateWalletOptions,
46
55
  waitForCompletion: boolean = true
47
56
  ): Promise<CreateWalletResponse> {
48
- const { name, walletType = WalletType.Standard } = options
57
+ const {
58
+ name,
59
+ walletType = WalletType.Standard,
60
+ sweepTaskParams,
61
+ walletPurpose,
62
+ sweepTaskId
63
+ } = options
49
64
 
50
65
  const response = await this.apiService.createWallet({
51
66
  name,
52
- walletType
67
+ walletType,
68
+ walletPurpose,
69
+ sweepTaskParams,
70
+ sweepTaskId
53
71
  })
54
72
 
55
73
  if (waitForCompletion && response.status === WalletCreationStatus.Pending) {
@@ -59,6 +77,19 @@ export class FystackSDK {
59
77
  return response
60
78
  }
61
79
 
80
+ /**
81
+ * Gets all wallets for the workspace
82
+ * @returns Promise with list of wallets
83
+ */
84
+ async getWallets(): Promise<WalletByWorkspaceResponse[]> {
85
+ if (!this.workspaceId) {
86
+ throw new Error('Workspace ID is required. Please set workspaceId in the constructor.')
87
+ }
88
+
89
+ const wallets = await this.apiService.getWallets(this.workspaceId)
90
+ return wallets
91
+ }
92
+
62
93
  /**
63
94
  * Gets the current status of a wallet creation process
64
95
  * @param walletId The ID of the wallet being created
@@ -137,4 +168,19 @@ export class FystackSDK {
137
168
  const depositAddressInfo = await this.apiService.getDepositAddress(walletId, addressType)
138
169
  return depositAddressInfo
139
170
  }
171
+
172
+ /**
173
+ * Rescans a transaction on a specific network
174
+ * @param params Transaction hash and network ID
175
+ * @returns Promise that resolves when the rescan is initiated
176
+ */
177
+ async rescanTransaction(params: RescanTransactionParams): Promise<void> {
178
+ validateUUID(params.networkId, 'networkId')
179
+
180
+ if (!params.txHash || params.txHash.trim() === '') {
181
+ throw new Error('Invalid transaction hash provided')
182
+ }
183
+
184
+ await this.apiService.rescanTransaction(params)
185
+ }
140
186
  }
package/src/signer.ts CHANGED
@@ -15,10 +15,11 @@ import {
15
15
  Signature
16
16
  } from 'ethers'
17
17
  import { TransactionRequest } from 'ethers/src.ts/providers'
18
- import { APIService, WalletDetail, WalletAddressType } from './api'
19
- import { APICredentials, TransactionStatusResponse, TxStatus, TransactionError } from './types'
18
+ import { APIService, WalletDetail } from './api'
19
+ import { APICredentials, TransactionStatusResponse, TransactionError } from './types'
20
20
  import { Environment } from './config'
21
21
  import { StatusPoller, StatusPollerOptions } from './utils/statusPoller'
22
+ import { AddressType, TxStatus } from './enum'
22
23
 
23
24
  export class EtherSigner extends AbstractSigner {
24
25
  private address!: string
@@ -73,7 +74,7 @@ export class EtherSigner extends AbstractSigner {
73
74
  }
74
75
 
75
76
  const detail: WalletDetail = await this.APIService.getWalletDetail(
76
- WalletAddressType.Evm,
77
+ AddressType.Evm,
77
78
  this.walletDetail?.WalletID
78
79
  )
79
80
 
@@ -168,6 +169,14 @@ export class EtherSigner extends AbstractSigner {
168
169
  const startTime = new Date()
169
170
  console.log(`[WalletSDK] Transaction started at: ${startTime.toLocaleString()}`)
170
171
 
172
+ if (!this.address) {
173
+ await this.getAddress()
174
+ }
175
+
176
+ if (!this.walletDetail) {
177
+ this.walletDetail = await this.APIService.getWalletDetail()
178
+ }
179
+
171
180
  // Replace any Addressable or ENS name with an address
172
181
  const { to, from } = await resolveProperties({
173
182
  to: tx.to ? resolveAddress(tx.to, this.provider) : undefined,
@@ -229,6 +238,10 @@ export class EtherSigner extends AbstractSigner {
229
238
  await this.getAddress()
230
239
  }
231
240
 
241
+ if (!this.walletDetail) {
242
+ this.walletDetail = await this.APIService.getWalletDetail()
243
+ }
244
+
232
245
  checkProvider(this, 'sendTransaction')
233
246
 
234
247
  // Only populate if gas fees are not set
@@ -1,10 +1,11 @@
1
- import { APIService, WalletAddressType, WalletDetail } from './api'
2
- import { APICredentials, TransactionStatusResponse, TxStatus, TransactionError } from './types'
1
+ import { APIService, WalletDetail } from './api'
2
+ import { APICredentials, TransactionStatusResponse, TransactionError } from './types'
3
3
  import { Environment } from './config'
4
4
  import { StatusPoller, StatusPollerOptions } from './utils/statusPoller'
5
5
  import { Transaction, PublicKey, VersionedTransaction } from '@solana/web3.js'
6
6
  import bs58 from 'bs58'
7
7
  import { Buffer } from 'buffer'
8
+ import { AddressType, TxStatus } from './enum'
8
9
 
9
10
  export class SolanaSigner {
10
11
  private address!: string
@@ -56,7 +57,7 @@ export class SolanaSigner {
56
57
  }
57
58
 
58
59
  const detail: WalletDetail = await this.APIService.getWalletDetail(
59
- WalletAddressType.Sol,
60
+ AddressType.Solana,
60
61
  this.walletDetail?.WalletID
61
62
  )
62
63
 
package/src/types.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import { SweepTaskParams } from './api'
2
+ import { TxApprovalStatus, TxStatus, WalletCreationStatus, WalletPurpose, WalletRole, WalletType } from './enum'
3
+
1
4
  export class TransactionError extends Error {
2
5
  constructor(
3
6
  message: string,
@@ -9,20 +12,6 @@ export class TransactionError extends Error {
9
12
  this.name = 'TransactionError'
10
13
  }
11
14
  }
12
- export enum TxStatus {
13
- Pending = 'pending',
14
- Completed = 'completed',
15
- Confirmed = 'confirmed',
16
- Failed = 'failed',
17
- PendingApproval = 'pending_approval',
18
- Rejected = 'rejected'
19
- }
20
-
21
- export enum TxApprovalStatus {
22
- Pending = 'pending',
23
- Approved = 'approved',
24
- Rejected = 'rejected'
25
- }
26
15
 
27
16
  export interface APICredentials {
28
17
  apiKey: string
@@ -79,20 +68,12 @@ export interface TransactionStatusResponse {
79
68
  failed_reason?: string
80
69
  }
81
70
 
82
- // Wallets
83
- export enum WalletType {
84
- Standard = 'standard',
85
- MPC = 'mpc'
86
- }
87
-
88
71
  export interface CreateWalletOptions {
89
72
  name: string
90
73
  walletType: WalletType
91
- }
92
- export enum WalletCreationStatus {
93
- Pending = 'pending',
94
- Success = 'success',
95
- Error = 'error'
74
+ walletPurpose?: WalletPurpose
75
+ sweepTaskParams?: SweepTaskParams
76
+ sweepTaskId?: string
96
77
  }
97
78
 
98
79
  export interface CreateWalletResponse {
@@ -152,13 +133,35 @@ export interface WalletAsset {
152
133
  asset: WalletAssetDetail
153
134
  }
154
135
 
155
- export enum AddressType {
156
- Evm = 'evm',
157
- Solana = 'sol'
158
- }
159
-
160
136
  export interface DepositAddressResponse {
161
137
  asset_id?: string
162
138
  address: string
163
139
  qr_code: string
164
140
  }
141
+
142
+ export interface RescanTransactionParams {
143
+ txHash: string
144
+ networkId: string
145
+ }
146
+
147
+ export interface WalletResponse {
148
+ id: string
149
+ name: string
150
+ value_usd: string
151
+ role: WalletRole
152
+ }
153
+
154
+ export interface TopAssets {
155
+ symbol: string
156
+ logo_url: string
157
+ }
158
+
159
+ export interface WalletByWorkspaceResponse {
160
+ id: string
161
+ name: string
162
+ role: string
163
+ wallet_type: string
164
+ value_usd: string
165
+ top_assets: TopAssets[]
166
+ wallet_purpose: string
167
+ }
package/test.js DELETED
@@ -1,76 +0,0 @@
1
- import { TypedDataEncoder, verifyTypedData, Signature } from 'ethers'
2
-
3
- // 0x2f71f2595162eaca40708bf6d6327d437e760b27d26f3a933389ebdb4eedf3b167008df6f1d403503c82a6d58da5659b14c578019603d6b138b2c03729c92af701
4
- // 0xd77d10c530b25d1ea6a466eb2b3169138b5ca0d1320ff54bbad000d97f686d0a314c5233844d84da5adf3580afa38c82d9595c22a985acfea02ca722c55df48a00
5
- // Example usage
6
- const address = '0xFFe120Fd4D5AB5A9f25b25c30620ac8ee3E1EF21'
7
- const jsonData = {
8
- domain: {
9
- name: 'Permit2',
10
- chainId: '8453',
11
- verifyingContract: '0x000000000022d473030f116ddee9f6b43ac78ba3'
12
- },
13
- types: {
14
- PermitSingle: [
15
- { name: 'details', type: 'PermitDetails' },
16
- { name: 'spender', type: 'address' },
17
- { name: 'sigDeadline', type: 'uint256' }
18
- ],
19
- PermitDetails: [
20
- { name: 'token', type: 'address' },
21
- { name: 'amount', type: 'uint160' },
22
- { name: 'expiration', type: 'uint48' },
23
- { name: 'nonce', type: 'uint48' }
24
- ]
25
- },
26
- message: {
27
- details: {
28
- token: '0x0b3e328455c4059eeb9e3f84b5543f74e24e7e1b',
29
- amount: '1461501637330902918203684832716283019655932542975',
30
- expiration: '1743496074',
31
- nonce: '0'
32
- },
33
- spender: '0x6ff5693b99212da76ad316178a184ab56d299b43',
34
- sigDeadline: '1740905874'
35
- }
36
- }
37
- const signature =
38
- '0x032f29648f9c2d9d2524aef755c225b96121f2c9b01beee5869a70ef95eb089548dc41f71126dac83c1632738dbea12bf5c925715068e32dda0064701bfc019e00'
39
-
40
- async function verifySignature(address, jsonData, signature) {
41
- try {
42
- // Step 1: Compute the EIP-712 hash
43
- const computedHash = TypedDataEncoder.hash(jsonData.domain, jsonData.types, jsonData.message)
44
- console.log('🔹 Computed EIP-712 Hash:', computedHash)
45
-
46
- // Step 2: Recover the signer address
47
- const recoveredAddress = verifyTypedData(
48
- jsonData.domain,
49
- jsonData.types,
50
- jsonData.message,
51
- signature
52
- )
53
-
54
- console.log('✅ Recovered Address:', recoveredAddress)
55
- console.log('🔹 Expected Address:', address)
56
-
57
- // Step 3: Compare the addresses
58
- const isValid = recoveredAddress.toLowerCase() === address.toLowerCase()
59
- console.log('🔹 Is Signature Valid?', isValid)
60
-
61
- // Step 4: Debug signature parts (r, s, v)
62
- const sig = Signature.from(signature)
63
- console.log('🔹 Signature Parts:')
64
- console.log(' r:', sig.r)
65
- console.log(' s:', sig.s)
66
- console.log(' v:', sig.v)
67
-
68
- return isValid
69
- } catch (error) {
70
- console.error('❌ Signature Verification Failed:', error)
71
- return false
72
- }
73
- }
74
-
75
- // Run verification
76
- verifySignature(address, jsonData, signature)