dipcoin-cli 1.3.4 → 1.3.5
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/cli.cjs +145 -50
- package/dist/cli.cjs.map +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -12921,8 +12921,8 @@ async function signMessage(keypair, messageBytes) {
|
|
|
12921
12921
|
*/
|
|
12922
12922
|
function buildSignature(signature, isKeyPair = false) {
|
|
12923
12923
|
const signatureData = cryptography.parseSerializedSignature(signature);
|
|
12924
|
-
|
|
12925
|
-
|
|
12924
|
+
const signatureHex = buffer.Buffer.from(signatureData.signature).toString("hex");
|
|
12925
|
+
const publicKey = buffer.Buffer.from(signatureData.publicKey).toString("base64");
|
|
12926
12926
|
let flag = SignerTypes.KP_SECP256;
|
|
12927
12927
|
if (signatureData.signatureScheme === "Secp256k1" ||
|
|
12928
12928
|
signatureData.signatureScheme === "Secp256r1") {
|
|
@@ -13006,13 +13006,11 @@ function getModuleDir() {
|
|
|
13006
13006
|
return path__default["default"].dirname(__filename);
|
|
13007
13007
|
}
|
|
13008
13008
|
}
|
|
13009
|
-
catch
|
|
13009
|
+
catch {
|
|
13010
13010
|
// Fall through to CommonJS
|
|
13011
13011
|
}
|
|
13012
13012
|
// CommonJS: use __dirname (will be available after compilation)
|
|
13013
|
-
// @ts-ignore - __dirname may not be defined in ESM context
|
|
13014
13013
|
if (typeof __dirname !== "undefined") {
|
|
13015
|
-
// @ts-ignore
|
|
13016
13014
|
return __dirname;
|
|
13017
13015
|
}
|
|
13018
13016
|
// Fallback to process.cwd()
|
|
@@ -16457,8 +16455,12 @@ class HttpClient {
|
|
|
16457
16455
|
const proc = child_process.spawn("curl", args);
|
|
16458
16456
|
let stdout = "";
|
|
16459
16457
|
let stderr = "";
|
|
16460
|
-
proc.stdout.on("data", (chunk) => {
|
|
16461
|
-
|
|
16458
|
+
proc.stdout.on("data", (chunk) => {
|
|
16459
|
+
stdout += chunk;
|
|
16460
|
+
});
|
|
16461
|
+
proc.stderr.on("data", (chunk) => {
|
|
16462
|
+
stderr += chunk;
|
|
16463
|
+
});
|
|
16462
16464
|
proc.on("close", (code) => {
|
|
16463
16465
|
if (!stdout) {
|
|
16464
16466
|
return reject(new Error(stderr || `curl exited with code ${code}`));
|
|
@@ -16806,17 +16808,87 @@ function buildSetOraclePriceTx(deployment, args, tx, gasBudget, sender) {
|
|
|
16806
16808
|
return t;
|
|
16807
16809
|
}
|
|
16808
16810
|
|
|
16811
|
+
// Copyright (c) 2025 Dipcoin LLC
|
|
16812
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
16813
|
+
const SUI_COIN_TYPE = "0x2::sui::SUI";
|
|
16814
|
+
const STALE_GAS_RETRY_DELAY_MS = 1000;
|
|
16815
|
+
function sleep(ms) {
|
|
16816
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
16817
|
+
}
|
|
16818
|
+
function getErrorMessage(error) {
|
|
16819
|
+
if (error instanceof Error)
|
|
16820
|
+
return error.message;
|
|
16821
|
+
return String(error);
|
|
16822
|
+
}
|
|
16823
|
+
function isStaleObjectVersionError(error) {
|
|
16824
|
+
const message = getErrorMessage(error);
|
|
16825
|
+
return (message.includes("Transaction needs to be rebuilt") ||
|
|
16826
|
+
message.includes("unavailable for consumption") ||
|
|
16827
|
+
message.includes("current version:"));
|
|
16828
|
+
}
|
|
16829
|
+
async function getFreshGasObjectRef(suiClient, owner) {
|
|
16830
|
+
const coins = [];
|
|
16831
|
+
let cursor;
|
|
16832
|
+
do {
|
|
16833
|
+
const page = await suiClient.getCoins({ owner, coinType: SUI_COIN_TYPE, cursor });
|
|
16834
|
+
coins.push(...page.data);
|
|
16835
|
+
cursor = page.hasNextPage ? page.nextCursor : null;
|
|
16836
|
+
} while (cursor);
|
|
16837
|
+
if (!coins.length) {
|
|
16838
|
+
throw new Error(`No SUI gas coins found for ${owner}`);
|
|
16839
|
+
}
|
|
16840
|
+
const gasCoin = coins.slice().sort((a, b) => {
|
|
16841
|
+
const aBalance = BigInt(a.balance);
|
|
16842
|
+
const bBalance = BigInt(b.balance);
|
|
16843
|
+
if (aBalance === bBalance)
|
|
16844
|
+
return 0;
|
|
16845
|
+
return aBalance < bBalance ? 1 : -1;
|
|
16846
|
+
})[0];
|
|
16847
|
+
const fresh = await suiClient.getObject({ id: gasCoin.coinObjectId });
|
|
16848
|
+
const ref = fresh.data;
|
|
16849
|
+
if (!ref?.objectId || !ref.version || !ref.digest) {
|
|
16850
|
+
throw new Error(`Failed to refresh gas coin object ref for ${gasCoin.coinObjectId}`);
|
|
16851
|
+
}
|
|
16852
|
+
return {
|
|
16853
|
+
objectId: ref.objectId,
|
|
16854
|
+
version: ref.version,
|
|
16855
|
+
digest: ref.digest,
|
|
16856
|
+
};
|
|
16857
|
+
}
|
|
16858
|
+
async function setFreshGasPayment(suiClient, tx, owner) {
|
|
16859
|
+
tx.setGasPayment([await getFreshGasObjectRef(suiClient, owner)]);
|
|
16860
|
+
}
|
|
16861
|
+
async function signAndExecuteTransactionWithFreshGas(suiClient, tx, signer, options) {
|
|
16862
|
+
const sender = signer.getPublicKey().toSuiAddress();
|
|
16863
|
+
tx.setSender(sender);
|
|
16864
|
+
await setFreshGasPayment(suiClient, tx, sender);
|
|
16865
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
16866
|
+
try {
|
|
16867
|
+
return await suiClient.signAndExecuteTransaction({
|
|
16868
|
+
signer,
|
|
16869
|
+
transaction: tx,
|
|
16870
|
+
options,
|
|
16871
|
+
});
|
|
16872
|
+
}
|
|
16873
|
+
catch (error) {
|
|
16874
|
+
if (attempt === 0 && isStaleObjectVersionError(error)) {
|
|
16875
|
+
await sleep(STALE_GAS_RETRY_DELAY_MS);
|
|
16876
|
+
await setFreshGasPayment(suiClient, tx, sender);
|
|
16877
|
+
continue;
|
|
16878
|
+
}
|
|
16879
|
+
throw error;
|
|
16880
|
+
}
|
|
16881
|
+
}
|
|
16882
|
+
throw new Error("Transaction failed after refreshing gas payment");
|
|
16883
|
+
}
|
|
16884
|
+
|
|
16809
16885
|
// Copyright (c) 2025 Dipcoin LLC
|
|
16810
16886
|
async function executeTxBlock(suiClient, tx, signer) {
|
|
16811
|
-
return suiClient
|
|
16812
|
-
|
|
16813
|
-
|
|
16814
|
-
|
|
16815
|
-
|
|
16816
|
-
showEffects: true,
|
|
16817
|
-
showEvents: true,
|
|
16818
|
-
showInput: true,
|
|
16819
|
-
},
|
|
16887
|
+
return signAndExecuteTransactionWithFreshGas(suiClient, tx, signer, {
|
|
16888
|
+
showObjectChanges: true,
|
|
16889
|
+
showEffects: true,
|
|
16890
|
+
showEvents: true,
|
|
16891
|
+
showInput: true,
|
|
16820
16892
|
});
|
|
16821
16893
|
}
|
|
16822
16894
|
function getDeploymentPerpetualID(deployment, market) {
|
|
@@ -16825,7 +16897,8 @@ function getDeploymentPerpetualID(deployment, market) {
|
|
|
16825
16897
|
async function getOraclePrice(suiClient, deployment, market) {
|
|
16826
16898
|
const objId = getPriceOracleObjectId(deployment, market);
|
|
16827
16899
|
const obj = await suiClient.getObject({ id: objId, options: { showContent: true } });
|
|
16828
|
-
const fields = obj.data?.content?.fields?.price_info?.fields?.price_feed?.fields?.price
|
|
16900
|
+
const fields = obj.data?.content?.fields?.price_info?.fields?.price_feed?.fields?.price
|
|
16901
|
+
?.fields;
|
|
16829
16902
|
if (!fields)
|
|
16830
16903
|
throw new Error(`Failed to read oracle price for ${market}`);
|
|
16831
16904
|
return Number(fields.price.fields.magnitude) / Math.pow(10, Number(fields.expo.fields.magnitude));
|
|
@@ -17784,9 +17857,7 @@ class DipCoinPerpSDK {
|
|
|
17784
17857
|
return {
|
|
17785
17858
|
status: false,
|
|
17786
17859
|
data: results,
|
|
17787
|
-
error: results.tpResult?.message ||
|
|
17788
|
-
results.slResult?.message ||
|
|
17789
|
-
"Failed to place TP/SL order",
|
|
17860
|
+
error: results.tpResult?.message || results.slResult?.message || "Failed to place TP/SL order",
|
|
17790
17861
|
};
|
|
17791
17862
|
}
|
|
17792
17863
|
catch (error) {
|
|
@@ -18355,12 +18426,8 @@ class DipCoinPerpSDK {
|
|
|
18355
18426
|
tpOrderPrice: toNormal(raw.tpOrderPrice),
|
|
18356
18427
|
slTriggerPrice: toNormal(raw.slTriggerPrice),
|
|
18357
18428
|
slOrderPrice: toNormal(raw.slOrderPrice),
|
|
18358
|
-
tpPlanId: planOrderType === "takeProfit"
|
|
18359
|
-
|
|
18360
|
-
: raw.tpPlanId ?? null,
|
|
18361
|
-
slPlanId: planOrderType === "stopLoss"
|
|
18362
|
-
? raw.slPlanId ?? raw.id ?? null
|
|
18363
|
-
: raw.slPlanId ?? null,
|
|
18429
|
+
tpPlanId: planOrderType === "takeProfit" ? raw.tpPlanId ?? raw.id ?? null : raw.tpPlanId ?? null,
|
|
18430
|
+
slPlanId: planOrderType === "stopLoss" ? raw.slPlanId ?? raw.id ?? null : raw.slPlanId ?? null,
|
|
18364
18431
|
tpslType: raw.tpslType,
|
|
18365
18432
|
createdAt: raw.createdAt,
|
|
18366
18433
|
updatedAt: raw.updatedAt,
|
|
@@ -18713,7 +18780,7 @@ class DipCoinPerpSDK {
|
|
|
18713
18780
|
* Build ExchangeOnChain call args for margin adjustments
|
|
18714
18781
|
*/
|
|
18715
18782
|
buildMarginCallArgs(params, action) {
|
|
18716
|
-
const { amount, accountAddress, symbol, market, perpId, subAccountsMapId, gasBudget, txHash
|
|
18783
|
+
const { amount, accountAddress, symbol, market, perpId, subAccountsMapId, gasBudget, txHash } = params;
|
|
18717
18784
|
if (!this.isPositiveNumber(amount)) {
|
|
18718
18785
|
throw new Error(`Amount must be greater than zero to ${action} margin`);
|
|
18719
18786
|
}
|
|
@@ -18869,7 +18936,8 @@ class DipCoinPerpSDK {
|
|
|
18869
18936
|
}
|
|
18870
18937
|
async buildMarginTransaction(params, action) {
|
|
18871
18938
|
const payload = this.buildMarginCallArgs(params, action);
|
|
18872
|
-
const signedMarket = payload.perpID ||
|
|
18939
|
+
const signedMarket = payload.perpID ||
|
|
18940
|
+
(payload.market ? this.resolvePerpIdFromDeployment(payload.market) : undefined);
|
|
18873
18941
|
if (!signedMarket) {
|
|
18874
18942
|
throw new Error("PerpetualID is required for signed margin payload");
|
|
18875
18943
|
}
|
|
@@ -19106,7 +19174,10 @@ class DipCoinPerpSDK {
|
|
|
19106
19174
|
if (!metadata) {
|
|
19107
19175
|
return { status: false, error: "Coin metadata not found" };
|
|
19108
19176
|
}
|
|
19109
|
-
return {
|
|
19177
|
+
return {
|
|
19178
|
+
status: true,
|
|
19179
|
+
data: { decimals: metadata.decimals, symbol: metadata.symbol, name: metadata.name },
|
|
19180
|
+
};
|
|
19110
19181
|
}
|
|
19111
19182
|
catch (error) {
|
|
19112
19183
|
return { status: false, error: formatError(error) };
|
|
@@ -19220,7 +19291,8 @@ class DipCoinPerpSDK {
|
|
|
19220
19291
|
// to catch up before submitting the PTB. Public RPC backends can disagree by
|
|
19221
19292
|
// a few seconds, so target a timestamp that is already ~10s old.
|
|
19222
19293
|
const start = Date.now();
|
|
19223
|
-
|
|
19294
|
+
const deadline = start + 180_000;
|
|
19295
|
+
while (Date.now() <= deadline) {
|
|
19224
19296
|
const clock = await this.suiClient.getObject({
|
|
19225
19297
|
id: "0x6",
|
|
19226
19298
|
options: { showContent: true },
|
|
@@ -19231,7 +19303,7 @@ class DipCoinPerpSDK {
|
|
|
19231
19303
|
const waitMs = timestamp - clockMs + 10_000;
|
|
19232
19304
|
if (waitMs <= 0)
|
|
19233
19305
|
return;
|
|
19234
|
-
if (Date.now()
|
|
19306
|
+
if (Date.now() + waitMs > deadline) {
|
|
19235
19307
|
throw new Error(`Signed price feed is too far ahead of Sui Clock (${Math.ceil(waitMs / 1000)}s). Try again later.`);
|
|
19236
19308
|
}
|
|
19237
19309
|
await this.sleep(Math.min(waitMs, 15_000));
|
|
@@ -19244,7 +19316,8 @@ class DipCoinPerpSDK {
|
|
|
19244
19316
|
const maxTimestamp = Math.max(...timestamps);
|
|
19245
19317
|
const minTimestamp = Math.min(...timestamps);
|
|
19246
19318
|
const start = Date.now();
|
|
19247
|
-
|
|
19319
|
+
const deadline = start + 180_000;
|
|
19320
|
+
while (Date.now() <= deadline) {
|
|
19248
19321
|
const clock = await this.suiClient.getObject({
|
|
19249
19322
|
id: "0x6",
|
|
19250
19323
|
options: { showContent: true },
|
|
@@ -19259,7 +19332,7 @@ class DipCoinPerpSDK {
|
|
|
19259
19332
|
}
|
|
19260
19333
|
return;
|
|
19261
19334
|
}
|
|
19262
|
-
if (Date.now()
|
|
19335
|
+
if (Date.now() + waitMs > deadline) {
|
|
19263
19336
|
throw new Error(`Signed price feed is too far ahead of Sui Clock (${Math.ceil(waitMs / 1000)}s). Try again later.`);
|
|
19264
19337
|
}
|
|
19265
19338
|
await this.sleep(Math.min(waitMs, 15_000));
|
|
@@ -19338,10 +19411,7 @@ class DipCoinPerpSDK {
|
|
|
19338
19411
|
await this.sleep(2_000 * (attempt + 1));
|
|
19339
19412
|
continue;
|
|
19340
19413
|
}
|
|
19341
|
-
return Array.from(new Map(entries.map((feed) => [
|
|
19342
|
-
Buffer.from(feed.payload).toString("hex"),
|
|
19343
|
-
feed,
|
|
19344
|
-
])).values());
|
|
19414
|
+
return Array.from(new Map(entries.map((feed) => [Buffer.from(feed.payload).toString("hex"), feed])).values());
|
|
19345
19415
|
}
|
|
19346
19416
|
throw lastClockError || new Error("Failed to fetch usable signed price feed chunks");
|
|
19347
19417
|
}
|
|
@@ -19444,11 +19514,9 @@ class DipCoinPerpSDK {
|
|
|
19444
19514
|
return { nav, tx: t };
|
|
19445
19515
|
}
|
|
19446
19516
|
async signAndExecuteVaultTx(tx) {
|
|
19447
|
-
|
|
19448
|
-
|
|
19449
|
-
|
|
19450
|
-
transaction: tx,
|
|
19451
|
-
options: { showEffects: true, showObjectChanges: true },
|
|
19517
|
+
return signAndExecuteTransactionWithFreshGas(this.suiClient, tx, this.keypair, {
|
|
19518
|
+
showEffects: true,
|
|
19519
|
+
showObjectChanges: true,
|
|
19452
19520
|
});
|
|
19453
19521
|
}
|
|
19454
19522
|
/**
|
|
@@ -20146,9 +20214,13 @@ function tryAutoBindReferral(sdk) {
|
|
|
20146
20214
|
try {
|
|
20147
20215
|
fs__default["default"].writeFileSync(markerPath, "");
|
|
20148
20216
|
}
|
|
20149
|
-
catch {
|
|
20217
|
+
catch {
|
|
20218
|
+
// Marker creation is best-effort; retrying referral binding is harmless.
|
|
20219
|
+
}
|
|
20150
20220
|
})
|
|
20151
|
-
.catch(() => {
|
|
20221
|
+
.catch(() => {
|
|
20222
|
+
// Auto-binding should never block normal CLI startup.
|
|
20223
|
+
});
|
|
20152
20224
|
}
|
|
20153
20225
|
/**
|
|
20154
20226
|
* Get or create the SDK instance (singleton).
|
|
@@ -20831,7 +20903,10 @@ function registerMarketCommands(program) {
|
|
|
20831
20903
|
const ob = result.data;
|
|
20832
20904
|
console.log(`\n Order Book: ${symbol}`);
|
|
20833
20905
|
console.log(" --- Asks (sell) ---");
|
|
20834
|
-
ob.asks
|
|
20906
|
+
ob.asks
|
|
20907
|
+
.slice(0, 10)
|
|
20908
|
+
.reverse()
|
|
20909
|
+
.forEach((a) => {
|
|
20835
20910
|
console.log(` ${formatWei(a.price).padStart(14)} | ${formatWei(a.quantity)}`);
|
|
20836
20911
|
});
|
|
20837
20912
|
console.log(" --- Bids (buy) ---");
|
|
@@ -21138,7 +21213,9 @@ function registerVaultCommands(program) {
|
|
|
21138
21213
|
return handleError(result.error);
|
|
21139
21214
|
let vaults = result.data || [];
|
|
21140
21215
|
if (!vaults.length)
|
|
21141
|
-
return isJson(program)
|
|
21216
|
+
return isJson(program)
|
|
21217
|
+
? printJson({ records: [], total: 0, pageNum: 1, pageSize: 10 })
|
|
21218
|
+
: console.log("No vaults found.");
|
|
21142
21219
|
// Client-side filter
|
|
21143
21220
|
const filter = opts.filter;
|
|
21144
21221
|
if (filter && filter !== "All") {
|
|
@@ -21166,7 +21243,16 @@ function registerVaultCommands(program) {
|
|
|
21166
21243
|
return printJson({ records: pageVaults, total, pageNum, pageSize, totalPages });
|
|
21167
21244
|
if (!pageVaults.length)
|
|
21168
21245
|
return console.log(`No vaults on page ${pageNum}. Total: ${total}, pages: ${totalPages}.`);
|
|
21169
|
-
printTable([
|
|
21246
|
+
printTable([
|
|
21247
|
+
"Name",
|
|
21248
|
+
"Vault ID",
|
|
21249
|
+
"TVL (USDC)",
|
|
21250
|
+
"APR (%)",
|
|
21251
|
+
"Depositors",
|
|
21252
|
+
"Age (d)",
|
|
21253
|
+
"Deposit",
|
|
21254
|
+
"Status",
|
|
21255
|
+
], pageVaults.map((v) => {
|
|
21170
21256
|
const tvl = new BigNumber__default["default"](v.tvl || "0").dividedBy(new BigNumber__default["default"](10).pow(18)).toFixed(2);
|
|
21171
21257
|
const apr = new BigNumber__default["default"](v.apr || "0").dividedBy(new BigNumber__default["default"](10).pow(14)).toFixed(2);
|
|
21172
21258
|
const depositors = new BigNumber__default["default"](v.currentDepositors || "0")
|
|
@@ -21208,7 +21294,10 @@ function registerVaultCommands(program) {
|
|
|
21208
21294
|
["Name", d.name || "-"],
|
|
21209
21295
|
["Creator", d.creator || "-"],
|
|
21210
21296
|
["Trader", d.trader || "-"],
|
|
21211
|
-
[
|
|
21297
|
+
[
|
|
21298
|
+
"Deposit Status",
|
|
21299
|
+
d.deposit_status === true || d.deposit_status === "true" ? "Open" : "Closed",
|
|
21300
|
+
],
|
|
21212
21301
|
["Total Shares", formatWeiValue(d.total_shares)],
|
|
21213
21302
|
["Max Cap", formatWeiValue(d.max_cap)],
|
|
21214
21303
|
["Min Deposit", formatWeiValue(d.min_deposit_amount)],
|
|
@@ -21480,7 +21569,10 @@ function registerVaultCommands(program) {
|
|
|
21480
21569
|
.action(async (vaultId, amount) => {
|
|
21481
21570
|
try {
|
|
21482
21571
|
const sdk = getSDK();
|
|
21483
|
-
const tx = await sdk.setVaultMinDepositAmount({
|
|
21572
|
+
const tx = await sdk.setVaultMinDepositAmount({
|
|
21573
|
+
vaultID: vaultId,
|
|
21574
|
+
minDepositAmount: parseAmount(amount),
|
|
21575
|
+
});
|
|
21484
21576
|
printTxResult(program, tx, `Min deposit set to ${amount} USDC.`);
|
|
21485
21577
|
}
|
|
21486
21578
|
catch (e) {
|
|
@@ -21497,7 +21589,10 @@ function registerVaultCommands(program) {
|
|
|
21497
21589
|
try {
|
|
21498
21590
|
const sdk = getSDK();
|
|
21499
21591
|
const enabled = !opts.disable;
|
|
21500
|
-
const tx = await sdk.setVaultAutoCloseOnWithdraw({
|
|
21592
|
+
const tx = await sdk.setVaultAutoCloseOnWithdraw({
|
|
21593
|
+
vaultID: vaultId,
|
|
21594
|
+
autoCloseOnWithdraw: enabled,
|
|
21595
|
+
});
|
|
21501
21596
|
printTxResult(program, tx, `Auto-close on withdraw ${enabled ? "enabled" : "disabled"}.`);
|
|
21502
21597
|
}
|
|
21503
21598
|
catch (e) {
|