@shogun-sdk/intents-sdk 1.1.1 → 1.2.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.
Files changed (115) hide show
  1. package/dist/esm/constants.js +24 -8
  2. package/dist/esm/constants.js.map +1 -1
  3. package/dist/esm/core/evm/intent-provider.js +55 -2
  4. package/dist/esm/core/evm/intent-provider.js.map +1 -1
  5. package/dist/esm/core/evm/order-signature.js +12 -1
  6. package/dist/esm/core/evm/order-signature.js.map +1 -1
  7. package/dist/esm/core/evm/permit2.js +24 -1
  8. package/dist/esm/core/evm/permit2.js.map +1 -1
  9. package/dist/esm/core/evm/sdk.js +5 -0
  10. package/dist/esm/core/evm/sdk.js.map +1 -1
  11. package/dist/esm/core/evm/validator.js +21 -0
  12. package/dist/esm/core/evm/validator.js.map +1 -1
  13. package/dist/esm/core/orders/cross-chain.js +3 -0
  14. package/dist/esm/core/orders/cross-chain.js.map +1 -1
  15. package/dist/esm/core/orders/dca-single-chain.js +169 -0
  16. package/dist/esm/core/orders/dca-single-chain.js.map +1 -0
  17. package/dist/esm/core/orders/single-chain.js +4 -0
  18. package/dist/esm/core/orders/single-chain.js.map +1 -1
  19. package/dist/esm/core/sdk.js +55 -81
  20. package/dist/esm/core/sdk.js.map +1 -1
  21. package/dist/esm/core/solana/dca/cancel-order.js +61 -0
  22. package/dist/esm/core/solana/dca/cancel-order.js.map +1 -0
  23. package/dist/esm/core/solana/dca/create-order.js +82 -0
  24. package/dist/esm/core/solana/dca/create-order.js.map +1 -0
  25. package/dist/esm/core/solana/inspect.js +43 -0
  26. package/dist/esm/core/solana/inspect.js.map +1 -0
  27. package/dist/esm/core/solana/sdk.js +36 -0
  28. package/dist/esm/core/solana/sdk.js.map +1 -1
  29. package/dist/esm/core/solana/utils.js.map +1 -1
  30. package/dist/esm/core/solana/validator.js +3 -0
  31. package/dist/esm/core/solana/validator.js.map +1 -1
  32. package/dist/esm/core/sui/sdk.js +0 -3
  33. package/dist/esm/core/sui/sdk.js.map +1 -1
  34. package/dist/esm/core/sui/validator.js +4 -0
  35. package/dist/esm/core/sui/validator.js.map +1 -1
  36. package/dist/esm/index.js +3 -1
  37. package/dist/esm/index.js.map +1 -1
  38. package/dist/esm/utils/base-validator.js +28 -0
  39. package/dist/esm/utils/base-validator.js.map +1 -1
  40. package/dist/esm/utils/order-validator.js +31 -0
  41. package/dist/esm/utils/order-validator.js.map +1 -1
  42. package/dist/esm/utils/quote/liquidswap.js.map +1 -1
  43. package/dist/types/constants.d.ts +10 -7
  44. package/dist/types/constants.d.ts.map +1 -1
  45. package/dist/types/core/evm/intent-provider.d.ts +5 -2
  46. package/dist/types/core/evm/intent-provider.d.ts.map +1 -1
  47. package/dist/types/core/evm/order-signature.d.ts +5 -0
  48. package/dist/types/core/evm/order-signature.d.ts.map +1 -1
  49. package/dist/types/core/evm/permit2.d.ts +90 -0
  50. package/dist/types/core/evm/permit2.d.ts.map +1 -1
  51. package/dist/types/core/evm/sdk.d.ts +3 -1
  52. package/dist/types/core/evm/sdk.d.ts.map +1 -1
  53. package/dist/types/core/evm/validator.d.ts +4 -0
  54. package/dist/types/core/evm/validator.d.ts.map +1 -1
  55. package/dist/types/core/orders/cross-chain.d.ts.map +1 -1
  56. package/dist/types/core/orders/dca-single-chain.d.ts +47 -0
  57. package/dist/types/core/orders/dca-single-chain.d.ts.map +1 -0
  58. package/dist/types/core/orders/single-chain.d.ts.map +1 -1
  59. package/dist/types/core/sdk.d.ts +15 -10
  60. package/dist/types/core/sdk.d.ts.map +1 -1
  61. package/dist/types/core/solana/dca/cancel-order.d.ts +5 -0
  62. package/dist/types/core/solana/dca/cancel-order.d.ts.map +1 -0
  63. package/dist/types/core/solana/dca/create-order.d.ts +8 -0
  64. package/dist/types/core/solana/dca/create-order.d.ts.map +1 -0
  65. package/dist/types/core/solana/inspect.d.ts +14 -0
  66. package/dist/types/core/solana/inspect.d.ts.map +1 -0
  67. package/dist/types/core/solana/sdk.d.ts +4 -1
  68. package/dist/types/core/solana/sdk.d.ts.map +1 -1
  69. package/dist/types/core/solana/utils.d.ts +2 -1
  70. package/dist/types/core/solana/utils.d.ts.map +1 -1
  71. package/dist/types/core/solana/validator.d.ts +1 -0
  72. package/dist/types/core/solana/validator.d.ts.map +1 -1
  73. package/dist/types/core/sui/sdk.d.ts +1 -2
  74. package/dist/types/core/sui/sdk.d.ts.map +1 -1
  75. package/dist/types/core/sui/validator.d.ts +1 -0
  76. package/dist/types/core/sui/validator.d.ts.map +1 -1
  77. package/dist/types/index.d.ts +3 -1
  78. package/dist/types/index.d.ts.map +1 -1
  79. package/dist/types/types/intent.d.ts +22 -0
  80. package/dist/types/types/intent.d.ts.map +1 -1
  81. package/dist/types/utils/base-validator.d.ts +7 -0
  82. package/dist/types/utils/base-validator.d.ts.map +1 -1
  83. package/dist/types/utils/order-validator.d.ts +15 -0
  84. package/dist/types/utils/order-validator.d.ts.map +1 -1
  85. package/package.json +1 -1
  86. package/src/auth/siwe.ts +1 -1
  87. package/src/constants.ts +72 -39
  88. package/src/core/evm/connectors/hyperevm.ts +1 -1
  89. package/src/core/evm/intent-provider.ts +88 -4
  90. package/src/core/evm/order-signature.ts +23 -1
  91. package/src/core/evm/permit2.ts +47 -1
  92. package/src/core/evm/sdk.ts +16 -3
  93. package/src/core/evm/validator.ts +32 -0
  94. package/src/core/orders/api/fetch.ts +0 -1
  95. package/src/core/orders/api/index.ts +4 -4
  96. package/src/core/orders/cross-chain.ts +4 -0
  97. package/src/core/orders/dca-single-chain.ts +143 -0
  98. package/src/core/orders/single-chain.ts +6 -0
  99. package/src/core/sdk.ts +72 -100
  100. package/src/core/solana/cancel-order.ts +1 -1
  101. package/src/core/solana/dca/cancel-order.ts +91 -0
  102. package/src/core/solana/dca/create-order.ts +142 -0
  103. package/src/core/solana/inspect.ts +50 -0
  104. package/src/core/solana/order-instructions.ts +1 -1
  105. package/src/core/solana/sdk.ts +65 -2
  106. package/src/core/solana/utils.ts +2 -1
  107. package/src/core/solana/validator.ts +4 -0
  108. package/src/core/sui/sdk.ts +2 -6
  109. package/src/core/sui/validator.ts +5 -0
  110. package/src/index.ts +12 -1
  111. package/src/types/api.ts +1 -1
  112. package/src/types/intent.ts +27 -0
  113. package/src/utils/base-validator.ts +40 -0
  114. package/src/utils/order-validator.ts +38 -0
  115. package/src/utils/quote/liquidswap.ts +2 -2
@@ -0,0 +1,142 @@
1
+ import {
2
+ address,
3
+ addSignersToTransactionMessage,
4
+ appendTransactionMessageInstructions,
5
+ createNoopSigner,
6
+ createSolanaRpc,
7
+ createTransactionMessage,
8
+ fetchEncodedAccount,
9
+ generateKeyPairSigner,
10
+ getAddressEncoder,
11
+ getProgramDerivedAddress,
12
+ getTransactionCodec,
13
+ partiallySignTransactionMessageWithSigners,
14
+ pipe,
15
+ setTransactionMessageFeePayerSigner,
16
+ setTransactionMessageLifetimeUsingBlockhash,
17
+ type Address,
18
+ type IInstruction,
19
+ } from '@solana/kit';
20
+ import type { DcaSingleChainOrder } from '../../orders/dca-single-chain.js';
21
+ import type { SolanaOrderInstructionResult } from '../order-instructions.js';
22
+ import { getDefaultSolanaRPC } from '../client.js';
23
+ import { genSecretHashAndNumber } from '../utils.js';
24
+ import {
25
+ NATIVE_SOLANA_TOKEN_ADDRESS,
26
+ SINGLE_CHAIN_GUARD_ADDRESSES,
27
+ WRAPPED_SOL_MINT_ADDRESS,
28
+ } from '../../../constants.js';
29
+ import {
30
+ ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
31
+ fetchMint,
32
+ getCreateAssociatedTokenInstructionAsync,
33
+ getSyncNativeInstruction,
34
+ } from '@solana-program/token';
35
+ import { ChainID } from '../../../chains.js';
36
+ import { getTransferSolInstruction } from '@solana-program/system';
37
+ import { getCreateDcaOrderInstructionAsync } from '../generated/single-chain/index.js';
38
+
39
+ export async function getSolanaDcaSingleChainOrderInstructions(
40
+ order: DcaSingleChainOrder,
41
+ options?: { rpcUrl?: string },
42
+ ): Promise<SolanaOrderInstructionResult & { secretNumber: string }> {
43
+ const rpc = options?.rpcUrl ? createSolanaRpc(options.rpcUrl) : getDefaultSolanaRPC();
44
+ const orderSigner = await generateKeyPairSigner();
45
+ const signer = createNoopSigner(order.user as Address);
46
+
47
+ let tokenInMint = address(order.tokenIn);
48
+
49
+ const { secretHash, secretNumber } = genSecretHashAndNumber(order);
50
+
51
+ const orderUserAddress = address(order.user);
52
+ const spendingNative = tokenInMint === NATIVE_SOLANA_TOKEN_ADDRESS;
53
+
54
+ if (spendingNative) {
55
+ tokenInMint = WRAPPED_SOL_MINT_ADDRESS;
56
+ }
57
+
58
+ const tokenMintProgram = await fetchMint(rpc, tokenInMint);
59
+
60
+ const guardAddress = address(SINGLE_CHAIN_GUARD_ADDRESSES[ChainID.Solana]); // Assuming DCA uses same guard
61
+ const addressEncoder = getAddressEncoder();
62
+ const instructions: Array<IInstruction> = [];
63
+
64
+ const [tokenInProgramAccount] = await getProgramDerivedAddress({
65
+ programAddress: ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
66
+ seeds: [
67
+ addressEncoder.encode(orderUserAddress),
68
+ addressEncoder.encode(tokenMintProgram.programAddress),
69
+ addressEncoder.encode(tokenInMint),
70
+ ],
71
+ });
72
+
73
+ const userTokenInAccount = await fetchEncodedAccount(rpc, tokenInProgramAccount);
74
+
75
+ if (!userTokenInAccount.exists) {
76
+ const createAccountIx = await getCreateAssociatedTokenInstructionAsync({
77
+ payer: signer,
78
+ ata: tokenInProgramAccount,
79
+ owner: orderUserAddress,
80
+ mint: tokenMintProgram.address,
81
+ tokenProgram: tokenMintProgram.programAddress,
82
+ });
83
+
84
+ instructions.push(createAccountIx);
85
+ }
86
+
87
+ const totalAmountIn = BigInt(order.amountInPerInterval) * BigInt(order.totalIntervals);
88
+
89
+ if (spendingNative) {
90
+ const transferIx = getTransferSolInstruction({
91
+ amount: totalAmountIn,
92
+ destination: userTokenInAccount.address,
93
+ source: signer,
94
+ });
95
+
96
+ instructions.push(transferIx);
97
+
98
+ const syncNativeIx = getSyncNativeInstruction({
99
+ account: userTokenInAccount.address,
100
+ });
101
+
102
+ instructions.push(syncNativeIx);
103
+ }
104
+
105
+ const createDcaOrderIx = await getCreateDcaOrderInstructionAsync({
106
+ user: signer,
107
+ order: orderSigner,
108
+ guard: guardAddress,
109
+ tokenInMint: tokenInMint,
110
+ userTokenInAccount: userTokenInAccount.address,
111
+ tokenInProgram: tokenMintProgram.programAddress,
112
+ amountInPerInterval: order.amountInPerInterval,
113
+ totalIntervals: order.totalIntervals,
114
+ intervalDuration: order.intervalDuration,
115
+ deadline: order.deadline,
116
+ amountOutMin: order.amountOutMin,
117
+ secretHash: Uint8Array.from(secretHash),
118
+ extraTransfersAmounts: [], // TODO: Implement extra transfers
119
+ });
120
+
121
+ instructions.push(createDcaOrderIx);
122
+
123
+ const { value: latestBlockhash } = await rpc.getLatestBlockhash({ commitment: 'confirmed' }).send();
124
+
125
+ const txMessage = pipe(
126
+ createTransactionMessage({ version: 0 }),
127
+ (tx) => setTransactionMessageFeePayerSigner(signer, tx),
128
+ (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
129
+ (tx) => appendTransactionMessageInstructions(instructions, tx),
130
+ (tx) => addSignersToTransactionMessage([orderSigner], tx),
131
+ );
132
+
133
+ const partiallySignedTransaction = await partiallySignTransactionMessageWithSigners(txMessage);
134
+
135
+ const txBytes = getTransactionCodec().encode(partiallySignedTransaction);
136
+
137
+ return {
138
+ orderAddress: orderSigner.address,
139
+ txBytes,
140
+ secretNumber,
141
+ };
142
+ }
@@ -0,0 +1,50 @@
1
+ import { address, createSolanaRpc, type Base58EncodedBytes } from '@solana/kit';
2
+ import { getDefaultSolanaRPC } from './client.js';
3
+ import { logger } from '../../utils/logger.js';
4
+
5
+ /**
6
+ * Inspect Solana guards to find orders that are currently locked on-chain.
7
+ * @param userAddress - The user's Solana address
8
+ * @param config - The Solana RPC configuration
9
+ * @returns An object containing the Solana guard programs for cross-chain and single-chain orders
10
+ */
11
+ export async function getSolanaOrdersWithLockedFunds(userAddress: string, config?: { rpcUrl?: string }) {
12
+ const rpc = config?.rpcUrl ? createSolanaRpc(config.rpcUrl) : getDefaultSolanaRPC();
13
+
14
+ // const singleChainGuardAddress = SINGLE_CHAIN_GUARD_ADDRESSES[ChainID.Solana];
15
+
16
+ const programAccountAddress = address('43cctGU9QJ4WEPzLoNEvo3TPiv6nMUG9puN2pXQSnB6V');
17
+ const programAccountsConfig = {
18
+ encoding: 'base64',
19
+ filters: [
20
+ {
21
+ memcmp: {
22
+ offset: 8n,
23
+ encoding: 'base58',
24
+ bytes: userAddress as Base58EncodedBytes,
25
+ },
26
+ },
27
+ ],
28
+ } as Readonly<unknown>;
29
+
30
+ logger.info(`Fetching cross-chain guard programs for user: ${userAddress}`);
31
+ const crossChainGuardPrograms = await rpc.getProgramAccounts(programAccountAddress, programAccountsConfig).send();
32
+ logger.info(`Found ${crossChainGuardPrograms.length} cross-chain guard programs`);
33
+ // const singleChainGuardPrograms = await rpc.getProgramAccounts(address(singleChainGuardAddress), programAccountsConfig).send();
34
+
35
+ // const crossChainCodec = getOrderCodec();
36
+ // const singleChainCodec = getLimitOrderCodec();
37
+ // const base64Encoder = getBase64Encoder();
38
+
39
+ const crossChainGuardProgramsWithOrders = crossChainGuardPrograms.map(({ pubkey, account }) => {
40
+ logger.info(`Account data: ${account} and pubkey: ${pubkey}`);
41
+
42
+ return {
43
+ pubkey,
44
+ };
45
+ });
46
+
47
+ return {
48
+ crossChainGuardPrograms: crossChainGuardProgramsWithOrders,
49
+ };
50
+ }
@@ -262,4 +262,4 @@ export async function getSolanaCrossChainOrderInstructions(
262
262
  orderAddress: orderSigner.address,
263
263
  txBytes: Uint8Array.from(txBytes),
264
264
  };
265
- }
265
+ }
@@ -22,12 +22,19 @@ import { BaseSDK } from '../sdk.js';
22
22
  import { createSolanaClient, type SolanaClient } from './client.js';
23
23
  import { cancelCrossChainOrderInstructions, cancelSingleChainOrderInstructions } from './cancel-order.js';
24
24
  import type { CrossChainOrder } from '../orders/cross-chain.js';
25
- import type { CrossChainOrderPrepared, SingleChainOrderPrepared } from '../../types/intent.js';
25
+ import type {
26
+ CrossChainOrderPrepared,
27
+ DcaSingleChainOrderPrepared,
28
+ SingleChainOrderPrepared,
29
+ } from '../../types/intent.js';
26
30
  import { getSolanaCrossChainOrderInstructions, getSolanaSingleChainOrderInstructions } from './order-instructions.js';
27
31
  import type { SingleChainOrder } from '../orders/single-chain.js';
28
32
  import { fetchJWTToken, fetchSiweMessage } from '../../auth/siwe.js';
29
33
  import { ChainID } from '../../chains.js';
30
34
  import { bytesToHex } from 'viem';
35
+ import type { DcaSingleChainOrder } from '../orders/dca-single-chain.js';
36
+ import { getSolanaDcaSingleChainOrderInstructions } from './dca/create-order.js';
37
+ import { cancelDcaSingleChainOrderInstructions } from './dca/cancel-order.js';
31
38
 
32
39
  /**
33
40
  * Solana-specific SDK implementation
@@ -224,7 +231,7 @@ export class SolanaSDK extends BaseSDK {
224
231
  };
225
232
  }
226
233
 
227
- protected async prepareSingleChainOrder(order: SingleChainOrder): Promise<SingleChainOrderPrepared> {
234
+ protected override async prepareSingleChainOrder(order: SingleChainOrder): Promise<SingleChainOrderPrepared> {
228
235
  const signerKeyPair = await this.getUserCryptoKeypair();
229
236
 
230
237
  const { orderAddress, txBytes, secretNumber } = await getSolanaSingleChainOrderInstructions(order);
@@ -237,6 +244,62 @@ export class SolanaSDK extends BaseSDK {
237
244
 
238
245
  const encodedTransaction = getBase64EncodedWireTransaction(signedTx);
239
246
 
247
+ await this.client.rpc
248
+ .sendTransaction(encodedTransaction, { preflightCommitment: this.config.commitment, encoding: 'base64' })
249
+ .send();
250
+
251
+ return {
252
+ order,
253
+ preparedData: {
254
+ orderPubkey: orderAddress,
255
+ secretNumber,
256
+ },
257
+ };
258
+ }
259
+ public async cancelDcaSingleChainOrder(orderId: string): Promise<string> {
260
+ const instructions = await cancelDcaSingleChainOrderInstructions(orderId, { rpcUrl: this.config.rpcProviderUrl });
261
+ const signer = await this.getUserSigner();
262
+ const signerKeyPair = await this.getUserCryptoKeypair();
263
+
264
+ const noopSigner = createNoopSigner(signer.address);
265
+
266
+ const { value: latestBlockhash } = await this.client.rpc
267
+ .getLatestBlockhash({ commitment: this.config.commitment })
268
+ .send();
269
+
270
+ const transactionMessage = pipe(
271
+ createTransactionMessage({ version: 0 }),
272
+ (tx) => setTransactionMessageFeePayerSigner(noopSigner, tx),
273
+ (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
274
+ (tx) => appendTransactionMessageInstructions(instructions, tx),
275
+ );
276
+
277
+ const myTx = compileTransaction(transactionMessage);
278
+
279
+ const signature = await signTransaction([signerKeyPair], myTx);
280
+
281
+ await this.client.sendAndConfirmTransaction(signature, {
282
+ commitment: this.config.commitment,
283
+ });
284
+
285
+ return orderId;
286
+ }
287
+
288
+ protected override async prepareDcaSingleChainOrder(
289
+ order: DcaSingleChainOrder,
290
+ ): Promise<DcaSingleChainOrderPrepared> {
291
+ const signerKeyPair = await this.getUserCryptoKeypair();
292
+
293
+ const { orderAddress, txBytes, secretNumber } = await getSolanaDcaSingleChainOrderInstructions(order);
294
+
295
+ const transactionCodec = getTransactionCodec();
296
+
297
+ const tx = transactionCodec.decode(txBytes);
298
+
299
+ const signedTx = await partiallySignTransaction([signerKeyPair], tx);
300
+
301
+ const encodedTransaction = getBase64EncodedWireTransaction(signedTx);
302
+
240
303
  await this.client.rpc
241
304
  .sendTransaction(encodedTransaction, { preflightCommitment: this.config.commitment, encoding: 'base64' })
242
305
  .send();
@@ -2,8 +2,9 @@ import BN from 'bn.js';
2
2
  import type { SingleChainOrder } from '../orders/single-chain.js';
3
3
  import { PublicKey } from '@solana/web3.js';
4
4
  import sha3 from 'js-sha3';
5
+ import type { DcaSingleChainOrder } from '../orders/dca-single-chain.js';
5
6
 
6
- export function genSecretHashAndNumber(order: SingleChainOrder): {
7
+ export function genSecretHashAndNumber(order: SingleChainOrder | DcaSingleChainOrder): {
7
8
  secretHash: number[];
8
9
  secretNumber: string;
9
10
  } {
@@ -27,4 +27,8 @@ export class SolanaValidator extends BaseValidator {
27
27
  // No chain-specific validation implemented for now for Solana
28
28
  return;
29
29
  }
30
+
31
+ override async validateDcaSingleChainOrderFeasability(): Promise<void> {
32
+ return Promise.resolve();
33
+ }
30
34
  }
@@ -5,7 +5,7 @@ import { BaseSDK } from '../sdk.js';
5
5
  import { createSuiClient } from './client.js';
6
6
  import { getSuiOrderTransaction } from './order-transaction.js';
7
7
  import { getSuiCancelCrossChainOrder } from './cancel.js';
8
- import type { CrossChainOrderPrepared, SingleChainOrderPrepared } from '../../types/intent.js';
8
+ import type { CrossChainOrderPrepared } from '../../types/intent.js';
9
9
  import type { CrossChainOrder } from '../orders/cross-chain.js';
10
10
  import { fetchJWTToken, fetchSiweMessage } from '../../auth/siwe.js';
11
11
  import { ChainID } from '../../chains.js';
@@ -57,10 +57,6 @@ export class SuiSDK extends BaseSDK {
57
57
  return Ed25519Keypair.fromSecretKey(this.config.privateKey);
58
58
  }
59
59
 
60
- protected override prepareSingleChainOrder(): Promise<SingleChainOrderPrepared> {
61
- throw new Error('Single-chain orders are not supported on Sui');
62
- }
63
-
64
60
  public async authenticate(token?: string): Promise<string> {
65
61
  const wallet = await this.getUserAddress();
66
62
 
@@ -103,7 +99,7 @@ export class SuiSDK extends BaseSDK {
103
99
  * @returns Promise resolving to a prepared order with Sui-specific data
104
100
  * @protected
105
101
  */
106
- protected async prepareCrossChainOrder(order: CrossChainOrder): Promise<CrossChainOrderPrepared> {
102
+ protected override async prepareCrossChainOrder(order: CrossChainOrder): Promise<CrossChainOrderPrepared> {
107
103
  const signer = this.getKeyPair();
108
104
 
109
105
  const transaction = await getSuiOrderTransaction(order);
@@ -1,6 +1,7 @@
1
1
  import { isValidSuiAddress, normalizeSuiAddress } from '@mysten/sui/utils';
2
2
  import { MAX_UINT_64 } from '../../constants.js';
3
3
  import { BaseValidator } from '../../utils/base-validator.js';
4
+ import { ValidationError } from '../../errors/index.js';
4
5
 
5
6
  const SUI_TOKEN_ADDRESS_REGEX = /^0x[a-fA-F0-9]{64}::\w+::\w+$/;
6
7
 
@@ -33,4 +34,8 @@ export class SuiValidator extends BaseValidator {
33
34
  override validateSingleChainOrderFeasability(): Promise<void> {
34
35
  return Promise.resolve();
35
36
  }
37
+
38
+ override validateDcaSingleChainOrderFeasability(): Promise<void> {
39
+ throw new ValidationError('DCA orders are not supported on Sui');
40
+ }
36
41
  }
package/src/index.ts CHANGED
@@ -14,7 +14,15 @@ export { fetchUserOrders } from './core/orders/api/fetch.js';
14
14
  export { AuctioneerAPI } from './core/orders/api/index.js';
15
15
  export { type FetchJWTParams, type FetchSiweMessageParams, fetchJWTToken, fetchSiweMessage } from './auth/siwe.js';
16
16
  export { ValidationError } from './errors/index.js';
17
- export { type ApiCrossChainOrder, type ApiResponse, type ApiSingleChainOrder, type ApiUserOrders, type ChainOrderStatus, isErrorApiResponse, isSuccessApiResponse } from './types/api.js';
17
+ export {
18
+ type ApiCrossChainOrder,
19
+ type ApiResponse,
20
+ type ApiSingleChainOrder,
21
+ type ApiUserOrders,
22
+ type ChainOrderStatus,
23
+ isErrorApiResponse,
24
+ isSuccessApiResponse,
25
+ } from './types/api.js';
18
26
  export { calculateAmounts, getCoinFromResponse, getTokensData } from './utils/defillama.js';
19
27
  export type { DefiLlamaCoinData, DefiLlamaTokensResponse } from './utils/defillama.js';
20
28
  export {
@@ -24,8 +32,11 @@ export {
24
32
  type CancelCrossChainOrderParams,
25
33
  getInvalidateNoncesRawData,
26
34
  } from './core/evm/cancel-order.js';
35
+ export { cancelDcaSingleChainOrderInstructions } from './core/solana/dca/cancel-order.js';
27
36
  export { getEVMCrossChainOrderTypedData, getEVMSingleChainOrderTypedData } from './core/evm/order-signature.js';
28
37
 
38
+ export { getSolanaOrdersWithLockedFunds } from './core/solana/inspect.js';
39
+
29
40
  export {
30
41
  getSolanaCrossChainOrderInstructions,
31
42
  getSolanaSingleChainOrderInstructions,
package/src/types/api.ts CHANGED
@@ -75,4 +75,4 @@ export function isErrorApiResponse<T extends ValidResponseData>(
75
75
  response: ApiResponse<T>,
76
76
  ): response is ApiResponse<T> & { success: false; error: unknown } {
77
77
  return !response.success;
78
- }
78
+ }
@@ -2,6 +2,7 @@ import type { SupportedChain } from '../chains.js';
2
2
  import type { CrossChainOrder } from '../core/orders/cross-chain.js';
3
3
  import type { ExtraTransfer } from '../core/orders/common.js';
4
4
  import type { SingleChainOrder } from '../core/orders/single-chain.js';
5
+ import type { DcaSingleChainOrder } from '../core/orders/dca-single-chain.js';
5
6
 
6
7
  /**
7
8
  * Details required to execute the order on the destination chain
@@ -120,3 +121,29 @@ export type SingleChainOrderPrepared = {
120
121
  order: SingleChainOrder;
121
122
  preparedData: SingleChainPreparedData;
122
123
  };
124
+
125
+ export type DcaSingleChainUserIntentRequest = {
126
+ genericData: DcaSingleChainOrder;
127
+ chainSpecificData: {
128
+ EVM?: DcaSingleChainEVMPreparedData;
129
+ Solana?: DcaSingleChainSolanaPreparedData;
130
+ Sui?: never; // DCA not supported on Sui
131
+ };
132
+ };
133
+
134
+ export type DcaSingleChainEVMPreparedData = {
135
+ nonce: string;
136
+ signature: string | Hash;
137
+ };
138
+
139
+ export type DcaSingleChainSolanaPreparedData = {
140
+ secretNumber: string;
141
+ orderPubkey: string;
142
+ };
143
+
144
+ export type DcaSingleChainPreparedData = DcaSingleChainEVMPreparedData | DcaSingleChainSolanaPreparedData;
145
+
146
+ export type DcaSingleChainOrderPrepared = {
147
+ order: DcaSingleChainOrder;
148
+ preparedData: DcaSingleChainPreparedData;
149
+ };
@@ -1,4 +1,5 @@
1
1
  import type { CreateCrossChainOrderParams } from '../core/orders/cross-chain.js';
2
+ import type { CreateDcaSingleChainOrderParams } from '../core/orders/dca-single-chain.js';
2
3
  import type { CreateSingleChainOrderParams } from '../core/orders/single-chain.js';
3
4
  import { ValidationError } from '../errors/index.js';
4
5
  import type { IChainValidator } from './order-validator.js';
@@ -59,6 +60,45 @@ export abstract class BaseValidator implements IChainValidator {
59
60
  }
60
61
  }
61
62
 
63
+ abstract validateDcaSingleChainOrderFeasability(
64
+ order: CreateDcaSingleChainOrderParams & { user: string },
65
+ ): Promise<void>;
66
+
67
+ async validateDcaSingleChainOrder(order: CreateDcaSingleChainOrderParams & { user: string }): Promise<void> {
68
+ this.validateTokenAddress(order.tokenIn);
69
+ this.validateTokenAddress(order.tokenOut);
70
+ this.validateAmount(order.amountInPerInterval);
71
+ this.validateAmount(order.amountOutMin ?? 1n);
72
+ this.validateAddress(order.destinationAddress);
73
+
74
+ // Validate DCA-specific parameters
75
+ if (order.totalIntervals <= 0) {
76
+ throw new ValidationError('Total intervals must be greater than 0');
77
+ }
78
+
79
+ if (order.intervalDuration <= 0) {
80
+ throw new ValidationError('Interval duration must be greater than 0');
81
+ }
82
+
83
+ if (order.startTime < 0) {
84
+ throw new ValidationError('Start time must be non-negative');
85
+ }
86
+
87
+ // Validate total amount doesn't overflow
88
+ const totalAmount = order.amountInPerInterval * BigInt(order.totalIntervals);
89
+ this.validateAmount(totalAmount);
90
+
91
+ if (order.extraTransfers) {
92
+ for (const extraTransfer of order.extraTransfers) {
93
+ this.validateAddress(extraTransfer.receiver);
94
+ this.validateTokenAddress(extraTransfer.token);
95
+ this.validateAmount(extraTransfer.amount);
96
+ }
97
+ }
98
+
99
+ await this.validateDcaSingleChainOrderFeasability(order);
100
+ }
101
+
62
102
  /**
63
103
  * Helper methods that throw specific validation errors
64
104
  */
@@ -26,6 +26,7 @@ export interface IChainValidator extends IAddressValidator, ITokenValidator, IAm
26
26
  validateSourceChain(order: CreateCrossChainOrderParams & { user: string }): Promise<void>;
27
27
  validateDestinationChain(order: CreateCrossChainOrderParams): void;
28
28
  validateSingleChainOrder(order: CreateSingleChainOrderParams & { user: string }): Promise<void>;
29
+ validateDcaSingleChainOrder(order: CreateDcaSingleChainOrderParams & { user: string }): Promise<void>;
29
30
  }
30
31
 
31
32
  /**
@@ -99,3 +100,40 @@ export class SingleChainOrderValidator {
99
100
  chainValidator.validateSingleChainOrder(order);
100
101
  }
101
102
  }
103
+
104
+ import type { CreateDcaSingleChainOrderParams } from '../core/orders/dca-single-chain.js';
105
+
106
+ export interface IDcaValidator {
107
+ validateDcaSingleChainOrder(order: CreateDcaSingleChainOrderParams & { user: string }): Promise<void>;
108
+ }
109
+
110
+ export class DcaSingleChainOrderValidator {
111
+ private readonly commonValidator = new CommonValidator();
112
+
113
+ async validateOrder(order: CreateDcaSingleChainOrderParams & { user: string }): Promise<void> {
114
+ this.commonValidator.validateDeadline(order.deadline);
115
+
116
+ // Validate start time is in the future or current time
117
+ if (order.startTime < Math.floor(Date.now() / 1000)) {
118
+ throw new ValidationError('Start time must be in the future or current time');
119
+ }
120
+
121
+ // Validate intervals
122
+ if (order.totalIntervals <= 0) {
123
+ throw new ValidationError('Total intervals must be greater than 0');
124
+ }
125
+
126
+ if (order.intervalDuration <= 0) {
127
+ throw new ValidationError('Interval duration must be greater than 0');
128
+ }
129
+
130
+ // Validate that the order will complete before deadline
131
+ const estimatedCompletionTime = order.startTime + order.totalIntervals * order.intervalDuration;
132
+ if (estimatedCompletionTime > order.deadline) {
133
+ throw new ValidationError('Order would complete after deadline');
134
+ }
135
+
136
+ const chainValidator = ValidatorFactory.getValidatorForChain(order.chainId);
137
+ await chainValidator.validateDcaSingleChainOrder(order);
138
+ }
139
+ }
@@ -18,8 +18,8 @@ const LIQUID_SWAP_API_URL = 'https://api.liqd.ag';
18
18
 
19
19
  export class LiquidSwapQuoteProvider {
20
20
  public async getQuote(liquidSwapParams: LiquidSwapQuoteParams): Promise<LiquidSwapQuoteResponse> {
21
- const params = {...liquidSwapParams};
22
-
21
+ const params = { ...liquidSwapParams };
22
+
23
23
  if (isNativeEvmToken(params.tokenOut)) {
24
24
  params.tokenOut = WRAPPED_ETH_ADDRESSES[ChainID.Hyperliquid];
25
25
  }