dipcoin-cli 1.2.2 → 1.3.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/cli.cjs
CHANGED
|
@@ -16596,6 +16596,13 @@ function getPerpetualId(deployment, market) {
|
|
|
16596
16596
|
throw new Error(`Deployment config missing Perpetual id for ${m}`);
|
|
16597
16597
|
return id;
|
|
16598
16598
|
}
|
|
16599
|
+
function getPriceFeedId(deployment) {
|
|
16600
|
+
const id = deployment?.objects?.PriceFeed?.id;
|
|
16601
|
+
if (!id) {
|
|
16602
|
+
throw new Error("Deployment config missing PriceFeed id. Add objects.PriceFeed to the network's main_contract.json — required for v6+ on-chain margin/vault writes.");
|
|
16603
|
+
}
|
|
16604
|
+
return id;
|
|
16605
|
+
}
|
|
16599
16606
|
function getPriceOracleObjectId(deployment, market) {
|
|
16600
16607
|
const m = market?.toUpperCase() || "ETH-PERP";
|
|
16601
16608
|
const id = deployment?.markets?.[m]?.Objects?.PriceInfoObject?.id;
|
|
@@ -16641,7 +16648,7 @@ function buildAddMarginTx(deployment, args, tx, gasBudget, sender) {
|
|
|
16641
16648
|
t.setSender(sender);
|
|
16642
16649
|
const packageId = getPackageId(deployment);
|
|
16643
16650
|
t.moveCall({
|
|
16644
|
-
target: `${packageId}::exchange::
|
|
16651
|
+
target: `${packageId}::exchange::add_margin_v3`,
|
|
16645
16652
|
arguments: [
|
|
16646
16653
|
t.object(getProtocolConfigId(deployment)),
|
|
16647
16654
|
t.object(CLOCK_OBJECT_ID),
|
|
@@ -16649,7 +16656,7 @@ function buildAddMarginTx(deployment, args, tx, gasBudget, sender) {
|
|
|
16649
16656
|
t.object(getBankId(deployment)),
|
|
16650
16657
|
t.object(args.subAccountsMapID || getSubAccountsId(deployment)),
|
|
16651
16658
|
t.object(getTxIndexerId(deployment)),
|
|
16652
|
-
t.object(
|
|
16659
|
+
t.object(getPriceFeedId(deployment)),
|
|
16653
16660
|
t.pure.address(args.account || sender || ""),
|
|
16654
16661
|
t.pure.u128(args.amount.toString()),
|
|
16655
16662
|
],
|
|
@@ -16665,7 +16672,7 @@ function buildRemoveMarginTx(deployment, args, tx, gasBudget, sender) {
|
|
|
16665
16672
|
t.setSender(sender);
|
|
16666
16673
|
const packageId = getPackageId(deployment);
|
|
16667
16674
|
t.moveCall({
|
|
16668
|
-
target: `${packageId}::exchange::
|
|
16675
|
+
target: `${packageId}::exchange::remove_margin_v3`,
|
|
16669
16676
|
arguments: [
|
|
16670
16677
|
t.object(getProtocolConfigId(deployment)),
|
|
16671
16678
|
t.object(CLOCK_OBJECT_ID),
|
|
@@ -16673,7 +16680,7 @@ function buildRemoveMarginTx(deployment, args, tx, gasBudget, sender) {
|
|
|
16673
16680
|
t.object(getBankId(deployment)),
|
|
16674
16681
|
t.object(args.subAccountsMapID || getSubAccountsId(deployment)),
|
|
16675
16682
|
t.object(getTxIndexerId(deployment)),
|
|
16676
|
-
t.object(
|
|
16683
|
+
t.object(getPriceFeedId(deployment)),
|
|
16677
16684
|
t.pure.address(args.account || sender || ""),
|
|
16678
16685
|
t.pure.u128(args.amount.toString()),
|
|
16679
16686
|
],
|
|
@@ -16744,17 +16751,6 @@ function buildSetOraclePriceTx(deployment, args, tx, gasBudget, sender) {
|
|
|
16744
16751
|
});
|
|
16745
16752
|
return t;
|
|
16746
16753
|
}
|
|
16747
|
-
function buildBatchSetOraclePriceTx(deployment, args, tx, gasBudget, sender) {
|
|
16748
|
-
let t = tx || new transactions.Transaction();
|
|
16749
|
-
for (const priceArgs of args.prices) {
|
|
16750
|
-
t = buildSetOraclePriceTx(deployment, priceArgs, t, undefined, undefined);
|
|
16751
|
-
}
|
|
16752
|
-
if (gasBudget)
|
|
16753
|
-
t.setGasBudget(gasBudget);
|
|
16754
|
-
if (sender)
|
|
16755
|
-
t.setSender(sender);
|
|
16756
|
-
return t;
|
|
16757
|
-
}
|
|
16758
16754
|
|
|
16759
16755
|
// Copyright (c) 2025 Dipcoin LLC
|
|
16760
16756
|
async function executeTxBlock(suiClient, tx, signer) {
|
|
@@ -18624,10 +18620,9 @@ class DipCoinPerpSDK {
|
|
|
18624
18620
|
}
|
|
18625
18621
|
async buildMarginTransaction(params, action) {
|
|
18626
18622
|
const payload = this.buildMarginCallArgs(params, action);
|
|
18627
|
-
|
|
18628
|
-
|
|
18629
|
-
|
|
18630
|
-
const baseTx = updatePriceTx || new transactions.Transaction();
|
|
18623
|
+
// v6+ uses add_margin_v3/remove_margin_v3 which read &PriceFeed (a shared object
|
|
18624
|
+
// maintained off-band by an operator). No Pyth update is needed on the user-side tx.
|
|
18625
|
+
const baseTx = new transactions.Transaction();
|
|
18631
18626
|
if (action === "add") {
|
|
18632
18627
|
return buildAddMarginTx(this.deploymentConfig, payload, baseTx, params.gasBudget);
|
|
18633
18628
|
}
|
|
@@ -18913,45 +18908,40 @@ class DipCoinPerpSDK {
|
|
|
18913
18908
|
throw new Error(`Deployment config missing PriceInfoObject id for ${symbol}`);
|
|
18914
18909
|
return id;
|
|
18915
18910
|
}
|
|
18916
|
-
|
|
18911
|
+
getPriceFeedId() {
|
|
18912
|
+
const id = this.deploymentConfig?.objects?.PriceFeed?.id;
|
|
18913
|
+
if (!id) {
|
|
18914
|
+
throw new Error("Deployment config missing PriceFeed id. Add objects.PriceFeed to the network's main_contract.json — required for v6+ vault/margin writes.");
|
|
18915
|
+
}
|
|
18916
|
+
return id;
|
|
18917
|
+
}
|
|
18918
|
+
async getOnChainPerpetualIds() {
|
|
18919
|
+
const pcId = this.getDeploymentProtocolConfigId();
|
|
18920
|
+
const df = await this.suiClient.getDynamicFieldObject({
|
|
18921
|
+
parentId: pcId,
|
|
18922
|
+
name: {
|
|
18923
|
+
type: "vector<u8>",
|
|
18924
|
+
value: Array.from(Buffer.from("perpetual_registry", "utf8")),
|
|
18925
|
+
},
|
|
18926
|
+
});
|
|
18927
|
+
const content = df.data?.content;
|
|
18928
|
+
const contents = content?.fields?.value?.fields?.perpetuals?.fields?.contents;
|
|
18929
|
+
if (!Array.isArray(contents)) {
|
|
18930
|
+
throw new Error("Could not read perpetual_registry from on-chain ProtocolConfig. Vault NAV requires the full list of perpetuals registered in the protocol.");
|
|
18931
|
+
}
|
|
18932
|
+
return contents;
|
|
18933
|
+
}
|
|
18934
|
+
async buildVaultNavTransaction(vaultID, _markets, tx) {
|
|
18917
18935
|
const t = tx || new transactions.Transaction();
|
|
18918
18936
|
const vaultPkg = this.getVaultPackageId();
|
|
18919
18937
|
const currencyType = this.getCurrencyType();
|
|
18920
|
-
|
|
18921
|
-
|
|
18922
|
-
|
|
18923
|
-
|
|
18924
|
-
|
|
18925
|
-
|
|
18926
|
-
|
|
18927
|
-
const feedId = await this.resolvePriceFeedId(sym);
|
|
18928
|
-
if (feedId)
|
|
18929
|
-
priceIds.push(feedId);
|
|
18930
|
-
}
|
|
18931
|
-
if (priceIds.length > 0) {
|
|
18932
|
-
const priceUpdateData = await this.priceServiceConnection.getPriceFeedsUpdateData(priceIds);
|
|
18933
|
-
await this.pythClient.updatePriceFeeds(t, priceUpdateData, priceIds);
|
|
18934
|
-
}
|
|
18935
|
-
}
|
|
18936
|
-
}
|
|
18937
|
-
else {
|
|
18938
|
-
// On testnet, prepend price oracle updates so PriceInfoObjects are fresh
|
|
18939
|
-
const prices = [];
|
|
18940
|
-
for (const sym of symbols) {
|
|
18941
|
-
try {
|
|
18942
|
-
const oraclePrice = await getOraclePrice(this.suiClient, this.deploymentConfig, sym);
|
|
18943
|
-
if (oraclePrice !== undefined && oraclePrice !== null) {
|
|
18944
|
-
prices.push({ price: Number(oraclePrice), market: sym });
|
|
18945
|
-
}
|
|
18946
|
-
}
|
|
18947
|
-
catch {
|
|
18948
|
-
// skip symbols where oracle price is unavailable
|
|
18949
|
-
}
|
|
18950
|
-
}
|
|
18951
|
-
if (prices.length > 0) {
|
|
18952
|
-
buildBatchSetOraclePriceTx(this.deploymentConfig, { prices }, t);
|
|
18953
|
-
}
|
|
18954
|
-
}
|
|
18938
|
+
// v6+: PriceFeed is a single shared object maintained by an operator off-band.
|
|
18939
|
+
// new_vault_nav populates `perpetuals` from ProtocolConfig.perpetual_registry, and
|
|
18940
|
+
// is_nav_filled requires EVERY registered perpetual to have a position value entry.
|
|
18941
|
+
// So we must compute against the on-chain registry, not the local deployment.markets
|
|
18942
|
+
// list (which can drift behind chain additions).
|
|
18943
|
+
const priceFeedId = this.getPriceFeedId();
|
|
18944
|
+
const perpetualIds = await this.getOnChainPerpetualIds();
|
|
18955
18945
|
const [nav] = t.moveCall({
|
|
18956
18946
|
target: `${vaultPkg}::vault::new_vault_nav`,
|
|
18957
18947
|
arguments: [
|
|
@@ -18962,12 +18952,10 @@ class DipCoinPerpSDK {
|
|
|
18962
18952
|
],
|
|
18963
18953
|
typeArguments: [currencyType],
|
|
18964
18954
|
});
|
|
18965
|
-
for (const
|
|
18966
|
-
const perpId = this.getVaultPerpetualId(sym);
|
|
18967
|
-
const priceInfoId = this.getVaultPriceInfoObjectId(sym);
|
|
18955
|
+
for (const perpId of perpetualIds) {
|
|
18968
18956
|
t.moveCall({
|
|
18969
|
-
target: `${vaultPkg}::vault::
|
|
18970
|
-
arguments: [nav, t.object("0x6"), t.object(perpId), t.object(
|
|
18957
|
+
target: `${vaultPkg}::vault::compute_perpetual_position_value_v2`,
|
|
18958
|
+
arguments: [nav, t.object("0x6"), t.object(perpId), t.object(priceFeedId)],
|
|
18971
18959
|
typeArguments: [],
|
|
18972
18960
|
});
|
|
18973
18961
|
}
|
|
@@ -19996,11 +19984,16 @@ function registerPositionCommands(program) {
|
|
|
19996
19984
|
.description("Add margin to position")
|
|
19997
19985
|
.argument("<symbol>", "Trading pair")
|
|
19998
19986
|
.argument("<amount>", "Amount in USDC")
|
|
19999
|
-
.
|
|
19987
|
+
.option("--vault <address>", "Target a vault's position (vault id) instead of personal account")
|
|
19988
|
+
.action(async (symbol, amount, opts) => {
|
|
20000
19989
|
try {
|
|
20001
19990
|
const sdk = getSDK();
|
|
20002
19991
|
symbol = normalizeSymbol(symbol);
|
|
20003
|
-
const tx = await sdk.addMargin({
|
|
19992
|
+
const tx = await sdk.addMargin({
|
|
19993
|
+
symbol,
|
|
19994
|
+
amount: parseAmount(amount),
|
|
19995
|
+
accountAddress: opts.vault,
|
|
19996
|
+
});
|
|
20004
19997
|
if (isJson(program))
|
|
20005
19998
|
return printJson({ digest: tx?.digest, status: "ok" });
|
|
20006
19999
|
console.log(`Added ${amount} margin to ${symbol}. Tx: ${tx?.digest || JSON.stringify(tx)}`);
|
|
@@ -20014,11 +20007,16 @@ function registerPositionCommands(program) {
|
|
|
20014
20007
|
.description("Remove margin from position")
|
|
20015
20008
|
.argument("<symbol>", "Trading pair")
|
|
20016
20009
|
.argument("<amount>", "Amount in USDC")
|
|
20017
|
-
.
|
|
20010
|
+
.option("--vault <address>", "Target a vault's position (vault id) instead of personal account")
|
|
20011
|
+
.action(async (symbol, amount, opts) => {
|
|
20018
20012
|
try {
|
|
20019
20013
|
const sdk = getSDK();
|
|
20020
20014
|
symbol = normalizeSymbol(symbol);
|
|
20021
|
-
const tx = await sdk.removeMargin({
|
|
20015
|
+
const tx = await sdk.removeMargin({
|
|
20016
|
+
symbol,
|
|
20017
|
+
amount: parseAmount(amount),
|
|
20018
|
+
accountAddress: opts.vault,
|
|
20019
|
+
});
|
|
20022
20020
|
if (isJson(program))
|
|
20023
20021
|
return printJson({ digest: tx?.digest, status: "ok" });
|
|
20024
20022
|
console.log(`Removed ${amount} margin from ${symbol}. Tx: ${tx?.digest || JSON.stringify(tx)}`);
|