@clonegod/ttd-sui-common 1.0.101 → 2.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/dist/appconfig/SuiQuoteAppConfig.d.ts +10 -0
- package/dist/appconfig/SuiQuoteAppConfig.js +35 -0
- package/dist/appconfig/SuiTradeAppConfig.d.ts +7 -0
- package/dist/appconfig/SuiTradeAppConfig.js +13 -0
- package/dist/appconfig/ensure_core_env.d.ts +1 -0
- package/dist/appconfig/ensure_core_env.js +18 -0
- package/dist/appconfig/index.d.ts +5 -0
- package/dist/appconfig/index.js +21 -0
- package/dist/appconfig/sui_dex_env_args.d.ts +5 -0
- package/dist/appconfig/sui_dex_env_args.js +28 -0
- package/dist/appconfig/sui_env_args.d.ts +4 -0
- package/dist/appconfig/sui_env_args.js +20 -0
- package/dist/grpc/gas-price-cache.js +19 -32
- package/dist/grpc/grpc-connection.js +5 -3
- package/dist/grpc/grpc_provider_registry.d.ts +14 -0
- package/dist/grpc/grpc_provider_registry.js +60 -0
- package/dist/grpc/index.d.ts +3 -0
- package/dist/grpc/index.js +13 -1
- package/dist/grpc/ledger-service.js +107 -128
- package/dist/grpc/proto_value.d.ts +4 -0
- package/dist/grpc/proto_value.js +59 -0
- package/dist/grpc/state-service.d.ts +1 -0
- package/dist/grpc/state-service.js +99 -102
- package/dist/grpc/sui-grpc-client.js +2 -13
- package/dist/grpc/sui_object_reader.d.ts +15 -0
- package/dist/grpc/sui_object_reader.js +60 -0
- package/dist/grpc/transaction-service.js +26 -37
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/quote/abstract_dex_quote.d.ts +60 -0
- package/dist/quote/abstract_dex_quote.js +186 -0
- package/dist/quote/chain_ops.d.ts +17 -0
- package/dist/quote/chain_ops.js +52 -0
- package/dist/quote/index.d.ts +7 -0
- package/dist/quote/index.js +7 -0
- package/dist/quote/pool_event.d.ts +21 -0
- package/dist/quote/pool_event.js +6 -0
- package/dist/quote/pricing/token_price_cache.js +18 -29
- package/dist/quote/quote_amount.d.ts +4 -0
- package/dist/quote/quote_amount.js +24 -0
- package/dist/quote/quote_trace.d.ts +16 -0
- package/dist/quote/quote_trace.js +40 -0
- package/dist/quote/tick/clmm_v3_engine.d.ts +32 -0
- package/dist/quote/tick/clmm_v3_engine.js +48 -0
- package/dist/quote/tick/index.d.ts +4 -0
- package/dist/quote/tick/index.js +20 -0
- package/dist/quote/tick/local_clmm_state.d.ts +17 -0
- package/dist/quote/tick/local_clmm_state.js +22 -0
- package/dist/quote/tick/sui_clmm_tick_cache.d.ts +42 -0
- package/dist/quote/tick/sui_clmm_tick_cache.js +163 -0
- package/dist/quote/tick/sui_tick_data_provider.d.ts +2 -0
- package/dist/quote/tick/sui_tick_data_provider.js +6 -0
- package/dist/quote/verify/index.d.ts +1 -0
- package/dist/quote/verify/index.js +17 -0
- package/dist/quote/verify/quote_price_verify.d.ts +30 -0
- package/dist/quote/verify/quote_price_verify.js +247 -0
- package/dist/redis/redis_client.d.ts +1 -0
- package/dist/redis/redis_client.js +88 -117
- package/dist/rpc/index.js +59 -75
- package/dist/test/test.js +1 -1
- package/dist/test/test_checkpoint.js +4 -13
- package/dist/test/test_grpc.js +32 -41
- package/dist/trade/abstract_sui_dex_trade.d.ts +43 -0
- package/dist/trade/abstract_sui_dex_trade.js +380 -0
- package/dist/trade/abstract_sui_dex_trade_plus.d.ts +3 -1
- package/dist/trade/abstract_sui_dex_trade_plus.js +232 -212
- package/dist/trade/check/tx_result_checker.js +65 -75
- package/dist/trade/coin/index.d.ts +1 -0
- package/dist/trade/coin/index.js +17 -0
- package/dist/trade/coin/lua_scripts.d.ts +5 -0
- package/dist/trade/coin/lua_scripts.js +130 -0
- package/dist/trade/coin/types.d.ts +30 -0
- package/dist/trade/coin/types.js +2 -0
- package/dist/trade/coin/wallet_coin_ledger.d.ts +22 -0
- package/dist/trade/coin/wallet_coin_ledger.js +85 -0
- package/dist/trade/executor/central_executor.d.ts +72 -0
- package/dist/trade/executor/central_executor.js +240 -0
- package/dist/trade/executor/coin_cache.d.ts +21 -0
- package/dist/trade/executor/coin_cache.js +143 -0
- package/dist/trade/executor/coin_maintainer.d.ts +32 -0
- package/dist/trade/executor/coin_maintainer.js +123 -0
- package/dist/trade/executor/core_channel.d.ts +38 -0
- package/dist/trade/executor/core_channel.js +131 -0
- package/dist/trade/executor/data_channel.d.ts +27 -0
- package/dist/trade/executor/data_channel.js +2 -0
- package/dist/trade/executor/effects.d.ts +16 -0
- package/dist/trade/executor/effects.js +63 -0
- package/dist/trade/executor/executor_client.d.ts +13 -0
- package/dist/trade/executor/executor_client.js +55 -0
- package/dist/trade/executor/executor_protocol.d.ts +26 -0
- package/dist/trade/executor/executor_protocol.js +32 -0
- package/dist/trade/executor/executor_server.d.ts +8 -0
- package/dist/trade/executor/executor_server.js +33 -0
- package/dist/trade/executor/executor_ws_client.d.ts +13 -0
- package/dist/trade/executor/executor_ws_client.js +58 -0
- package/dist/trade/executor/grpc_channel.d.ts +14 -0
- package/dist/trade/executor/grpc_channel.js +73 -0
- package/dist/trade/executor/index.d.ts +7 -0
- package/dist/trade/executor/index.js +23 -0
- package/dist/trade/executor/json_rpc_channel.d.ts +14 -0
- package/dist/trade/executor/json_rpc_channel.js +77 -0
- package/dist/trade/index.d.ts +5 -1
- package/dist/trade/index.js +5 -1
- package/dist/trade/parse/sui_tx_parser.js +98 -81
- package/dist/trade/send_tx/index.js +34 -47
- package/dist/trade/swap/builders/bluefin.d.ts +9 -0
- package/dist/trade/swap/builders/bluefin.js +60 -0
- package/dist/trade/swap/builders/cetus_magma.d.ts +13 -0
- package/dist/trade/swap/builders/cetus_magma.js +52 -0
- package/dist/trade/swap/builders/momentum.d.ts +9 -0
- package/dist/trade/swap/builders/momentum.js +80 -0
- package/dist/trade/swap/dex_swap_config.d.ts +28 -0
- package/dist/trade/swap/dex_swap_config.js +40 -0
- package/dist/trade/swap/index.d.ts +7 -0
- package/dist/trade/swap/index.js +36 -0
- package/dist/trade/swap/types.d.ts +20 -0
- package/dist/trade/swap/types.js +2 -0
- package/dist/trade/test/test_parse_sui_tx_result.js +33 -44
- package/dist/trade/tx_result_channel.d.ts +7 -0
- package/dist/trade/tx_result_channel.js +7 -0
- package/dist/utils/decode.js +1 -2
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/trade_direction.d.ts +14 -0
- package/dist/utils/trade_direction.js +23 -0
- package/package.json +3 -2
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CentralExecutor = void 0;
|
|
4
|
+
const dist_1 = require("@clonegod/ttd-core/dist");
|
|
5
|
+
const ed25519_1 = require("@mysten/sui/keypairs/ed25519");
|
|
6
|
+
const transactions_1 = require("@mysten/sui/transactions");
|
|
7
|
+
const coin_cache_1 = require("./coin_cache");
|
|
8
|
+
const effects_1 = require("./effects");
|
|
9
|
+
const swap_1 = require("../swap");
|
|
10
|
+
const constants_1 = require("../../constants");
|
|
11
|
+
class CentralExecutor {
|
|
12
|
+
constructor(core, opts = {}) {
|
|
13
|
+
this.core = core;
|
|
14
|
+
this.cache = new coin_cache_1.InProcessCoinCache();
|
|
15
|
+
this.gasAddress = '';
|
|
16
|
+
this.tradeWallets = new Map();
|
|
17
|
+
this.sharedRefCache = new Map();
|
|
18
|
+
this.seq = 0;
|
|
19
|
+
this.gasBudget = opts.gasBudget ?? BigInt(process.env.SUI_GAS_BUDGET || '50000000');
|
|
20
|
+
this.gasMinCoin = opts.gasMinCoin ?? BigInt(process.env.SUI_GAS_MIN_COIN || this.gasBudget.toString());
|
|
21
|
+
this.reconcileAfterTx = opts.reconcileAfterTx ?? true;
|
|
22
|
+
this.onBroadcastResult = opts.onBroadcastResult;
|
|
23
|
+
}
|
|
24
|
+
async init() {
|
|
25
|
+
const tradeIds = (process.env.SUI_WALLET_GROUP_IDS || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
26
|
+
const gasIds = (process.env.SUI_GAS_WALLET_GROUP_IDS || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
27
|
+
if (!tradeIds.length)
|
|
28
|
+
throw new Error('SUI_WALLET_GROUP_IDS 未配置(集中执行器需交易钱包)');
|
|
29
|
+
if (!gasIds.length)
|
|
30
|
+
throw new Error('SUI_GAS_WALLET_GROUP_IDS 未配置(集中执行器需 gas 赞助钱包)');
|
|
31
|
+
for (const info of (0, dist_1.load_wallet_multi)(tradeIds, false)) {
|
|
32
|
+
const kp = ed25519_1.Ed25519Keypair.fromSecretKey(info.private_key);
|
|
33
|
+
this.tradeWallets.set(kp.getPublicKey().toSuiAddress(), kp);
|
|
34
|
+
}
|
|
35
|
+
const gasInfos = (0, dist_1.load_wallet_multi)(gasIds, false);
|
|
36
|
+
if (!gasInfos.length)
|
|
37
|
+
throw new Error('gas 钱包加载为空');
|
|
38
|
+
this.gasKeypair = ed25519_1.Ed25519Keypair.fromSecretKey(gasInfos[0].private_key);
|
|
39
|
+
this.gasAddress = this.gasKeypair.getPublicKey().toSuiAddress();
|
|
40
|
+
await this.reconcileCoins(this.gasAddress, constants_1.SUI_TOKEN_ADDRESS.LONG);
|
|
41
|
+
(0, dist_1.log_info)(`[executor] init: trade=${[...this.tradeWallets.keys()].join(',')}, gas=${this.gasAddress}, gasBudget=${this.gasBudget}`);
|
|
42
|
+
}
|
|
43
|
+
async reconcileCoins(wallet, coinType) {
|
|
44
|
+
try {
|
|
45
|
+
const refs = [];
|
|
46
|
+
let cursor = undefined;
|
|
47
|
+
do {
|
|
48
|
+
const page = await this.core.getCoins({ address: wallet, coinType, cursor });
|
|
49
|
+
for (const c of page.objects) {
|
|
50
|
+
refs.push({ objectId: c.id, version: c.version, digest: c.digest, balance: c.balance });
|
|
51
|
+
}
|
|
52
|
+
cursor = page.hasNextPage ? page.cursor : null;
|
|
53
|
+
} while (cursor);
|
|
54
|
+
this.cache.reconcile(wallet, coinType, refs);
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
(0, dist_1.log_error)(`[executor] reconcileCoins 失败 ${wallet} ${coinType}`, e);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async getSharedRefCached(objectId) {
|
|
61
|
+
let isv = this.sharedRefCache.get(objectId);
|
|
62
|
+
if (!isv) {
|
|
63
|
+
const res = await this.core.getObjects({ objectIds: [objectId] });
|
|
64
|
+
const obj = res.objects[0];
|
|
65
|
+
if (obj instanceof Error)
|
|
66
|
+
throw new Error(`[executor] getObjects(${objectId}) 失败: ${obj.message}`);
|
|
67
|
+
const owner = obj.owner;
|
|
68
|
+
if (owner.$kind !== 'Shared')
|
|
69
|
+
throw new Error(`[executor] ${objectId} 非共享对象($kind=${owner.$kind})`);
|
|
70
|
+
isv = owner.Shared.initialSharedVersion;
|
|
71
|
+
this.sharedRefCache.set(objectId, isv);
|
|
72
|
+
}
|
|
73
|
+
return isv;
|
|
74
|
+
}
|
|
75
|
+
async getGasPrice() {
|
|
76
|
+
return BigInt((await this.core.getReferenceGasPrice()).referenceGasPrice);
|
|
77
|
+
}
|
|
78
|
+
nextTag(prefix) { return `${prefix}:${Date.now()}:${++this.seq}`; }
|
|
79
|
+
inputCoinType(req) { return req.a2b ? req.coinTypeA : req.coinTypeB; }
|
|
80
|
+
outputCoinType(req) { return req.a2b ? req.coinTypeB : req.coinTypeA; }
|
|
81
|
+
chooseTradeWallet(req, coinType, amount) {
|
|
82
|
+
if (req.walletAddress) {
|
|
83
|
+
if (!this.tradeWallets.has(req.walletAddress))
|
|
84
|
+
throw new Error(`未知交易钱包: ${req.walletAddress}`);
|
|
85
|
+
return req.walletAddress;
|
|
86
|
+
}
|
|
87
|
+
let best = '';
|
|
88
|
+
let bestTotal = -1n;
|
|
89
|
+
for (const w of this.tradeWallets.keys()) {
|
|
90
|
+
const { total } = this.cache.snapshot(w, coinType);
|
|
91
|
+
if (total >= amount && total > bestTotal) {
|
|
92
|
+
best = w;
|
|
93
|
+
bestTotal = total;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (!best)
|
|
97
|
+
throw new Error(`无交易钱包持有 ≥ ${amount} 的 ${coinType}`);
|
|
98
|
+
return best;
|
|
99
|
+
}
|
|
100
|
+
async registerShared(tx, objectId, mutable) {
|
|
101
|
+
const initialSharedVersion = await this.getSharedRefCached(objectId);
|
|
102
|
+
tx.object(transactions_1.Inputs.SharedObjectRef({ objectId, initialSharedVersion, mutable }));
|
|
103
|
+
}
|
|
104
|
+
async submitSwap(req) {
|
|
105
|
+
const inType = this.inputCoinType(req);
|
|
106
|
+
const wallet = this.chooseTradeWallet(req, inType, req.amountIn);
|
|
107
|
+
const inputTag = this.nextTag('in');
|
|
108
|
+
const gasTag = this.nextTag('gas');
|
|
109
|
+
const inputRes = this.cache.acquire(wallet, inType, req.amountIn, inputTag);
|
|
110
|
+
let gasRes;
|
|
111
|
+
try {
|
|
112
|
+
gasRes = this.cache.acquireGas(this.gasAddress, constants_1.SUI_TOKEN_ADDRESS.LONG, this.gasMinCoin, gasTag);
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
this.cache.abort(inputTag, false);
|
|
116
|
+
throw e;
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
const { txBytes, tx } = await this.buildSwapTx(req, wallet, inputRes.coins, gasRes.coin);
|
|
120
|
+
const { signature: senderSig } = await this.tradeWallets.get(wallet).signTransaction(txBytes);
|
|
121
|
+
const { signature: sponsorSig } = await this.gasKeypair.signTransaction(txBytes);
|
|
122
|
+
const digest = await tx.getDigest();
|
|
123
|
+
void this.broadcastAndCommit(txBytes, [senderSig, sponsorSig], digest, wallet, inType, this.outputCoinType(req), inputRes.coins, gasRes.coin.objectId, inputTag, gasTag);
|
|
124
|
+
(0, dist_1.log_info)(`[executor] swap 已签提交 digest=${digest} dex=${req.dexId} ${req.a2b ? 'a2b' : 'b2a'} in=${req.amountIn}`);
|
|
125
|
+
return { digest, submitted: true };
|
|
126
|
+
}
|
|
127
|
+
catch (e) {
|
|
128
|
+
this.cache.abort(inputTag, false);
|
|
129
|
+
this.cache.abort(gasTag, false);
|
|
130
|
+
(0, dist_1.log_error)(`[executor] submitSwap 失败 dex=${req.dexId}`, e);
|
|
131
|
+
return { digest: '', submitted: false, error: e.message };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async broadcastAndCommit(txBytes, signatures, digest, wallet, inType, outType, inputCoins, gasCoinId, inputTag, gasTag) {
|
|
135
|
+
try {
|
|
136
|
+
const resp = await this.core.executeTransaction({ transaction: txBytes, signatures });
|
|
137
|
+
const tr = resp.transaction;
|
|
138
|
+
if (!tr?.effects) {
|
|
139
|
+
this.cache.abort(inputTag, true);
|
|
140
|
+
this.cache.abort(gasTag, true);
|
|
141
|
+
this.reconcileAfterFailure(wallet, inType, outType);
|
|
142
|
+
(0, dist_1.log_error)(`[executor] 响应缺 effects,无法更新 cache digest=${digest}`, new Error('missing effects'));
|
|
143
|
+
this.onBroadcastResult?.({ digest, success: false, error: 'missing effects' });
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const { success, error } = (0, effects_1.coreTxStatus)(tr.effects);
|
|
147
|
+
if (!success) {
|
|
148
|
+
this.cache.abort(inputTag, true);
|
|
149
|
+
this.cache.abort(gasTag, true);
|
|
150
|
+
this.reconcileAfterFailure(wallet, inType, outType);
|
|
151
|
+
(0, dist_1.log_warn)(`[executor] swap 链上失败 digest=${digest} err=${error}`);
|
|
152
|
+
this.onBroadcastResult?.({ digest, success: false, error });
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
await this.onSuccess(tr, wallet, inType, outType, inputCoins, gasCoinId, inputTag, gasTag);
|
|
156
|
+
(0, dist_1.log_info)(`[executor] swap quorum-executed 确认 digest=${digest}`);
|
|
157
|
+
this.onBroadcastResult?.({ digest, success: true });
|
|
158
|
+
}
|
|
159
|
+
catch (e) {
|
|
160
|
+
this.cache.abort(inputTag, true);
|
|
161
|
+
this.cache.abort(gasTag, true);
|
|
162
|
+
this.reconcileAfterFailure(wallet, inType, outType);
|
|
163
|
+
(0, dist_1.log_error)(`[executor] broadcast 失败 digest=${digest}`, e);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
reconcileAfterFailure(wallet, inType, outType) {
|
|
167
|
+
for (const t of new Set([inType, outType, constants_1.SUI_TOKEN_ADDRESS.LONG]))
|
|
168
|
+
void this.reconcileCoins(wallet, t);
|
|
169
|
+
void this.reconcileCoins(this.gasAddress, constants_1.SUI_TOKEN_ADDRESS.LONG);
|
|
170
|
+
}
|
|
171
|
+
async simulateSwap(req) {
|
|
172
|
+
const inType = this.inputCoinType(req);
|
|
173
|
+
const wallet = req.walletAddress ?? this.chooseTradeWallet(req, inType, req.amountIn);
|
|
174
|
+
const { coins } = this.cache.snapshot(wallet, inType);
|
|
175
|
+
if (!coins.length)
|
|
176
|
+
throw new Error(`[executor] simulate 无 ${inType} 输入币(先 reconcileCoins)`);
|
|
177
|
+
const picked = [];
|
|
178
|
+
let sum = 0n;
|
|
179
|
+
for (const c of coins) {
|
|
180
|
+
picked.push(c);
|
|
181
|
+
sum += BigInt(c.balance);
|
|
182
|
+
if (sum >= req.amountIn)
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
if (sum < req.amountIn)
|
|
186
|
+
throw new Error(`[executor] simulate 输入不足 ${sum} < ${req.amountIn}`);
|
|
187
|
+
const gasSnap = this.cache.snapshot(this.gasAddress, constants_1.SUI_TOKEN_ADDRESS.LONG);
|
|
188
|
+
const gasCoin = gasSnap.coins.find(c => BigInt(c.balance) >= this.gasMinCoin);
|
|
189
|
+
if (!gasCoin)
|
|
190
|
+
throw new Error(`[executor] simulate 无 ≥ ${this.gasMinCoin} 的 gas coin`);
|
|
191
|
+
const { txBytes } = await this.buildSwapTx(req, wallet, picked, gasCoin);
|
|
192
|
+
return (await this.core.dryRunTransaction({ transaction: txBytes })).transaction;
|
|
193
|
+
}
|
|
194
|
+
async buildSwapTx(req, wallet, inputCoins, gasCoin) {
|
|
195
|
+
const tx = new transactions_1.Transaction();
|
|
196
|
+
tx.setSender(wallet);
|
|
197
|
+
await this.registerShared(tx, req.poolId, true);
|
|
198
|
+
await this.registerShared(tx, (0, swap_1.configSharedObjectId)(req.dexId), true);
|
|
199
|
+
tx.object(transactions_1.Inputs.SharedObjectRef({ objectId: swap_1.SUI_CLOCK_ID, initialSharedVersion: '1', mutable: false }));
|
|
200
|
+
const primary = tx.object(transactions_1.Inputs.ObjectRef(inputCoins[0]));
|
|
201
|
+
if (inputCoins.length > 1) {
|
|
202
|
+
tx.mergeCoins(primary, inputCoins.slice(1).map(c => tx.object(transactions_1.Inputs.ObjectRef(c))));
|
|
203
|
+
}
|
|
204
|
+
const [inCoin] = tx.splitCoins(primary, [tx.pure.u64(req.amountIn)]);
|
|
205
|
+
const { outputCoin, leftoverCoins } = (0, swap_1.buildSwapMoveCall)(req.dexId, tx, {
|
|
206
|
+
coinTypeA: req.coinTypeA, coinTypeB: req.coinTypeB, poolId: req.poolId,
|
|
207
|
+
a2b: req.a2b, byAmountIn: true, amount: req.amountIn,
|
|
208
|
+
amountLimit: req.minOut, sqrtPriceLimit: req.sqrtPriceLimit,
|
|
209
|
+
}, inCoin);
|
|
210
|
+
tx.transferObjects([outputCoin, ...leftoverCoins], tx.pure.address(wallet));
|
|
211
|
+
tx.setGasOwner(this.gasAddress);
|
|
212
|
+
tx.setGasPayment([{ objectId: gasCoin.objectId, version: gasCoin.version, digest: gasCoin.digest }]);
|
|
213
|
+
tx.setGasBudget(this.gasBudget);
|
|
214
|
+
tx.setGasPrice(await this.getGasPrice());
|
|
215
|
+
const txBytes = await tx.build();
|
|
216
|
+
return { txBytes, tx };
|
|
217
|
+
}
|
|
218
|
+
async onSuccess(tr, wallet, inType, outType, inputCoins, gasCoinId, inputTag, gasTag) {
|
|
219
|
+
const objectTypes = await tr.objectTypes;
|
|
220
|
+
const coinTypeById = new Map();
|
|
221
|
+
for (const c of inputCoins)
|
|
222
|
+
coinTypeById.set(c.objectId, inType);
|
|
223
|
+
coinTypeById.set(gasCoinId, constants_1.SUI_TOKEN_ADDRESS.LONG);
|
|
224
|
+
const tradeChanges = (0, effects_1.extractCoinChangesFromCore)(tr.effects, objectTypes, { owners: new Set([wallet]), coinTypeById });
|
|
225
|
+
const gasChanges = (0, effects_1.extractCoinChangesFromCore)(tr.effects, objectTypes, { owners: new Set([this.gasAddress]), coinTypeById });
|
|
226
|
+
this.cache.commit(inputTag, tradeChanges);
|
|
227
|
+
this.cache.commit(gasTag, gasChanges);
|
|
228
|
+
if (this.reconcileAfterTx) {
|
|
229
|
+
for (const t of new Set([inType, outType, constants_1.SUI_TOKEN_ADDRESS.LONG]))
|
|
230
|
+
void this.reconcileCoins(wallet, t);
|
|
231
|
+
void this.reconcileCoins(this.gasAddress, constants_1.SUI_TOKEN_ADDRESS.LONG);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
get coinCache() { return this.cache; }
|
|
235
|
+
get gasWalletAddress() { return this.gasAddress; }
|
|
236
|
+
get gasSigner() { return this.gasKeypair; }
|
|
237
|
+
get tradeWalletAddresses() { return [...this.tradeWallets.keys()]; }
|
|
238
|
+
get coreClient() { return this.core; }
|
|
239
|
+
}
|
|
240
|
+
exports.CentralExecutor = CentralExecutor;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CoinRef, CoinReservation, GasReservation, CoinObjectChange } from '../coin/types';
|
|
2
|
+
export declare class InProcessCoinCache {
|
|
3
|
+
private available;
|
|
4
|
+
private inflight;
|
|
5
|
+
private walletMap;
|
|
6
|
+
private list;
|
|
7
|
+
private sortDesc;
|
|
8
|
+
seed(wallet: string, coinType: string, coins: CoinRef[]): void;
|
|
9
|
+
reconcile(wallet: string, coinType: string, freshCoins: CoinRef[]): void;
|
|
10
|
+
acquire(wallet: string, coinType: string, amount: bigint, txTag: string, maxCoins?: number): CoinReservation;
|
|
11
|
+
acquireGas(wallet: string, coinType: string, minGas: bigint, txTag: string): GasReservation;
|
|
12
|
+
commit(txTag: string, changes: CoinObjectChange[]): void;
|
|
13
|
+
abort(txTag: string, consumed: boolean): void;
|
|
14
|
+
private removeEverywhere;
|
|
15
|
+
snapshot(wallet: string, coinType: string): {
|
|
16
|
+
count: number;
|
|
17
|
+
total: bigint;
|
|
18
|
+
coins: CoinRef[];
|
|
19
|
+
};
|
|
20
|
+
inflightCount(): number;
|
|
21
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InProcessCoinCache = void 0;
|
|
4
|
+
const dist_1 = require("@clonegod/ttd-core/dist");
|
|
5
|
+
class InProcessCoinCache {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.available = new Map();
|
|
8
|
+
this.inflight = new Map();
|
|
9
|
+
}
|
|
10
|
+
walletMap(wallet) {
|
|
11
|
+
let m = this.available.get(wallet);
|
|
12
|
+
if (!m) {
|
|
13
|
+
m = new Map();
|
|
14
|
+
this.available.set(wallet, m);
|
|
15
|
+
}
|
|
16
|
+
return m;
|
|
17
|
+
}
|
|
18
|
+
list(wallet, coinType) {
|
|
19
|
+
const m = this.walletMap(wallet);
|
|
20
|
+
let l = m.get(coinType);
|
|
21
|
+
if (!l) {
|
|
22
|
+
l = [];
|
|
23
|
+
m.set(coinType, l);
|
|
24
|
+
}
|
|
25
|
+
return l;
|
|
26
|
+
}
|
|
27
|
+
sortDesc(l) {
|
|
28
|
+
l.sort((a, b) => (BigInt(b.balance) > BigInt(a.balance) ? 1 : BigInt(b.balance) < BigInt(a.balance) ? -1 : 0));
|
|
29
|
+
}
|
|
30
|
+
seed(wallet, coinType, coins) {
|
|
31
|
+
const l = coins.slice();
|
|
32
|
+
this.sortDesc(l);
|
|
33
|
+
this.walletMap(wallet).set(coinType, l);
|
|
34
|
+
(0, dist_1.log_info)(`[coin-cache] seed ${wallet} ${coinType}: ${l.length} coins`);
|
|
35
|
+
}
|
|
36
|
+
reconcile(wallet, coinType, freshCoins) {
|
|
37
|
+
const inflightIds = new Set();
|
|
38
|
+
for (const r of this.inflight.values()) {
|
|
39
|
+
if (r.wallet === wallet && r.coinType === coinType)
|
|
40
|
+
r.coins.forEach(c => inflightIds.add(c.objectId));
|
|
41
|
+
}
|
|
42
|
+
const kept = freshCoins.filter(c => !inflightIds.has(c.objectId));
|
|
43
|
+
this.sortDesc(kept);
|
|
44
|
+
this.walletMap(wallet).set(coinType, kept);
|
|
45
|
+
(0, dist_1.log_info)(`[coin-cache] reconcile ${wallet} ${coinType}: ${kept.length} avail (${inflightIds.size} inflight kept)`);
|
|
46
|
+
}
|
|
47
|
+
acquire(wallet, coinType, amount, txTag, maxCoins = 8) {
|
|
48
|
+
if (this.inflight.has(txTag))
|
|
49
|
+
throw new Error(`[coin-cache] txTag 重复: ${txTag}`);
|
|
50
|
+
const l = this.list(wallet, coinType);
|
|
51
|
+
const picked = [];
|
|
52
|
+
let sum = 0n;
|
|
53
|
+
for (const c of l) {
|
|
54
|
+
if (sum >= amount)
|
|
55
|
+
break;
|
|
56
|
+
picked.push(c);
|
|
57
|
+
sum += BigInt(c.balance);
|
|
58
|
+
if (picked.length >= maxCoins && sum < amount) {
|
|
59
|
+
throw new Error(`[coin-cache] ${wallet} ${coinType} 碎片化:${maxCoins} 个 coin 仅凑 ${sum} < ${amount}(需先 merge)`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (sum < amount) {
|
|
63
|
+
throw new Error(`[coin-cache] ${wallet} ${coinType} 余额不足:可用 ${sum} < 需 ${amount}`);
|
|
64
|
+
}
|
|
65
|
+
const pickedIds = new Set(picked.map(c => c.objectId));
|
|
66
|
+
this.walletMap(wallet).set(coinType, l.filter(c => !pickedIds.has(c.objectId)));
|
|
67
|
+
this.inflight.set(txTag, { wallet, coinType, coins: picked, gas: false });
|
|
68
|
+
return { txTag, coinType, coins: picked };
|
|
69
|
+
}
|
|
70
|
+
acquireGas(wallet, coinType, minGas, txTag) {
|
|
71
|
+
if (this.inflight.has(txTag))
|
|
72
|
+
throw new Error(`[coin-cache] gas txTag 重复: ${txTag}`);
|
|
73
|
+
const l = this.list(wallet, coinType);
|
|
74
|
+
let chosen;
|
|
75
|
+
for (let i = l.length - 1; i >= 0; i--) {
|
|
76
|
+
if (BigInt(l[i].balance) >= minGas) {
|
|
77
|
+
chosen = l[i];
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (!chosen)
|
|
82
|
+
throw new Error(`[coin-cache] gas 钱包 ${wallet} 无 ≥ ${minGas} 的 gas coin(需 split 补给)`);
|
|
83
|
+
this.walletMap(wallet).set(coinType, l.filter(c => c.objectId !== chosen.objectId));
|
|
84
|
+
this.inflight.set(txTag, { wallet, coinType, coins: [chosen], gas: true });
|
|
85
|
+
return { txTag, coin: chosen };
|
|
86
|
+
}
|
|
87
|
+
commit(txTag, changes) {
|
|
88
|
+
const res = this.inflight.get(txTag);
|
|
89
|
+
if (!res) {
|
|
90
|
+
(0, dist_1.log_warn)(`[coin-cache] commit 未知 txTag: ${txTag}`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
this.inflight.delete(txTag);
|
|
94
|
+
for (const ch of changes) {
|
|
95
|
+
const wallet = res.wallet;
|
|
96
|
+
if (ch.kind === 'deleted') {
|
|
97
|
+
this.removeEverywhere(wallet, ch.coinType, ch.objectId);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (ch.version == null || ch.digest == null) {
|
|
101
|
+
(0, dist_1.log_warn)(`[coin-cache] commit 跳过缺 version/digest 的 ${ch.kind} ${ch.objectId}`);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const old = this.list(wallet, ch.coinType).find(c => c.objectId === ch.objectId);
|
|
105
|
+
const balance = ch.balance ?? old?.balance ?? '0';
|
|
106
|
+
const ref = { objectId: ch.objectId, version: ch.version, digest: ch.digest, balance };
|
|
107
|
+
this.removeEverywhere(wallet, ch.coinType, ch.objectId);
|
|
108
|
+
const l = this.list(wallet, ch.coinType);
|
|
109
|
+
l.push(ref);
|
|
110
|
+
this.sortDesc(l);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
abort(txTag, consumed) {
|
|
114
|
+
const res = this.inflight.get(txTag);
|
|
115
|
+
if (!res) {
|
|
116
|
+
(0, dist_1.log_warn)(`[coin-cache] abort 未知 txTag: ${txTag}`);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
this.inflight.delete(txTag);
|
|
120
|
+
if (consumed) {
|
|
121
|
+
(0, dist_1.log_warn)(`[coin-cache] abort consumed txTag=${txTag}(${res.coins.length} coin 交 reconcile 兜底)`);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const l = this.list(res.wallet, res.coinType);
|
|
125
|
+
for (const c of res.coins)
|
|
126
|
+
if (!l.find(x => x.objectId === c.objectId))
|
|
127
|
+
l.push(c);
|
|
128
|
+
this.sortDesc(l);
|
|
129
|
+
}
|
|
130
|
+
removeEverywhere(wallet, coinType, objectId) {
|
|
131
|
+
const l = this.list(wallet, coinType);
|
|
132
|
+
const idx = l.findIndex(c => c.objectId === objectId);
|
|
133
|
+
if (idx >= 0)
|
|
134
|
+
l.splice(idx, 1);
|
|
135
|
+
}
|
|
136
|
+
snapshot(wallet, coinType) {
|
|
137
|
+
const l = this.list(wallet, coinType);
|
|
138
|
+
const total = l.reduce((s, c) => s + BigInt(c.balance), 0n);
|
|
139
|
+
return { count: l.length, total, coins: l.slice() };
|
|
140
|
+
}
|
|
141
|
+
inflightCount() { return this.inflight.size; }
|
|
142
|
+
}
|
|
143
|
+
exports.InProcessCoinCache = InProcessCoinCache;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
|
|
2
|
+
import { CentralExecutor } from './central_executor';
|
|
3
|
+
import { ExecutorCore } from './core_channel';
|
|
4
|
+
export interface CoinMaintainerOptions {
|
|
5
|
+
gasTarget?: number;
|
|
6
|
+
gasMin?: number;
|
|
7
|
+
gasMax?: number;
|
|
8
|
+
gasCoinSize?: bigint;
|
|
9
|
+
intervalMs?: number;
|
|
10
|
+
maintainGasBudget?: bigint;
|
|
11
|
+
}
|
|
12
|
+
export declare class CoinMaintainer {
|
|
13
|
+
private readonly core;
|
|
14
|
+
private readonly gasKeypair;
|
|
15
|
+
private readonly executor;
|
|
16
|
+
private readonly gasTarget;
|
|
17
|
+
private readonly gasMin;
|
|
18
|
+
private readonly gasMax;
|
|
19
|
+
private readonly gasCoinSize;
|
|
20
|
+
private readonly intervalMs;
|
|
21
|
+
private readonly maintainGasBudget;
|
|
22
|
+
private timer;
|
|
23
|
+
private running;
|
|
24
|
+
constructor(core: ExecutorCore, gasKeypair: Ed25519Keypair, executor: CentralExecutor, opts?: CoinMaintainerOptions);
|
|
25
|
+
start(): void;
|
|
26
|
+
stop(): void;
|
|
27
|
+
maintainGasPool(): Promise<void>;
|
|
28
|
+
private splitGasCoins;
|
|
29
|
+
private mergeGasCoins;
|
|
30
|
+
private sortedDesc;
|
|
31
|
+
private buildAndSend;
|
|
32
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CoinMaintainer = void 0;
|
|
4
|
+
const dist_1 = require("@clonegod/ttd-core/dist");
|
|
5
|
+
const transactions_1 = require("@mysten/sui/transactions");
|
|
6
|
+
const effects_1 = require("./effects");
|
|
7
|
+
const constants_1 = require("../../constants");
|
|
8
|
+
class CoinMaintainer {
|
|
9
|
+
constructor(core, gasKeypair, executor, opts = {}) {
|
|
10
|
+
this.core = core;
|
|
11
|
+
this.gasKeypair = gasKeypair;
|
|
12
|
+
this.executor = executor;
|
|
13
|
+
this.timer = null;
|
|
14
|
+
this.running = false;
|
|
15
|
+
this.gasTarget = opts.gasTarget ?? Number(process.env.SUI_GAS_POOL_TARGET || 8);
|
|
16
|
+
this.gasMin = opts.gasMin ?? Number(process.env.SUI_GAS_POOL_MIN || 5);
|
|
17
|
+
this.gasMax = opts.gasMax ?? Number(process.env.SUI_GAS_POOL_MAX || 10);
|
|
18
|
+
this.gasCoinSize = opts.gasCoinSize ?? BigInt(process.env.SUI_GAS_COIN_SIZE || '150000000');
|
|
19
|
+
this.intervalMs = opts.intervalMs ?? Number(process.env.SUI_COIN_MAINTAIN_INTERVAL_MS || 30000);
|
|
20
|
+
this.maintainGasBudget = opts.maintainGasBudget ?? BigInt(process.env.SUI_MAINTAIN_GAS_BUDGET || '20000000');
|
|
21
|
+
}
|
|
22
|
+
start() {
|
|
23
|
+
if (this.timer)
|
|
24
|
+
return;
|
|
25
|
+
(0, dist_1.log_info)(`[maintainer] start: gas target=${this.gasTarget}[${this.gasMin}-${this.gasMax}], size=${this.gasCoinSize}, interval=${this.intervalMs}ms`);
|
|
26
|
+
const tick = async () => {
|
|
27
|
+
if (this.running)
|
|
28
|
+
return;
|
|
29
|
+
this.running = true;
|
|
30
|
+
try {
|
|
31
|
+
await this.maintainGasPool();
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
(0, dist_1.log_error)('[maintainer] tick 失败', e);
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
this.running = false;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
void tick();
|
|
41
|
+
this.timer = setInterval(tick, this.intervalMs);
|
|
42
|
+
}
|
|
43
|
+
stop() { if (this.timer) {
|
|
44
|
+
clearInterval(this.timer);
|
|
45
|
+
this.timer = null;
|
|
46
|
+
} }
|
|
47
|
+
async maintainGasPool() {
|
|
48
|
+
const gasAddr = this.executor.gasWalletAddress;
|
|
49
|
+
const snap = this.executor.coinCache.snapshot(gasAddr, constants_1.SUI_TOKEN_ADDRESS.LONG);
|
|
50
|
+
const count = snap.count;
|
|
51
|
+
if (count >= this.gasMin && count <= this.gasMax)
|
|
52
|
+
return;
|
|
53
|
+
if (count < this.gasMin)
|
|
54
|
+
await this.splitGasCoins(gasAddr, snap.coins, this.gasTarget - count);
|
|
55
|
+
else
|
|
56
|
+
await this.mergeGasCoins(gasAddr, snap.coins, count - this.gasTarget);
|
|
57
|
+
await this.executor.reconcileCoins(gasAddr, constants_1.SUI_TOKEN_ADDRESS.LONG);
|
|
58
|
+
}
|
|
59
|
+
async splitGasCoins(gasAddr, coins, n) {
|
|
60
|
+
if (n <= 0)
|
|
61
|
+
return;
|
|
62
|
+
const sorted = this.sortedDesc(coins);
|
|
63
|
+
const src = sorted[0];
|
|
64
|
+
const gasPay = sorted[1];
|
|
65
|
+
if (!src || !gasPay) {
|
|
66
|
+
(0, dist_1.log_warn)('[maintainer] gas coin 不足 2 个,无法独立挑 gas payment 做 split');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const need = this.gasCoinSize * BigInt(n);
|
|
70
|
+
if (BigInt(src.balance) < need) {
|
|
71
|
+
(0, dist_1.log_warn)(`[maintainer] gas 源 coin ${src.balance} 不足 split ${n} × ${this.gasCoinSize}=${need}`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const tx = new transactions_1.Transaction();
|
|
75
|
+
tx.setSender(gasAddr);
|
|
76
|
+
const srcCoin = tx.object(transactions_1.Inputs.ObjectRef(src));
|
|
77
|
+
const amounts = Array.from({ length: n }, () => tx.pure.u64(this.gasCoinSize));
|
|
78
|
+
const newCoins = tx.splitCoins(srcCoin, amounts);
|
|
79
|
+
tx.transferObjects(Array.from({ length: n }, (_, i) => newCoins[i]), tx.pure.address(gasAddr));
|
|
80
|
+
await this.buildAndSend(tx, gasAddr, gasPay, `split ${n} gas coins`);
|
|
81
|
+
}
|
|
82
|
+
async mergeGasCoins(gasAddr, coins, n) {
|
|
83
|
+
if (n <= 0)
|
|
84
|
+
return;
|
|
85
|
+
const sorted = this.sortedDesc(coins);
|
|
86
|
+
const primary = sorted[0];
|
|
87
|
+
const toMerge = sorted.slice(-n).filter(c => c.objectId !== primary.objectId);
|
|
88
|
+
if (!toMerge.length)
|
|
89
|
+
return;
|
|
90
|
+
const mergeIds = new Set(toMerge.map(c => c.objectId));
|
|
91
|
+
const gasPay = sorted.find(c => c.objectId !== primary.objectId && !mergeIds.has(c.objectId));
|
|
92
|
+
if (!gasPay) {
|
|
93
|
+
(0, dist_1.log_warn)('[maintainer] 无空闲 gas coin 付 merge 交易 gas');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const tx = new transactions_1.Transaction();
|
|
97
|
+
tx.setSender(gasAddr);
|
|
98
|
+
const primaryArg = tx.object(transactions_1.Inputs.ObjectRef(primary));
|
|
99
|
+
tx.mergeCoins(primaryArg, toMerge.map(c => tx.object(transactions_1.Inputs.ObjectRef(c))));
|
|
100
|
+
await this.buildAndSend(tx, gasAddr, gasPay, `merge ${toMerge.length} gas coins`);
|
|
101
|
+
}
|
|
102
|
+
sortedDesc(coins) {
|
|
103
|
+
return coins.slice().sort((a, b) => (BigInt(b.balance) > BigInt(a.balance) ? 1 : BigInt(b.balance) < BigInt(a.balance) ? -1 : 0));
|
|
104
|
+
}
|
|
105
|
+
async buildAndSend(tx, gasAddr, gasPay, label) {
|
|
106
|
+
try {
|
|
107
|
+
tx.setGasOwner(gasAddr);
|
|
108
|
+
tx.setGasPayment([{ objectId: gasPay.objectId, version: gasPay.version, digest: gasPay.digest }]);
|
|
109
|
+
tx.setGasBudget(this.maintainGasBudget);
|
|
110
|
+
tx.setGasPrice(BigInt((await this.core.getReferenceGasPrice()).referenceGasPrice));
|
|
111
|
+
const bytes = await tx.build();
|
|
112
|
+
const { signature } = await this.gasKeypair.signTransaction(bytes);
|
|
113
|
+
const resp = await this.core.executeTransaction({ transaction: bytes, signatures: [signature] });
|
|
114
|
+
const tr = resp.transaction;
|
|
115
|
+
const { success, error } = (0, effects_1.coreTxStatus)(tr.effects);
|
|
116
|
+
(0, dist_1.log_info)(`[maintainer] ${label} ${success ? 'OK' : 'FAILED'} digest=${tr.digest}${error ? ' err=' + error : ''}`);
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
(0, dist_1.log_error)(`[maintainer] ${label} 失败`, e);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.CoinMaintainer = CoinMaintainer;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Experimental_CoreClient, Experimental_SuiClientTypes } from '@mysten/sui/experimental';
|
|
2
|
+
export interface GrpcCoreOptions {
|
|
3
|
+
endpoint?: string;
|
|
4
|
+
token?: string;
|
|
5
|
+
network?: 'mainnet' | 'testnet' | 'devnet' | 'localnet';
|
|
6
|
+
}
|
|
7
|
+
export declare function buildGrpcCore(opts?: GrpcCoreOptions): Experimental_CoreClient;
|
|
8
|
+
export interface GraphqlCoreOptions {
|
|
9
|
+
url?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function buildGraphqlCore(opts?: GraphqlCoreOptions): Experimental_CoreClient;
|
|
12
|
+
export declare function buildDefaultCore(): Experimental_CoreClient;
|
|
13
|
+
export type ExecutorCore = Pick<Experimental_CoreClient, 'getCoins' | 'getObjects' | 'executeTransaction' | 'dryRunTransaction'> & {
|
|
14
|
+
getReferenceGasPrice(): Promise<Experimental_SuiClientTypes.GetReferenceGasPriceResponse>;
|
|
15
|
+
};
|
|
16
|
+
export interface ResilientCoreOptions {
|
|
17
|
+
retries?: number;
|
|
18
|
+
readDeadlineMs?: number;
|
|
19
|
+
execDeadlineMs?: number;
|
|
20
|
+
gasPriceTtlMs?: number;
|
|
21
|
+
}
|
|
22
|
+
export declare class ResilientCore implements ExecutorCore {
|
|
23
|
+
private readonly primary;
|
|
24
|
+
private readonly fallback?;
|
|
25
|
+
private readonly retries;
|
|
26
|
+
private readonly readDeadlineMs;
|
|
27
|
+
private readonly execDeadlineMs;
|
|
28
|
+
private readonly gasPriceTtlMs;
|
|
29
|
+
private gasPriceCache?;
|
|
30
|
+
constructor(primary: Experimental_CoreClient, fallback?: Experimental_CoreClient, opts?: ResilientCoreOptions);
|
|
31
|
+
private read;
|
|
32
|
+
getCoins(o: Experimental_SuiClientTypes.GetCoinsOptions): Promise<Experimental_SuiClientTypes.GetCoinsResponse>;
|
|
33
|
+
getObjects(o: Experimental_SuiClientTypes.GetObjectsOptions): Promise<Experimental_SuiClientTypes.GetObjectsResponse>;
|
|
34
|
+
dryRunTransaction(o: Experimental_SuiClientTypes.DryRunTransactionOptions): Promise<Experimental_SuiClientTypes.DryRunTransactionResponse>;
|
|
35
|
+
getReferenceGasPrice(): Promise<Experimental_SuiClientTypes.GetReferenceGasPriceResponse>;
|
|
36
|
+
executeTransaction(o: Experimental_SuiClientTypes.ExecuteTransactionOptions): Promise<Experimental_SuiClientTypes.ExecuteTransactionResponse>;
|
|
37
|
+
}
|
|
38
|
+
export declare function buildResilientCore(opts?: ResilientCoreOptions): ResilientCore;
|