perps-sdk-ts 1.0.1
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/.claude/settings.local.json +11 -0
- package/CONTRACT_METHOD_FIXES.md +189 -0
- package/INTEGRATION_SUMMARY.md +219 -0
- package/OPTIMIZATION_GUIDE.md +238 -0
- package/README.md +384 -0
- package/SNAPSHOT_FIX_SUMMARY.md +161 -0
- package/SNAPSHOT_OPTIMIZATION_SUMMARY.md +199 -0
- package/dist/abis/Referral.d.ts +36 -0
- package/dist/abis/Referral.js +4 -0
- package/dist/abis/Trading.d.ts +57 -0
- package/dist/abis/Trading.js +742 -0
- package/dist/abis/erc20.d.ts +51 -0
- package/dist/abis/erc20.js +4 -0
- package/dist/abis/index.d.ts +8 -0
- package/dist/abis/index.js +24 -0
- package/dist/abis/multicall.d.ts +85 -0
- package/dist/abis/multicall.js +4 -0
- package/dist/abis/pairInfos.d.ts +77 -0
- package/dist/abis/pairInfos.js +4 -0
- package/dist/abis/pairStorage.d.ts +124 -0
- package/dist/abis/pairStorage.js +4 -0
- package/dist/abis/priceAggregator.d.ts +77 -0
- package/dist/abis/priceAggregator.js +4 -0
- package/dist/abis/tardingStorage.d.ts +97 -0
- package/dist/abis/tardingStorage.js +1295 -0
- package/dist/abis.d.ts +623 -0
- package/dist/abis.js +49 -0
- package/dist/client.d.ts +118 -0
- package/dist/client.js +224 -0
- package/dist/config.d.ts +43 -0
- package/dist/config.js +42 -0
- package/dist/crypto/spki.d.ts +55 -0
- package/dist/crypto/spki.js +160 -0
- package/dist/feed/feed_client.d.ts +68 -0
- package/dist/feed/feed_client.js +239 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +87 -0
- package/dist/rpc/asset_parameters.d.ts +62 -0
- package/dist/rpc/asset_parameters.js +169 -0
- package/dist/rpc/blended.d.ts +23 -0
- package/dist/rpc/blended.js +55 -0
- package/dist/rpc/category_parameters.d.ts +34 -0
- package/dist/rpc/category_parameters.js +105 -0
- package/dist/rpc/delegation.d.ts +81 -0
- package/dist/rpc/delegation.js +180 -0
- package/dist/rpc/fee_parameters.d.ts +46 -0
- package/dist/rpc/fee_parameters.js +113 -0
- package/dist/rpc/multicall.d.ts +83 -0
- package/dist/rpc/multicall.js +117 -0
- package/dist/rpc/pair_info_queries.d.ts +101 -0
- package/dist/rpc/pair_info_queries.js +161 -0
- package/dist/rpc/pairs_cache.d.ts +62 -0
- package/dist/rpc/pairs_cache.js +240 -0
- package/dist/rpc/referral_operations.d.ts +67 -0
- package/dist/rpc/referral_operations.js +143 -0
- package/dist/rpc/snapshot.d.ts +49 -0
- package/dist/rpc/snapshot.js +162 -0
- package/dist/rpc/trade.d.ts +84 -0
- package/dist/rpc/trade.js +249 -0
- package/dist/rpc/trading_operations.d.ts +103 -0
- package/dist/rpc/trading_operations.js +295 -0
- package/dist/rpc/trading_parameters.d.ts +49 -0
- package/dist/rpc/trading_parameters.js +94 -0
- package/dist/signers/base.d.ts +24 -0
- package/dist/signers/base.js +10 -0
- package/dist/signers/kms.d.ts +47 -0
- package/dist/signers/kms.js +172 -0
- package/dist/signers/local.d.ts +43 -0
- package/dist/signers/local.js +64 -0
- package/dist/types.d.ts +1419 -0
- package/dist/types.js +245 -0
- package/dist/utils.d.ts +52 -0
- package/dist/utils.js +134 -0
- package/examples/advanced-queries.ts +181 -0
- package/examples/basic-usage.ts +78 -0
- package/examples/delegation-and-referrals.ts +130 -0
- package/examples/get-pyth-ids.ts +61 -0
- package/examples/kms-signer.ts +31 -0
- package/examples/optimized-snapshot.ts +153 -0
- package/examples/price-feed-with-sdk-ids.ts +97 -0
- package/examples/price-feed.ts +36 -0
- package/examples/trading-operations.ts +149 -0
- package/package.json +41 -0
- package/src/abis/Referral.ts +3 -0
- package/src/abis/Trading.ts +741 -0
- package/src/abis/erc20.ts +3 -0
- package/src/abis/index.ts +8 -0
- package/src/abis/multicall.ts +3 -0
- package/src/abis/pairInfos.ts +3 -0
- package/src/abis/pairStorage.ts +3 -0
- package/src/abis/priceAggregator.ts +3 -0
- package/src/abis/tardingStorage.ts +1294 -0
- package/src/abis.ts +56 -0
- package/src/client.ts +373 -0
- package/src/config.ts +62 -0
- package/src/crypto/spki.ts +197 -0
- package/src/feed/feed_client.ts +288 -0
- package/src/index.ts +114 -0
- package/src/rpc/asset_parameters.ts +217 -0
- package/src/rpc/blended.ts +77 -0
- package/src/rpc/category_parameters.ts +128 -0
- package/src/rpc/delegation.ts +225 -0
- package/src/rpc/fee_parameters.ts +150 -0
- package/src/rpc/multicall.ts +164 -0
- package/src/rpc/pair_info_queries.ts +208 -0
- package/src/rpc/pairs_cache.ts +268 -0
- package/src/rpc/referral_operations.ts +164 -0
- package/src/rpc/snapshot.ts +210 -0
- package/src/rpc/trade.ts +306 -0
- package/src/rpc/trading_operations.ts +378 -0
- package/src/rpc/trading_parameters.ts +127 -0
- package/src/signers/base.ts +27 -0
- package/src/signers/kms.ts +212 -0
- package/src/signers/local.ts +70 -0
- package/src/types.ts +410 -0
- package/src/utils.ts +155 -0
- package/tsconfig.json +18 -0
package/src/abis.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract ABIs for Avantis Protocol
|
|
3
|
+
*
|
|
4
|
+
* These ABIs contain the function signatures needed to interact with
|
|
5
|
+
* the Avantis smart contracts.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ERC20 ABI (for USDC)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import refferal from "./abis/Referral";
|
|
13
|
+
import trading from "./abis/Trading"
|
|
14
|
+
import erc20 from "./abis/erc20"
|
|
15
|
+
import pairStorage from "./abis/pairStorage"
|
|
16
|
+
import tradingStorage from "./abis/tardingStorage"
|
|
17
|
+
import pairinfos from "./abis/pairInfos"
|
|
18
|
+
import priceAggregator from "./abis/priceAggregator"
|
|
19
|
+
import referral from "./abis/Referral"
|
|
20
|
+
import multicall from "./abis/multicall"
|
|
21
|
+
|
|
22
|
+
export const ERC20_ABI = erc20;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Trading Contract ABI
|
|
26
|
+
*/
|
|
27
|
+
export const TRADING_ABI = trading;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* TradingStorage Contract ABI
|
|
31
|
+
*/
|
|
32
|
+
export const TRADING_STORAGE_ABI = tradingStorage;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* PairStorage Contract ABI
|
|
36
|
+
*/
|
|
37
|
+
export const PAIR_STORAGE_ABI = pairStorage;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* PairInfos Contract ABI
|
|
41
|
+
*/
|
|
42
|
+
export const PAIR_INFOS_ABI = pairinfos;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* PriceAggregator Contract ABI
|
|
46
|
+
*/
|
|
47
|
+
export const PRICE_AGGREGATOR_ABI = priceAggregator;
|
|
48
|
+
/**
|
|
49
|
+
* Referral Contract ABI
|
|
50
|
+
*/
|
|
51
|
+
export const REFERRAL_ABI = referral;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Multicall Contract ABI
|
|
55
|
+
*/
|
|
56
|
+
export const MULTICALL_ABI = multicall;
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import { ethers, JsonRpcProvider, Contract, TransactionReceipt, TransactionRequest } from 'ethers';
|
|
2
|
+
import { BaseSigner } from './signers/base';
|
|
3
|
+
import { LocalSigner } from './signers/local';
|
|
4
|
+
import { KMSSigner } from './signers/kms';
|
|
5
|
+
import { FeedClient } from './feed/feed_client';
|
|
6
|
+
import { CONTRACTS, getContractAddress } from './config';
|
|
7
|
+
import { PairsCache } from './rpc/pairs_cache';
|
|
8
|
+
import { AssetParametersRPC } from './rpc/asset_parameters';
|
|
9
|
+
import { CategoryParametersRPC } from './rpc/category_parameters';
|
|
10
|
+
import { FeeParametersRPC } from './rpc/fee_parameters';
|
|
11
|
+
import { TradingParametersRPC } from './rpc/trading_parameters';
|
|
12
|
+
import { BlendedRPC } from './rpc/blended';
|
|
13
|
+
import { TradeRPC } from './rpc/trade';
|
|
14
|
+
import { SnapshotRPC } from './rpc/snapshot';
|
|
15
|
+
import { TradingOperationsRPC } from './rpc/trading_operations';
|
|
16
|
+
import { DelegationRPC } from './rpc/delegation';
|
|
17
|
+
import { PairInfoQueriesRPC } from './rpc/pair_info_queries';
|
|
18
|
+
import { ReferralOperationsRPC } from './rpc/referral_operations';
|
|
19
|
+
import { MulticallRPC } from './rpc/multicall';
|
|
20
|
+
import { fromBlockchain6 } from './types';
|
|
21
|
+
import {
|
|
22
|
+
ERC20_ABI,
|
|
23
|
+
TRADING_ABI,
|
|
24
|
+
TRADING_STORAGE_ABI,
|
|
25
|
+
PAIR_STORAGE_ABI,
|
|
26
|
+
PAIR_INFOS_ABI,
|
|
27
|
+
PRICE_AGGREGATOR_ABI,
|
|
28
|
+
REFERRAL_ABI,
|
|
29
|
+
MULTICALL_ABI,
|
|
30
|
+
} from './abis';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Main client for interacting with Avantis trading platform
|
|
34
|
+
*/
|
|
35
|
+
export class TraderClient {
|
|
36
|
+
public provider: JsonRpcProvider;
|
|
37
|
+
signer?: BaseSigner;
|
|
38
|
+
public feedClient?: FeedClient;
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
// Contracts
|
|
42
|
+
private contracts: Map<string, Contract> = new Map();
|
|
43
|
+
|
|
44
|
+
// RPC modules
|
|
45
|
+
public pairsCache: PairsCache;
|
|
46
|
+
public assetParams: AssetParametersRPC;
|
|
47
|
+
public categoryParams: CategoryParametersRPC;
|
|
48
|
+
public feeParams: FeeParametersRPC;
|
|
49
|
+
public tradingParams: TradingParametersRPC;
|
|
50
|
+
public blendedParams: BlendedRPC;
|
|
51
|
+
public tradeRPC: TradeRPC;
|
|
52
|
+
public snapshotRPC: SnapshotRPC;
|
|
53
|
+
|
|
54
|
+
// New trading modules
|
|
55
|
+
public tradingOps: TradingOperationsRPC;
|
|
56
|
+
public delegation: DelegationRPC;
|
|
57
|
+
public pairInfoQueries: PairInfoQueriesRPC;
|
|
58
|
+
public referral: ReferralOperationsRPC;
|
|
59
|
+
public multicall: MulticallRPC;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create a new TraderClient
|
|
63
|
+
* @param providerUrl - Ethereum RPC endpoint
|
|
64
|
+
* @param signer - Transaction signer (optional)
|
|
65
|
+
* @param feedClient - Feed client for price updates (optional)
|
|
66
|
+
*/
|
|
67
|
+
constructor(
|
|
68
|
+
providerUrl: string,
|
|
69
|
+
signer?: BaseSigner,
|
|
70
|
+
feedClient?: FeedClient
|
|
71
|
+
) {
|
|
72
|
+
this.provider = new JsonRpcProvider(providerUrl);
|
|
73
|
+
this.signer = signer;
|
|
74
|
+
this.feedClient = feedClient;
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
// Initialize RPC modules
|
|
78
|
+
this.initializeContracts();
|
|
79
|
+
this.pairsCache = new PairsCache(
|
|
80
|
+
this.provider,
|
|
81
|
+
this.getContract('PairStorage')
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const pairStorage = this.getContract('PairStorage');
|
|
85
|
+
const pairInfos = this.getContract('PairInfos');
|
|
86
|
+
const trading = this.getContract('Trading');
|
|
87
|
+
const tradingStorage = this.getContract('TradingStorage');
|
|
88
|
+
const referral = this.getContract('Referral');
|
|
89
|
+
|
|
90
|
+
this.assetParams = new AssetParametersRPC(
|
|
91
|
+
this.provider,
|
|
92
|
+
pairStorage,
|
|
93
|
+
pairInfos,
|
|
94
|
+
this.pairsCache,
|
|
95
|
+
tradingStorage
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
this.categoryParams = new CategoryParametersRPC(
|
|
99
|
+
this.provider,
|
|
100
|
+
pairStorage,
|
|
101
|
+
this.pairsCache
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
this.feeParams = new FeeParametersRPC(
|
|
105
|
+
this.provider,
|
|
106
|
+
pairInfos,
|
|
107
|
+
this.pairsCache,
|
|
108
|
+
referral
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
this.tradingParams = new TradingParametersRPC(
|
|
112
|
+
this.provider,
|
|
113
|
+
pairInfos,
|
|
114
|
+
this.pairsCache
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
this.blendedParams = new BlendedRPC(
|
|
118
|
+
this.assetParams,
|
|
119
|
+
this.categoryParams,
|
|
120
|
+
this.pairsCache
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
this.tradeRPC = new TradeRPC(
|
|
124
|
+
this.provider,
|
|
125
|
+
trading,
|
|
126
|
+
tradingStorage,
|
|
127
|
+
this.pairsCache
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
this.snapshotRPC = new SnapshotRPC(
|
|
131
|
+
this.pairsCache,
|
|
132
|
+
this.assetParams,
|
|
133
|
+
this.categoryParams,
|
|
134
|
+
this.feeParams,
|
|
135
|
+
this.blendedParams
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
// Initialize new trading modules
|
|
139
|
+
this.tradingOps = new TradingOperationsRPC(
|
|
140
|
+
trading,
|
|
141
|
+
tradingStorage,
|
|
142
|
+
this.signer
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
this.delegation = new DelegationRPC(
|
|
146
|
+
trading,
|
|
147
|
+
this.signer
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
this.pairInfoQueries = new PairInfoQueriesRPC(
|
|
151
|
+
pairInfos,
|
|
152
|
+
this.getContract('PriceAggregator')
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
this.referral = new ReferralOperationsRPC(
|
|
156
|
+
referral,
|
|
157
|
+
this.signer
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
this.multicall = new MulticallRPC(
|
|
161
|
+
this.getContract('Multicall')
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Initialize contract instances
|
|
167
|
+
*/
|
|
168
|
+
private initializeContracts(): void {
|
|
169
|
+
this.contracts.set(
|
|
170
|
+
'TradingStorage',
|
|
171
|
+
new Contract(CONTRACTS.TradingStorage, TRADING_STORAGE_ABI, this.provider)
|
|
172
|
+
);
|
|
173
|
+
this.contracts.set(
|
|
174
|
+
'PairStorage',
|
|
175
|
+
new Contract(CONTRACTS.PairStorage, PAIR_STORAGE_ABI, this.provider)
|
|
176
|
+
);
|
|
177
|
+
this.contracts.set(
|
|
178
|
+
'PairInfos',
|
|
179
|
+
new Contract(CONTRACTS.PairInfos, PAIR_INFOS_ABI, this.provider)
|
|
180
|
+
);
|
|
181
|
+
this.contracts.set(
|
|
182
|
+
'PriceAggregator',
|
|
183
|
+
new Contract(CONTRACTS.PriceAggregator, PRICE_AGGREGATOR_ABI, this.provider)
|
|
184
|
+
);
|
|
185
|
+
this.contracts.set(
|
|
186
|
+
'USDC',
|
|
187
|
+
new Contract(CONTRACTS.USDC, ERC20_ABI, this.provider)
|
|
188
|
+
);
|
|
189
|
+
this.contracts.set(
|
|
190
|
+
'Trading',
|
|
191
|
+
new Contract(CONTRACTS.Trading, TRADING_ABI, this.provider)
|
|
192
|
+
);
|
|
193
|
+
this.contracts.set(
|
|
194
|
+
'Referral',
|
|
195
|
+
new Contract(CONTRACTS.Referral, REFERRAL_ABI, this.provider)
|
|
196
|
+
);
|
|
197
|
+
this.contracts.set(
|
|
198
|
+
'Multicall',
|
|
199
|
+
new Contract(CONTRACTS.Multicall, MULTICALL_ABI, this.provider)
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Get a contract instance
|
|
205
|
+
* @param name - Contract name
|
|
206
|
+
* @returns Contract instance
|
|
207
|
+
*/
|
|
208
|
+
private getContract(name: string): Contract {
|
|
209
|
+
const contract = this.contracts.get(name);
|
|
210
|
+
if (!contract) {
|
|
211
|
+
throw new Error(`Contract ${name} not initialized`);
|
|
212
|
+
}
|
|
213
|
+
return contract;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Set signer for transaction signing
|
|
218
|
+
* @param signer - Signer instance
|
|
219
|
+
*/
|
|
220
|
+
setSigner(signer: BaseSigner): void {
|
|
221
|
+
this.signer = signer;
|
|
222
|
+
this.tradingOps.setSigner(signer);
|
|
223
|
+
this.delegation.setSigner(signer);
|
|
224
|
+
this.referral.setSigner(signer);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Set local signer using private key
|
|
229
|
+
* @param privateKey - Private key
|
|
230
|
+
*/
|
|
231
|
+
setLocalSigner(privateKey: string): void {
|
|
232
|
+
this.signer = new LocalSigner(privateKey, this.provider);
|
|
233
|
+
this.setSigner(this.signer);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Set AWS KMS signer
|
|
238
|
+
* @param kmsKeyId - KMS key ID
|
|
239
|
+
* @param region - AWS region
|
|
240
|
+
*/
|
|
241
|
+
setAwsKmsSigner(kmsKeyId: string, region: string = 'us-east-1'): void {
|
|
242
|
+
this.signer = new KMSSigner(kmsKeyId, this.provider, region);
|
|
243
|
+
this.setSigner(this.signer);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Get native token balance
|
|
248
|
+
* @param address - Address to check
|
|
249
|
+
* @returns Balance in native token
|
|
250
|
+
*/
|
|
251
|
+
async getBalance(address: string): Promise<bigint> {
|
|
252
|
+
return await this.provider.getBalance(address);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Get USDC balance
|
|
257
|
+
* @param address - Address to check
|
|
258
|
+
* @returns USDC balance
|
|
259
|
+
*/
|
|
260
|
+
async getUsdcBalance(address: string): Promise<number> {
|
|
261
|
+
const balance = await this.getContract('USDC').balanceOf(address);
|
|
262
|
+
return fromBlockchain6(balance);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Get USDC allowance for trading
|
|
267
|
+
* @param address - Address to check
|
|
268
|
+
* @returns Allowance amount
|
|
269
|
+
*/
|
|
270
|
+
async getUsdcAllowanceForTrading(address: string): Promise<number> {
|
|
271
|
+
const tradingStorageAddress = await this.getContract('TradingStorage').getAddress();
|
|
272
|
+
const allowance = await this.getContract('USDC').allowance(address, tradingStorageAddress);
|
|
273
|
+
return fromBlockchain6(allowance);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Approve USDC for trading
|
|
278
|
+
* @param amount - Amount to approve
|
|
279
|
+
* @returns Transaction receipt
|
|
280
|
+
*/
|
|
281
|
+
async approveUsdcForTrading(amount: number): Promise<TransactionReceipt | null> {
|
|
282
|
+
if (!this.signer) {
|
|
283
|
+
throw new Error('Signer not set');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const tradingStorageAddress = await this.getContract('TradingStorage').getAddress();
|
|
287
|
+
const amountWei = BigInt(Math.floor(amount * 1e6));
|
|
288
|
+
|
|
289
|
+
const tx: TransactionRequest = {
|
|
290
|
+
to: CONTRACTS.USDC,
|
|
291
|
+
data: this.getContract('USDC').interface.encodeFunctionData('approve', [
|
|
292
|
+
tradingStorageAddress,
|
|
293
|
+
amountWei,
|
|
294
|
+
]),
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
return await this.signAndGetReceipt(tx);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Sign transaction and wait for receipt
|
|
302
|
+
* @param tx - Transaction to sign
|
|
303
|
+
* @returns Transaction receipt
|
|
304
|
+
*/
|
|
305
|
+
async signAndGetReceipt(tx: TransactionRequest): Promise<TransactionReceipt | null> {
|
|
306
|
+
if (!this.signer) {
|
|
307
|
+
throw new Error('Signer not set');
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Fill in missing transaction fields
|
|
311
|
+
const address = await this.signer.getAddress();
|
|
312
|
+
tx.from = address;
|
|
313
|
+
|
|
314
|
+
if (!tx.chainId) {
|
|
315
|
+
const network = await this.provider.getNetwork();
|
|
316
|
+
tx.chainId = network.chainId;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (tx.nonce === undefined) {
|
|
320
|
+
tx.nonce = await this.provider.getTransactionCount(address);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (!tx.gasLimit) {
|
|
324
|
+
tx.gasLimit = await this.provider.estimateGas(tx);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (!tx.maxFeePerGas && !tx.gasPrice) {
|
|
328
|
+
const feeData = await this.provider.getFeeData();
|
|
329
|
+
if (feeData.maxFeePerGas) {
|
|
330
|
+
tx.maxFeePerGas = feeData.maxFeePerGas;
|
|
331
|
+
tx.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas || feeData.maxFeePerGas;
|
|
332
|
+
} else {
|
|
333
|
+
tx.gasPrice = feeData.gasPrice || undefined;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Sign the transaction
|
|
338
|
+
const signedTx = await this.signer.signTransaction(tx);
|
|
339
|
+
|
|
340
|
+
// Send the transaction
|
|
341
|
+
const txResponse = await this.provider.broadcastTransaction(signedTx);
|
|
342
|
+
|
|
343
|
+
// Wait for confirmation
|
|
344
|
+
return await txResponse.wait();
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Estimate gas for a transaction
|
|
349
|
+
* @param tx - Transaction to estimate
|
|
350
|
+
* @returns Estimated gas
|
|
351
|
+
*/
|
|
352
|
+
async estimateGas(tx: TransactionRequest): Promise<bigint> {
|
|
353
|
+
return await this.provider.estimateGas(tx);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Get transaction count (nonce)
|
|
358
|
+
* @param address - Address to check
|
|
359
|
+
* @returns Transaction count
|
|
360
|
+
*/
|
|
361
|
+
async getTransactionCount(address: string): Promise<number> {
|
|
362
|
+
return await this.provider.getTransactionCount(address);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Get chain ID
|
|
367
|
+
* @returns Chain ID
|
|
368
|
+
*/
|
|
369
|
+
async getChainId(): Promise<bigint> {
|
|
370
|
+
const network = await this.provider.getNetwork();
|
|
371
|
+
return network.chainId;
|
|
372
|
+
}
|
|
373
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration file containing contract addresses and API endpoints
|
|
3
|
+
* for Avantis trading platform
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ContractAddresses {
|
|
7
|
+
TradingStorage: string;
|
|
8
|
+
PairStorage: string;
|
|
9
|
+
PairInfos: string;
|
|
10
|
+
PriceAggregator: string;
|
|
11
|
+
USDC: string;
|
|
12
|
+
Trading: string;
|
|
13
|
+
Multicall: string;
|
|
14
|
+
Referral: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Mainnet contract addresses for Avantis (Base Network)
|
|
19
|
+
*/
|
|
20
|
+
export const CONTRACTS: ContractAddresses = {
|
|
21
|
+
TradingStorage: '0x8a311D7048c35985aa31C131B9A13e03a5f7422d',
|
|
22
|
+
PairStorage: '0x5db3772136e5557EFE028Db05EE95C84D76faEC4',
|
|
23
|
+
PairInfos: '0x81F22d0Cc22977c91bEfE648C9fddf1f2bd977e5',
|
|
24
|
+
PriceAggregator: '0x64e2625621970F8cfA17B294670d61CB883dA511',
|
|
25
|
+
USDC: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
26
|
+
Trading: '0x44914408af82bC9983bbb330e3578E1105e11d4e',
|
|
27
|
+
Multicall: '0xb7125506Ff25211c4C51DFD8DdED00BE6Fa8Cbf7',
|
|
28
|
+
Referral: '0x1A110bBA13A1f16cCa4b79758BD39290f29De82D',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* API endpoints for Avantis services
|
|
33
|
+
*/
|
|
34
|
+
export const API_ENDPOINTS = {
|
|
35
|
+
SOCKET_API: 'https://socket-api-pub.avantisfi.com/socket-api/v1/data',
|
|
36
|
+
PYTH_WS: 'wss://hermes.pyth.network/ws',
|
|
37
|
+
PYTH_HTTP: 'https://hermes.pyth.network/v2/updates/price/latest',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Network configuration
|
|
42
|
+
*/
|
|
43
|
+
export interface NetworkConfig {
|
|
44
|
+
chainId: number;
|
|
45
|
+
name: string;
|
|
46
|
+
rpcUrl: string;
|
|
47
|
+
contracts: ContractAddresses;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get contract address by name
|
|
52
|
+
*/
|
|
53
|
+
export function getContractAddress(contractName: keyof ContractAddresses): string {
|
|
54
|
+
return CONTRACTS[contractName];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Update contract addresses (useful for testing or different networks)
|
|
59
|
+
*/
|
|
60
|
+
export function setContractAddresses(addresses: Partial<ContractAddresses>): void {
|
|
61
|
+
Object.assign(CONTRACTS, addresses);
|
|
62
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { keccak256, getBytes, concat, SigningKey } from 'ethers';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Cryptographic utilities for KMS signature handling
|
|
5
|
+
* Handles ECDSA signature conversion and Ethereum address derivation
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Convert a public key (as big integer coordinates) to an Ethereum address
|
|
10
|
+
* @param publicKeyX - X coordinate of public key
|
|
11
|
+
* @param publicKeyY - Y coordinate of public key
|
|
12
|
+
* @returns Ethereum address
|
|
13
|
+
*/
|
|
14
|
+
export function publicKeyIntToEthAddress(publicKeyX: bigint, publicKeyY: bigint): string {
|
|
15
|
+
// Concatenate 0x04 (uncompressed key prefix) + x + y
|
|
16
|
+
const xBytes = publicKeyX.toString(16).padStart(64, '0');
|
|
17
|
+
const yBytes = publicKeyY.toString(16).padStart(64, '0');
|
|
18
|
+
const publicKeyHex = '0x04' + xBytes + yBytes;
|
|
19
|
+
|
|
20
|
+
// Keccak256 hash
|
|
21
|
+
const hash = keccak256(publicKeyHex);
|
|
22
|
+
|
|
23
|
+
// Take last 20 bytes as address
|
|
24
|
+
return '0x' + hash.slice(-40);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Parse DER-encoded public key and convert to Ethereum address
|
|
29
|
+
* @param derPublicKey - DER-encoded public key bytes
|
|
30
|
+
* @returns Ethereum address
|
|
31
|
+
*/
|
|
32
|
+
export function derEncodedPublicKeyToEthAddress(derPublicKey: Uint8Array): string {
|
|
33
|
+
// Parse the DER structure to extract the public key
|
|
34
|
+
// DER structure for ECDSA public key (simplified parsing)
|
|
35
|
+
|
|
36
|
+
// Find the public key bytes (starts with 0x04 for uncompressed key)
|
|
37
|
+
let publicKeyStart = -1;
|
|
38
|
+
for (let i = 0; i < derPublicKey.length - 64; i++) {
|
|
39
|
+
if (derPublicKey[i] === 0x04) {
|
|
40
|
+
publicKeyStart = i;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (publicKeyStart === -1) {
|
|
46
|
+
throw new Error('Could not find uncompressed public key in DER structure');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Extract 65 bytes: 0x04 + 32 bytes X + 32 bytes Y
|
|
50
|
+
const publicKeyBytes = derPublicKey.slice(publicKeyStart, publicKeyStart + 65);
|
|
51
|
+
|
|
52
|
+
// Convert to hex
|
|
53
|
+
const publicKeyHex = '0x' + Buffer.from(publicKeyBytes).toString('hex');
|
|
54
|
+
|
|
55
|
+
// Keccak256 hash (skip the 0x04 prefix)
|
|
56
|
+
const hash = keccak256(publicKeyHex);
|
|
57
|
+
|
|
58
|
+
// Take last 20 bytes as address
|
|
59
|
+
return '0x' + hash.slice(-40);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Parse DER-encoded signature to extract r and s values
|
|
64
|
+
* @param derSignature - DER-encoded signature
|
|
65
|
+
* @returns Object with r and s as hex strings
|
|
66
|
+
*/
|
|
67
|
+
export function getSigRS(derSignature: Uint8Array): { r: string; s: string } {
|
|
68
|
+
// DER signature structure:
|
|
69
|
+
// 0x30 [total-length] 0x02 [r-length] [r-bytes] 0x02 [s-length] [s-bytes]
|
|
70
|
+
|
|
71
|
+
let offset = 0;
|
|
72
|
+
|
|
73
|
+
// Check sequence tag
|
|
74
|
+
if (derSignature[offset++] !== 0x30) {
|
|
75
|
+
throw new Error('Invalid DER signature: missing sequence tag');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Skip total length
|
|
79
|
+
offset++;
|
|
80
|
+
|
|
81
|
+
// Read r
|
|
82
|
+
if (derSignature[offset++] !== 0x02) {
|
|
83
|
+
throw new Error('Invalid DER signature: missing r integer tag');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const rLength = derSignature[offset++];
|
|
87
|
+
let rBytes = derSignature.slice(offset, offset + rLength);
|
|
88
|
+
offset += rLength;
|
|
89
|
+
|
|
90
|
+
// Remove leading zero if present (DER encoding adds it for positive numbers)
|
|
91
|
+
if (rBytes[0] === 0x00) {
|
|
92
|
+
rBytes = rBytes.slice(1);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const r = '0x' + Buffer.from(rBytes).toString('hex');
|
|
96
|
+
|
|
97
|
+
// Read s
|
|
98
|
+
if (derSignature[offset++] !== 0x02) {
|
|
99
|
+
throw new Error('Invalid DER signature: missing s integer tag');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const sLength = derSignature[offset++];
|
|
103
|
+
let sBytes = derSignature.slice(offset, offset + sLength);
|
|
104
|
+
|
|
105
|
+
// Remove leading zero if present
|
|
106
|
+
if (sBytes[0] === 0x00) {
|
|
107
|
+
sBytes = sBytes.slice(1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const s = '0x' + Buffer.from(sBytes).toString('hex');
|
|
111
|
+
|
|
112
|
+
return { r, s };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Recover the v value for an ECDSA signature
|
|
117
|
+
* @param msgHash - Message hash that was signed
|
|
118
|
+
* @param r - r component of signature
|
|
119
|
+
* @param s - s component of signature
|
|
120
|
+
* @param expectedAddress - Expected Ethereum address
|
|
121
|
+
* @returns v value (27 or 28)
|
|
122
|
+
*/
|
|
123
|
+
export function getSigV(
|
|
124
|
+
msgHash: string,
|
|
125
|
+
r: string,
|
|
126
|
+
s: string,
|
|
127
|
+
expectedAddress: string
|
|
128
|
+
): number {
|
|
129
|
+
// Try both possible v values (27 and 28)
|
|
130
|
+
for (const v of [27, 28]) {
|
|
131
|
+
try {
|
|
132
|
+
const signature = {
|
|
133
|
+
r,
|
|
134
|
+
s,
|
|
135
|
+
v,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// Construct the signature string
|
|
139
|
+
const sigString = concat([
|
|
140
|
+
signature.r,
|
|
141
|
+
signature.s,
|
|
142
|
+
new Uint8Array([signature.v]),
|
|
143
|
+
]);
|
|
144
|
+
|
|
145
|
+
// Try to recover the address
|
|
146
|
+
const recoveredAddress = SigningKey.recoverPublicKey(
|
|
147
|
+
getBytes(msgHash),
|
|
148
|
+
sigString
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const recoveredAddr = keccak256('0x' + recoveredAddress.slice(4));
|
|
152
|
+
const addr = '0x' + recoveredAddr.slice(-40);
|
|
153
|
+
|
|
154
|
+
if (addr.toLowerCase() === expectedAddress.toLowerCase()) {
|
|
155
|
+
return v;
|
|
156
|
+
}
|
|
157
|
+
} catch (e) {
|
|
158
|
+
// Continue to next v value
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
throw new Error('Could not recover v value from signature');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get complete signature (r, s, v) from DER-encoded KMS signature
|
|
168
|
+
* @param kmsSignature - DER-encoded signature from KMS
|
|
169
|
+
* @param msgHash - Message hash that was signed
|
|
170
|
+
* @param ethAddress - Expected Ethereum address
|
|
171
|
+
* @returns Complete signature object
|
|
172
|
+
*/
|
|
173
|
+
export function getSigRSV(
|
|
174
|
+
kmsSignature: Uint8Array,
|
|
175
|
+
msgHash: string,
|
|
176
|
+
ethAddress: string
|
|
177
|
+
): { r: string; s: string; v: number } {
|
|
178
|
+
const { r, s } = getSigRS(kmsSignature);
|
|
179
|
+
const v = getSigV(msgHash, r, s, ethAddress);
|
|
180
|
+
|
|
181
|
+
return { r, s, v };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Convert signature components to a single hex string
|
|
186
|
+
* @param r - r component
|
|
187
|
+
* @param s - s component
|
|
188
|
+
* @param v - v component
|
|
189
|
+
* @returns Signature as hex string
|
|
190
|
+
*/
|
|
191
|
+
export function signatureToHex(r: string, s: string, v: number): string {
|
|
192
|
+
const rHex = r.startsWith('0x') ? r.slice(2) : r;
|
|
193
|
+
const sHex = s.startsWith('0x') ? s.slice(2) : s;
|
|
194
|
+
const vHex = v.toString(16).padStart(2, '0');
|
|
195
|
+
|
|
196
|
+
return '0x' + rHex.padStart(64, '0') + sHex.padStart(64, '0') + vHex;
|
|
197
|
+
}
|