@shogun-sdk/intents-sdk 1.1.0 → 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.
- package/dist/esm/constants.js +24 -8
- package/dist/esm/constants.js.map +1 -1
- package/dist/esm/core/evm/intent-provider.js +55 -2
- package/dist/esm/core/evm/intent-provider.js.map +1 -1
- package/dist/esm/core/evm/order-signature.js +12 -1
- package/dist/esm/core/evm/order-signature.js.map +1 -1
- package/dist/esm/core/evm/permit2.js +24 -1
- package/dist/esm/core/evm/permit2.js.map +1 -1
- package/dist/esm/core/evm/sdk.js +5 -18
- package/dist/esm/core/evm/sdk.js.map +1 -1
- package/dist/esm/core/evm/validator.js +21 -0
- package/dist/esm/core/evm/validator.js.map +1 -1
- package/dist/esm/core/orders/api/index.js +31 -0
- package/dist/esm/core/orders/api/index.js.map +1 -0
- package/dist/esm/core/orders/cross-chain.js +3 -0
- package/dist/esm/core/orders/cross-chain.js.map +1 -1
- package/dist/esm/core/orders/dca-single-chain.js +169 -0
- package/dist/esm/core/orders/dca-single-chain.js.map +1 -0
- package/dist/esm/core/orders/single-chain.js +4 -0
- package/dist/esm/core/orders/single-chain.js.map +1 -1
- package/dist/esm/core/sdk.js +55 -81
- package/dist/esm/core/sdk.js.map +1 -1
- package/dist/esm/core/solana/dca/cancel-order.js +61 -0
- package/dist/esm/core/solana/dca/cancel-order.js.map +1 -0
- package/dist/esm/core/solana/dca/create-order.js +82 -0
- package/dist/esm/core/solana/dca/create-order.js.map +1 -0
- package/dist/esm/core/solana/inspect.js +43 -0
- package/dist/esm/core/solana/inspect.js.map +1 -0
- package/dist/esm/core/solana/sdk.js +36 -18
- package/dist/esm/core/solana/sdk.js.map +1 -1
- package/dist/esm/core/solana/utils.js.map +1 -1
- package/dist/esm/core/solana/validator.js +3 -0
- package/dist/esm/core/solana/validator.js.map +1 -1
- package/dist/esm/core/sui/sdk.js +0 -21
- package/dist/esm/core/sui/sdk.js.map +1 -1
- package/dist/esm/core/sui/validator.js +4 -0
- package/dist/esm/core/sui/validator.js.map +1 -1
- package/dist/esm/index.js +4 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/utils/base-validator.js +28 -0
- package/dist/esm/utils/base-validator.js.map +1 -1
- package/dist/esm/utils/order-validator.js +31 -0
- package/dist/esm/utils/order-validator.js.map +1 -1
- package/dist/esm/utils/quote/liquidswap.js.map +1 -1
- package/dist/types/constants.d.ts +10 -7
- package/dist/types/constants.d.ts.map +1 -1
- package/dist/types/core/evm/intent-provider.d.ts +5 -2
- package/dist/types/core/evm/intent-provider.d.ts.map +1 -1
- package/dist/types/core/evm/order-signature.d.ts +5 -0
- package/dist/types/core/evm/order-signature.d.ts.map +1 -1
- package/dist/types/core/evm/permit2.d.ts +90 -0
- package/dist/types/core/evm/permit2.d.ts.map +1 -1
- package/dist/types/core/evm/sdk.d.ts +3 -5
- package/dist/types/core/evm/sdk.d.ts.map +1 -1
- package/dist/types/core/evm/validator.d.ts +4 -0
- package/dist/types/core/evm/validator.d.ts.map +1 -1
- package/dist/types/core/orders/api/index.d.ts +8 -0
- package/dist/types/core/orders/api/index.d.ts.map +1 -0
- package/dist/types/core/orders/cross-chain.d.ts.map +1 -1
- package/dist/types/core/orders/dca-single-chain.d.ts +47 -0
- package/dist/types/core/orders/dca-single-chain.d.ts.map +1 -0
- package/dist/types/core/orders/single-chain.d.ts.map +1 -1
- package/dist/types/core/sdk.d.ts +16 -12
- package/dist/types/core/sdk.d.ts.map +1 -1
- package/dist/types/core/solana/dca/cancel-order.d.ts +5 -0
- package/dist/types/core/solana/dca/cancel-order.d.ts.map +1 -0
- package/dist/types/core/solana/dca/create-order.d.ts +8 -0
- package/dist/types/core/solana/dca/create-order.d.ts.map +1 -0
- package/dist/types/core/solana/inspect.d.ts +14 -0
- package/dist/types/core/solana/inspect.d.ts.map +1 -0
- package/dist/types/core/solana/sdk.d.ts +4 -5
- package/dist/types/core/solana/sdk.d.ts.map +1 -1
- package/dist/types/core/solana/utils.d.ts +2 -1
- package/dist/types/core/solana/utils.d.ts.map +1 -1
- package/dist/types/core/solana/validator.d.ts +1 -0
- package/dist/types/core/solana/validator.d.ts.map +1 -1
- package/dist/types/core/sui/sdk.d.ts +1 -6
- package/dist/types/core/sui/sdk.d.ts.map +1 -1
- package/dist/types/core/sui/validator.d.ts +1 -0
- package/dist/types/core/sui/validator.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types/intent.d.ts +22 -0
- package/dist/types/types/intent.d.ts.map +1 -1
- package/dist/types/utils/base-validator.d.ts +7 -0
- package/dist/types/utils/base-validator.d.ts.map +1 -1
- package/dist/types/utils/order-validator.d.ts +15 -0
- package/dist/types/utils/order-validator.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/auth/siwe.ts +1 -1
- package/src/constants.ts +72 -39
- package/src/core/evm/connectors/hyperevm.ts +1 -1
- package/src/core/evm/intent-provider.ts +88 -4
- package/src/core/evm/order-signature.ts +23 -1
- package/src/core/evm/permit2.ts +47 -1
- package/src/core/evm/sdk.ts +15 -21
- package/src/core/evm/validator.ts +32 -0
- package/src/core/orders/api/index.ts +33 -0
- package/src/core/orders/cross-chain.ts +4 -0
- package/src/core/orders/dca-single-chain.ts +143 -0
- package/src/core/orders/single-chain.ts +6 -0
- package/src/core/sdk.ts +73 -102
- package/src/core/solana/cancel-order.ts +1 -1
- package/src/core/solana/dca/cancel-order.ts +91 -0
- package/src/core/solana/dca/create-order.ts +142 -0
- package/src/core/solana/inspect.ts +50 -0
- package/src/core/solana/order-instructions.ts +1 -1
- package/src/core/solana/sdk.ts +65 -21
- package/src/core/solana/utils.ts +2 -1
- package/src/core/solana/validator.ts +4 -0
- package/src/core/sui/sdk.ts +2 -24
- package/src/core/sui/validator.ts +5 -0
- package/src/index.ts +13 -1
- package/src/types/api.ts +1 -1
- package/src/types/intent.ts +27 -0
- package/src/utils/base-validator.ts +40 -0
- package/src/utils/order-validator.ts +38 -0
- package/src/utils/quote/liquidswap.ts +2 -2
|
@@ -63,8 +63,14 @@ export class SingleChainOrder {
|
|
|
63
63
|
user: input.user,
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
+
if (isEvmChain(order.chainId)) {
|
|
67
|
+
return order;
|
|
68
|
+
}
|
|
69
|
+
|
|
66
70
|
const preparedRandomData = order.getRandomPreparedData();
|
|
67
71
|
const intentRequest = order.toIntentRequest(preparedRandomData);
|
|
72
|
+
|
|
73
|
+
// Just validate for non EVM
|
|
68
74
|
await BaseSDK.validateSingleChainOrder(intentRequest);
|
|
69
75
|
|
|
70
76
|
return order;
|
package/src/core/sdk.ts
CHANGED
|
@@ -1,123 +1,72 @@
|
|
|
1
1
|
import { AUCTIONEER_URL } from '../constants.js';
|
|
2
2
|
import { NetworkError } from '../errors/index.js';
|
|
3
|
-
import type { ApiResponse
|
|
3
|
+
import type { ApiResponse } from '../types/api.js';
|
|
4
4
|
import type {
|
|
5
5
|
CrossChainOrderPrepared,
|
|
6
6
|
CrossChainUserIntentRequest,
|
|
7
|
+
DcaSingleChainOrderPrepared,
|
|
8
|
+
DcaSingleChainUserIntentRequest,
|
|
7
9
|
SingleChainOrderPrepared,
|
|
8
10
|
SingleChainUserIntentRequest,
|
|
9
11
|
} from '../types/intent.js';
|
|
10
12
|
import { Parsers } from '../utils/parsers.js';
|
|
11
13
|
import { CrossChainOrder, type CreateCrossChainOrderParams } from './orders/cross-chain.js';
|
|
14
|
+
import { DcaSingleChainOrder, type CreateDcaSingleChainOrderParams } from './orders/dca-single-chain.js';
|
|
12
15
|
import { SingleChainOrder, type CreateSingleChainOrderParams } from './orders/single-chain.js';
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
18
|
* Base SDK providing common functionality for all blockchain implementations
|
|
16
|
-
*
|
|
17
|
-
* This abstract class serves as the foundation for chain-specific SDK implementations
|
|
18
|
-
* (EVM, Solana, Sui), providing shared functionality for creating and sending orders
|
|
19
|
-
* across different blockchains.
|
|
20
19
|
*/
|
|
21
20
|
export abstract class BaseSDK {
|
|
22
|
-
public abstract getOrders(): Promise<ApiUserOrders>;
|
|
23
21
|
public abstract getUserAddress(): Promise<string>;
|
|
24
|
-
protected abstract prepareCrossChainOrder(order: CrossChainOrder): Promise<CrossChainOrderPrepared>;
|
|
25
|
-
protected abstract prepareSingleChainOrder(order: SingleChainOrder): Promise<SingleChainOrderPrepared>;
|
|
26
|
-
|
|
27
|
-
public async createSingleChainOrder(params: CreateSingleChainOrderParams): Promise<SingleChainOrderPrepared> {
|
|
28
|
-
const userAddress = await this.getUserAddress();
|
|
29
|
-
|
|
30
|
-
const order = await SingleChainOrder.create({
|
|
31
|
-
...params,
|
|
32
|
-
user: userAddress,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
return this.prepareSingleChainOrder(order);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
public async createCrossChainOrder(params: CreateCrossChainOrderParams): Promise<CrossChainOrderPrepared> {
|
|
39
|
-
const userAddress = await this.getUserAddress();
|
|
40
|
-
|
|
41
|
-
const order = await CrossChainOrder.create({
|
|
42
|
-
...params,
|
|
43
|
-
user: userAddress,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
return this.prepareCrossChainOrder(order);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
public async createAndSendSingleChainOrder(params: CreateSingleChainOrderParams): Promise<ApiResponse> {
|
|
50
|
-
const preparedOrder = await this.createSingleChainOrder(params);
|
|
51
|
-
return BaseSDK.sendSingleChainOrder(preparedOrder);
|
|
52
|
-
}
|
|
53
22
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
23
|
+
protected abstract prepareCrossChainOrder(order: CrossChainOrder): Promise<CrossChainOrderPrepared>;
|
|
24
|
+
protected prepareSingleChainOrder?(order: SingleChainOrder): Promise<SingleChainOrderPrepared>;
|
|
25
|
+
protected prepareDcaSingleChainOrder?(order: DcaSingleChainOrder): Promise<DcaSingleChainOrderPrepared>;
|
|
57
26
|
|
|
58
|
-
|
|
27
|
+
// Generic HTTP request handler
|
|
28
|
+
private static async makeRequest(url: string, body: string): Promise<ApiResponse> {
|
|
59
29
|
const response = await fetch(url, {
|
|
60
30
|
method: 'POST',
|
|
61
|
-
headers: {
|
|
62
|
-
'Content-Type': 'application/json',
|
|
63
|
-
},
|
|
31
|
+
headers: { 'Content-Type': 'application/json' },
|
|
64
32
|
body,
|
|
65
33
|
});
|
|
66
34
|
|
|
67
35
|
if (!response.ok) {
|
|
68
36
|
const errorJson: ApiResponse = await response.json();
|
|
69
|
-
|
|
37
|
+
const mainError = errorJson.error;
|
|
70
38
|
const extraErrorData = errorJson.extra_error_data;
|
|
71
|
-
|
|
39
|
+
|
|
40
|
+
const errorMessage = mainError
|
|
41
|
+
? `${mainError}. Extra error data: ${extraErrorData}`
|
|
42
|
+
: `Server error ${extraErrorData}`;
|
|
43
|
+
|
|
44
|
+
throw new NetworkError(errorMessage);
|
|
72
45
|
}
|
|
73
46
|
|
|
74
47
|
return response.json();
|
|
75
48
|
}
|
|
76
49
|
|
|
77
|
-
|
|
50
|
+
private static async validateOrder<T>(intentRequest: T, endpoint: string): Promise<void> {
|
|
78
51
|
const body = JSON.stringify(intentRequest, Parsers.bigIntReplacer);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const response = await fetch(url, {
|
|
82
|
-
method: 'POST',
|
|
83
|
-
headers: {
|
|
84
|
-
'Content-Type': 'application/json',
|
|
85
|
-
},
|
|
86
|
-
body,
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
if (!response.ok) {
|
|
90
|
-
const errorJson: ApiResponse = await response.json();
|
|
91
|
-
|
|
92
|
-
const mainError = errorJson.error;
|
|
93
|
-
const extraErrorData = errorJson.extra_error_data;
|
|
94
|
-
throw new NetworkError(`Validation error: ${mainError}. Extra error data: ${extraErrorData}`);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return;
|
|
52
|
+
const url = `${AUCTIONEER_URL}${endpoint}`;
|
|
53
|
+
await BaseSDK.makeRequest(url, body);
|
|
98
54
|
}
|
|
99
55
|
|
|
100
|
-
|
|
56
|
+
private static async sendOrder<T extends { toIntentRequest(preparedData: any): any }>(
|
|
57
|
+
preparedOrder: { order: T; preparedData: any },
|
|
58
|
+
endpoint: string,
|
|
59
|
+
): Promise<ApiResponse> {
|
|
60
|
+
const intentRequest = preparedOrder.order.toIntentRequest(preparedOrder.preparedData);
|
|
101
61
|
const body = JSON.stringify(intentRequest, Parsers.bigIntReplacer);
|
|
62
|
+
const url = `${AUCTIONEER_URL}${endpoint}`;
|
|
63
|
+
return BaseSDK.makeRequest(url, body);
|
|
64
|
+
}
|
|
102
65
|
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
'Content-Type': 'application/json',
|
|
108
|
-
},
|
|
109
|
-
body,
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
if (!response.ok) {
|
|
113
|
-
const errorJson: ApiResponse = await response.json();
|
|
114
|
-
|
|
115
|
-
const mainError = errorJson.error;
|
|
116
|
-
const extraErrorData = errorJson.extra_error_data;
|
|
117
|
-
throw new NetworkError(`Validation error: ${mainError}. Extra error data: ${extraErrorData}`);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return;
|
|
66
|
+
public async createCrossChainOrder(params: CreateCrossChainOrderParams): Promise<CrossChainOrderPrepared> {
|
|
67
|
+
const userAddress = await this.getUserAddress();
|
|
68
|
+
const order = await CrossChainOrder.create({ ...params, user: userAddress });
|
|
69
|
+
return this.prepareCrossChainOrder!(order);
|
|
121
70
|
}
|
|
122
71
|
|
|
123
72
|
public async createAndSendCrossChainOrder(params: CreateCrossChainOrderParams): Promise<ApiResponse> {
|
|
@@ -126,28 +75,50 @@ export abstract class BaseSDK {
|
|
|
126
75
|
}
|
|
127
76
|
|
|
128
77
|
public static async sendCrossChainOrder(preparedOrder: CrossChainOrderPrepared): Promise<ApiResponse> {
|
|
129
|
-
|
|
130
|
-
|
|
78
|
+
return BaseSDK.sendOrder(preparedOrder, '/user_intent/cross_chain/limit_order');
|
|
79
|
+
}
|
|
131
80
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
headers: {
|
|
136
|
-
'Content-Type': 'application/json',
|
|
137
|
-
},
|
|
138
|
-
body,
|
|
139
|
-
});
|
|
81
|
+
public static async validateCrossChainOrder(intentRequest: CrossChainUserIntentRequest): Promise<void> {
|
|
82
|
+
return BaseSDK.validateOrder(intentRequest, '/validate_intent/cross_chain/limit_order');
|
|
83
|
+
}
|
|
140
84
|
|
|
141
|
-
|
|
142
|
-
|
|
85
|
+
public async createSingleChainOrder(params: CreateSingleChainOrderParams): Promise<SingleChainOrderPrepared> {
|
|
86
|
+
const userAddress = await this.getUserAddress();
|
|
87
|
+
const order = await SingleChainOrder.create({ ...params, user: userAddress });
|
|
88
|
+
return this.prepareSingleChainOrder!(order);
|
|
89
|
+
}
|
|
143
90
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
);
|
|
149
|
-
}
|
|
91
|
+
public async createAndSendSingleChainOrder(params: CreateSingleChainOrderParams): Promise<ApiResponse> {
|
|
92
|
+
const preparedOrder = await this.createSingleChainOrder(params);
|
|
93
|
+
return BaseSDK.sendSingleChainOrder(preparedOrder);
|
|
94
|
+
}
|
|
150
95
|
|
|
151
|
-
|
|
96
|
+
public static async sendSingleChainOrder(preparedOrder: SingleChainOrderPrepared): Promise<ApiResponse> {
|
|
97
|
+
return BaseSDK.sendOrder(preparedOrder, '/user_intent/single_chain/limit_order');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public static async validateSingleChainOrder(intentRequest: SingleChainUserIntentRequest): Promise<void> {
|
|
101
|
+
return BaseSDK.validateOrder(intentRequest, '/validate_intent/single_chain/limit_order');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public async createDcaSingleChainOrder(
|
|
105
|
+
params: CreateDcaSingleChainOrderParams,
|
|
106
|
+
): Promise<DcaSingleChainOrderPrepared> {
|
|
107
|
+
const userAddress = await this.getUserAddress();
|
|
108
|
+
const order = await DcaSingleChainOrder.create({ ...params, user: userAddress });
|
|
109
|
+
return this.prepareDcaSingleChainOrder!(order);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public async createAndSendDcaSingleChainOrder(params: CreateDcaSingleChainOrderParams): Promise<ApiResponse> {
|
|
113
|
+
const preparedOrder = await this.createDcaSingleChainOrder(params);
|
|
114
|
+
return BaseSDK.sendDcaSingleChainOrder(preparedOrder);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public static async sendDcaSingleChainOrder(preparedOrder: DcaSingleChainOrderPrepared): Promise<ApiResponse> {
|
|
118
|
+
return BaseSDK.sendOrder(preparedOrder, '/user_intent/single_chain/dca_order');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public static async validateDcaSingleChainOrder(intentRequest: DcaSingleChainUserIntentRequest): Promise<void> {
|
|
122
|
+
return BaseSDK.validateOrder(intentRequest, '/validate_intent/single_chain/dca_order');
|
|
152
123
|
}
|
|
153
124
|
}
|
|
@@ -164,7 +164,7 @@ export async function cancelCrossChainOrderInstructions(
|
|
|
164
164
|
const addressEncoder = getAddressEncoder();
|
|
165
165
|
|
|
166
166
|
const isRecoveringTokenIn = chainOrder.data.lockedStablecoins === 0n;
|
|
167
|
-
const recoverTokenMint = isRecoveringTokenIn ? chainOrder.data.tokenInMint : address(SOLANA_MINT_TOKEN.mint);
|
|
167
|
+
const recoverTokenMint = isRecoveringTokenIn ? chainOrder.data.tokenInMint : address(SOLANA_MINT_TOKEN.mint);
|
|
168
168
|
|
|
169
169
|
const recoverTokenMintProgram = await fetchMint(rpc, recoverTokenMint);
|
|
170
170
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {
|
|
2
|
+
address,
|
|
3
|
+
createNoopSigner,
|
|
4
|
+
createSolanaRpc,
|
|
5
|
+
fetchEncodedAccount,
|
|
6
|
+
getAddressEncoder,
|
|
7
|
+
getProgramDerivedAddress,
|
|
8
|
+
type Address,
|
|
9
|
+
type IInstruction,
|
|
10
|
+
} from '@solana/kit';
|
|
11
|
+
import { getDefaultSolanaRPC } from '../client.js';
|
|
12
|
+
import { fetchMaybeDcaOrder, getCancelDcaOrderInstruction } from '../generated/single-chain/index.js';
|
|
13
|
+
import {
|
|
14
|
+
ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
|
|
15
|
+
fetchMint,
|
|
16
|
+
getCreateAssociatedTokenInstructionAsync,
|
|
17
|
+
} from '@solana-program/token';
|
|
18
|
+
import { SINGLE_CHAIN_GUARD_ADDRESSES } from '../../../constants.js';
|
|
19
|
+
import { ChainID } from '../../../chains.js';
|
|
20
|
+
|
|
21
|
+
export async function cancelDcaSingleChainOrderInstructions(
|
|
22
|
+
orderAddress: string,
|
|
23
|
+
options?: { rpcUrl?: string },
|
|
24
|
+
): Promise<IInstruction[]> {
|
|
25
|
+
const rpc = options?.rpcUrl ? createSolanaRpc(options.rpcUrl) : getDefaultSolanaRPC();
|
|
26
|
+
|
|
27
|
+
const orderId = address(orderAddress);
|
|
28
|
+
const chainOrder = await fetchMaybeDcaOrder(rpc, orderId);
|
|
29
|
+
|
|
30
|
+
if (!chainOrder.exists) {
|
|
31
|
+
throw new Error(`Order with address ${orderAddress} not found`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const instructions: IInstruction[] = [];
|
|
35
|
+
const orderUserAddress = chainOrder.data.user;
|
|
36
|
+
|
|
37
|
+
const tokenInMint = chainOrder.data.tokenInMint;
|
|
38
|
+
|
|
39
|
+
const tokenMintProgram = await fetchMint(rpc, tokenInMint);
|
|
40
|
+
|
|
41
|
+
const addressEncoder = getAddressEncoder();
|
|
42
|
+
|
|
43
|
+
const [tokenInProgramAccount] = await getProgramDerivedAddress({
|
|
44
|
+
programAddress: ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
|
|
45
|
+
seeds: [
|
|
46
|
+
addressEncoder.encode(orderUserAddress),
|
|
47
|
+
addressEncoder.encode(tokenMintProgram.programAddress),
|
|
48
|
+
addressEncoder.encode(tokenInMint),
|
|
49
|
+
],
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const guardAddress = SINGLE_CHAIN_GUARD_ADDRESSES[ChainID.Solana] as Address;
|
|
53
|
+
const [guardProgramAccount] = await getProgramDerivedAddress({
|
|
54
|
+
programAddress: ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
|
|
55
|
+
seeds: [
|
|
56
|
+
// Owner
|
|
57
|
+
addressEncoder.encode(guardAddress),
|
|
58
|
+
// Token program
|
|
59
|
+
addressEncoder.encode(tokenMintProgram.programAddress),
|
|
60
|
+
// mint address
|
|
61
|
+
addressEncoder.encode(tokenInMint),
|
|
62
|
+
],
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const userTokenInAccount = await fetchEncodedAccount(rpc, tokenInProgramAccount);
|
|
66
|
+
|
|
67
|
+
if (!userTokenInAccount.exists) {
|
|
68
|
+
const createTokenIx = await getCreateAssociatedTokenInstructionAsync({
|
|
69
|
+
mint: tokenInMint,
|
|
70
|
+
owner: orderUserAddress,
|
|
71
|
+
payer: createNoopSigner(orderUserAddress),
|
|
72
|
+
tokenProgram: tokenMintProgram.programAddress,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
instructions.push(createTokenIx);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const cancelLimitOrderIx = getCancelDcaOrderInstruction({
|
|
79
|
+
user: createNoopSigner(orderUserAddress),
|
|
80
|
+
order: orderId,
|
|
81
|
+
guard: guardAddress,
|
|
82
|
+
tokenInMint: chainOrder.data.tokenInMint,
|
|
83
|
+
userTokenInAccount: userTokenInAccount.address,
|
|
84
|
+
guardTokenInAccount: guardProgramAccount,
|
|
85
|
+
tokenInProgram: tokenMintProgram.programAddress,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
instructions.push(cancelLimitOrderIx);
|
|
89
|
+
|
|
90
|
+
return instructions;
|
|
91
|
+
}
|
|
@@ -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
|
+
}
|
package/src/core/solana/sdk.ts
CHANGED
|
@@ -22,14 +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 {
|
|
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
|
-
import type { ApiUserOrders } from '../../types/api.js';
|
|
29
32
|
import { fetchJWTToken, fetchSiweMessage } from '../../auth/siwe.js';
|
|
30
33
|
import { ChainID } from '../../chains.js';
|
|
31
34
|
import { bytesToHex } from 'viem';
|
|
32
|
-
import {
|
|
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';
|
|
33
38
|
|
|
34
39
|
/**
|
|
35
40
|
* Solana-specific SDK implementation
|
|
@@ -41,7 +46,6 @@ import { fetchUserOrders } from '../orders/api/fetch.js';
|
|
|
41
46
|
export class SolanaSDK extends BaseSDK {
|
|
42
47
|
/** Configuration for Solana connection and authentication */
|
|
43
48
|
private readonly config: SolanaConfig;
|
|
44
|
-
private token?: string;
|
|
45
49
|
/** Client for Solana RPC interactions and transaction handling */
|
|
46
50
|
private client: SolanaClient;
|
|
47
51
|
|
|
@@ -70,12 +74,6 @@ export class SolanaSDK extends BaseSDK {
|
|
|
70
74
|
return signer.address;
|
|
71
75
|
}
|
|
72
76
|
|
|
73
|
-
public setToken(token: string) {
|
|
74
|
-
this.token = token;
|
|
75
|
-
|
|
76
|
-
return this;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
77
|
public async cancelCrossChainOrder(orderId: string): Promise<string> {
|
|
80
78
|
const instructions = await cancelCrossChainOrderInstructions(orderId, { rpcUrl: this.config.rpcProviderUrl });
|
|
81
79
|
const signer = await this.getUserSigner();
|
|
@@ -195,16 +193,6 @@ export class SolanaSDK extends BaseSDK {
|
|
|
195
193
|
return newToken;
|
|
196
194
|
}
|
|
197
195
|
|
|
198
|
-
public override async getOrders(): Promise<ApiUserOrders> {
|
|
199
|
-
if (!this.token) {
|
|
200
|
-
throw new Error('No token provided');
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const orders = await fetchUserOrders(this.token);
|
|
204
|
-
|
|
205
|
-
return orders;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
196
|
/**
|
|
209
197
|
* Prepares a Solana order for submission
|
|
210
198
|
*
|
|
@@ -243,7 +231,7 @@ export class SolanaSDK extends BaseSDK {
|
|
|
243
231
|
};
|
|
244
232
|
}
|
|
245
233
|
|
|
246
|
-
protected async prepareSingleChainOrder(order: SingleChainOrder): Promise<SingleChainOrderPrepared> {
|
|
234
|
+
protected override async prepareSingleChainOrder(order: SingleChainOrder): Promise<SingleChainOrderPrepared> {
|
|
247
235
|
const signerKeyPair = await this.getUserCryptoKeypair();
|
|
248
236
|
|
|
249
237
|
const { orderAddress, txBytes, secretNumber } = await getSolanaSingleChainOrderInstructions(order);
|
|
@@ -256,6 +244,62 @@ export class SolanaSDK extends BaseSDK {
|
|
|
256
244
|
|
|
257
245
|
const encodedTransaction = getBase64EncodedWireTransaction(signedTx);
|
|
258
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
|
+
|
|
259
303
|
await this.client.rpc
|
|
260
304
|
.sendTransaction(encodedTransaction, { preflightCommitment: this.config.commitment, encoding: 'base64' })
|
|
261
305
|
.send();
|