@sign-global/tokentable-core 1.14.2 → 2.0.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/CHANGELOG.md +15 -0
- package/dist/index.d.mts +6 -5
- package/dist/index.d.ts +6 -5
- package/dist/index.js +69 -84
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +69 -84
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -4
- package/src/constants/network.ts +4 -5
- package/src/contracts/sui/BaseDistributorClient.ts +22 -38
- package/src/contracts/sui/DistributorWithFeeClient.ts +8 -8
- package/src/contracts/sui/SuiContractClient.ts +43 -37
- package/src/contracts/sui/__tests__/SuiContractClient.test.ts +16 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @sign-global/tokentable-core
|
|
2
2
|
|
|
3
|
+
## 2.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 1db0af2: Migrate Sui to `SuiGrpcClient` (`@mysten/sui` 2.x) and `@mysten/dapp-kit-react`. Sui Foundation public full nodes no longer serve JSON-RPC.
|
|
8
|
+
|
|
9
|
+
Breaking changes:
|
|
10
|
+
- core: `SuiContractInfo.chainRpc` must be a gRPC-web endpoint; JSON-RPC URLs no longer work.
|
|
11
|
+
- core: `signAndExecute` returns the 2.x `Transaction` object (`effects.changedObjects` instead of `effects.created`) and throws when execution fails.
|
|
12
|
+
- core: `readMoveFunction` returns the BCS bytes of the first return value.
|
|
13
|
+
- core: `getDistributorInfo().signer` now reads the on-chain `authorized_public_key` field.
|
|
14
|
+
- wallets: `@mysten/dapp-kit` is replaced by `@mysten/dapp-kit-react`; consumers must install `@mysten/dapp-kit-react` and `@mysten/sui` 2.x. The `@mysten/dapp-kit/dist/index.css` import is no longer needed.
|
|
15
|
+
- wallets: `SuiWallet.getStore().wallet` is now the wallet-standard `Wallet` (previously `{ currentWallet }`); pass it directly as `walletClient`.
|
|
16
|
+
- Requires `moduleResolution: bundler` (or `node16`/`nodenext`) in consuming TypeScript projects, as the 2.x `@mysten/sui` package exposes subpaths only through `exports`.
|
|
17
|
+
|
|
3
18
|
## 1.14.2
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -1648,10 +1648,10 @@ declare const suiTestNet: {
|
|
|
1648
1648
|
};
|
|
1649
1649
|
rpcUrls: {
|
|
1650
1650
|
public: {
|
|
1651
|
-
http:
|
|
1651
|
+
http: string[];
|
|
1652
1652
|
};
|
|
1653
1653
|
default: {
|
|
1654
|
-
http:
|
|
1654
|
+
http: string[];
|
|
1655
1655
|
};
|
|
1656
1656
|
};
|
|
1657
1657
|
blockExplorers: {
|
|
@@ -1673,10 +1673,10 @@ declare const suiMainNet: {
|
|
|
1673
1673
|
};
|
|
1674
1674
|
rpcUrls: {
|
|
1675
1675
|
public: {
|
|
1676
|
-
http:
|
|
1676
|
+
http: string[];
|
|
1677
1677
|
};
|
|
1678
1678
|
default: {
|
|
1679
|
-
http:
|
|
1679
|
+
http: string[];
|
|
1680
1680
|
};
|
|
1681
1681
|
};
|
|
1682
1682
|
blockExplorers: {
|
|
@@ -2151,6 +2151,7 @@ interface SuiContractInfo {
|
|
|
2151
2151
|
walletClient: Wallet$1;
|
|
2152
2152
|
coinType: string;
|
|
2153
2153
|
distributorId?: string;
|
|
2154
|
+
/** gRPC endpoint, e.g. https://fullnode.mainnet.sui.io:443 */
|
|
2154
2155
|
chainRpc?: string;
|
|
2155
2156
|
}
|
|
2156
2157
|
|
|
@@ -2170,7 +2171,7 @@ declare class SignatureAirdropService {
|
|
|
2170
2171
|
ownerCapId: any;
|
|
2171
2172
|
version: string | undefined;
|
|
2172
2173
|
feeCollector: any;
|
|
2173
|
-
token:
|
|
2174
|
+
token: string;
|
|
2174
2175
|
tokenBalance: any;
|
|
2175
2176
|
paused: any;
|
|
2176
2177
|
}>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1648,10 +1648,10 @@ declare const suiTestNet: {
|
|
|
1648
1648
|
};
|
|
1649
1649
|
rpcUrls: {
|
|
1650
1650
|
public: {
|
|
1651
|
-
http:
|
|
1651
|
+
http: string[];
|
|
1652
1652
|
};
|
|
1653
1653
|
default: {
|
|
1654
|
-
http:
|
|
1654
|
+
http: string[];
|
|
1655
1655
|
};
|
|
1656
1656
|
};
|
|
1657
1657
|
blockExplorers: {
|
|
@@ -1673,10 +1673,10 @@ declare const suiMainNet: {
|
|
|
1673
1673
|
};
|
|
1674
1674
|
rpcUrls: {
|
|
1675
1675
|
public: {
|
|
1676
|
-
http:
|
|
1676
|
+
http: string[];
|
|
1677
1677
|
};
|
|
1678
1678
|
default: {
|
|
1679
|
-
http:
|
|
1679
|
+
http: string[];
|
|
1680
1680
|
};
|
|
1681
1681
|
};
|
|
1682
1682
|
blockExplorers: {
|
|
@@ -2151,6 +2151,7 @@ interface SuiContractInfo {
|
|
|
2151
2151
|
walletClient: Wallet$1;
|
|
2152
2152
|
coinType: string;
|
|
2153
2153
|
distributorId?: string;
|
|
2154
|
+
/** gRPC endpoint, e.g. https://fullnode.mainnet.sui.io:443 */
|
|
2154
2155
|
chainRpc?: string;
|
|
2155
2156
|
}
|
|
2156
2157
|
|
|
@@ -2170,7 +2171,7 @@ declare class SignatureAirdropService {
|
|
|
2170
2171
|
ownerCapId: any;
|
|
2171
2172
|
version: string | undefined;
|
|
2172
2173
|
feeCollector: any;
|
|
2173
|
-
token:
|
|
2174
|
+
token: string;
|
|
2174
2175
|
tokenBalance: any;
|
|
2175
2176
|
paused: any;
|
|
2176
2177
|
}>;
|
package/dist/index.js
CHANGED
|
@@ -102,7 +102,6 @@ module.exports = __toCommonJS(index_exports);
|
|
|
102
102
|
var import_chains = require("viem/chains");
|
|
103
103
|
|
|
104
104
|
// src/constants/network.ts
|
|
105
|
-
var import_client = require("@mysten/sui/client");
|
|
106
105
|
var import_sdk = require("@tonconnect/sdk");
|
|
107
106
|
var import_viem = require("viem");
|
|
108
107
|
var mevmDevNet = (0, import_viem.defineChain)({
|
|
@@ -260,10 +259,10 @@ var suiTestNet = {
|
|
|
260
259
|
},
|
|
261
260
|
rpcUrls: {
|
|
262
261
|
public: {
|
|
263
|
-
http: [
|
|
262
|
+
http: ["https://fullnode.testnet.sui.io:443"]
|
|
264
263
|
},
|
|
265
264
|
default: {
|
|
266
|
-
http: [
|
|
265
|
+
http: ["https://fullnode.testnet.sui.io:443"]
|
|
267
266
|
}
|
|
268
267
|
},
|
|
269
268
|
blockExplorers: {
|
|
@@ -285,10 +284,10 @@ var suiMainNet = {
|
|
|
285
284
|
},
|
|
286
285
|
rpcUrls: {
|
|
287
286
|
public: {
|
|
288
|
-
http: [
|
|
287
|
+
http: ["https://fullnode.mainnet.sui.io:443"]
|
|
289
288
|
},
|
|
290
289
|
default: {
|
|
291
|
-
http: [
|
|
290
|
+
http: ["https://fullnode.mainnet.sui.io:443"]
|
|
292
291
|
}
|
|
293
292
|
},
|
|
294
293
|
blockExplorers: {
|
|
@@ -12474,9 +12473,10 @@ var AirdropService3 = class {
|
|
|
12474
12473
|
};
|
|
12475
12474
|
|
|
12476
12475
|
// src/contracts/sui/SuiContractClient.ts
|
|
12477
|
-
var
|
|
12476
|
+
var import_grpc = require("@mysten/sui/grpc");
|
|
12478
12477
|
var import_bcs = require("@mysten/sui/bcs");
|
|
12479
12478
|
var import_transactions = require("@mysten/sui/transactions");
|
|
12479
|
+
var import_utils19 = require("@mysten/sui/utils");
|
|
12480
12480
|
var import_wallet_standard = require("@mysten/wallet-standard");
|
|
12481
12481
|
var SuiContractClientBase = class {
|
|
12482
12482
|
packageId;
|
|
@@ -12491,7 +12491,10 @@ var SuiContractClientBase = class {
|
|
|
12491
12491
|
this.moduleName = contractInfo.moduleName;
|
|
12492
12492
|
this.distributorId = contractInfo.distributorId;
|
|
12493
12493
|
this.wallet = contractInfo.walletClient;
|
|
12494
|
-
this.client = new
|
|
12494
|
+
this.client = new import_grpc.SuiGrpcClient({
|
|
12495
|
+
network: this.chainId,
|
|
12496
|
+
baseUrl: contractInfo.chainRpc || `https://fullnode.${this.chainId}.sui.io:443`
|
|
12497
|
+
});
|
|
12495
12498
|
}
|
|
12496
12499
|
async signAndExecute(tx) {
|
|
12497
12500
|
if (!this.wallet) {
|
|
@@ -12529,25 +12532,25 @@ var SuiContractClientBase = class {
|
|
|
12529
12532
|
account: signerAccount,
|
|
12530
12533
|
chain
|
|
12531
12534
|
});
|
|
12532
|
-
const result = await this.client.
|
|
12533
|
-
|
|
12534
|
-
signature,
|
|
12535
|
-
|
|
12536
|
-
showEffects: true,
|
|
12537
|
-
showEvents: true
|
|
12538
|
-
}
|
|
12535
|
+
const result = await this.client.executeTransaction({
|
|
12536
|
+
transaction: (0, import_utils19.fromBase64)(bytes),
|
|
12537
|
+
signatures: [signature],
|
|
12538
|
+
include: { effects: true, events: true }
|
|
12539
12539
|
});
|
|
12540
|
-
|
|
12541
|
-
|
|
12540
|
+
if (result.$kind === "FailedTransaction") {
|
|
12541
|
+
throw new Error(result.FailedTransaction.status.error?.message ?? "Transaction failed");
|
|
12542
|
+
}
|
|
12543
|
+
await this.waitForTx(result.Transaction.digest);
|
|
12544
|
+
return result.Transaction;
|
|
12542
12545
|
}
|
|
12543
12546
|
async waitForTx(digest) {
|
|
12544
12547
|
return this.client.waitForTransaction({
|
|
12545
12548
|
digest,
|
|
12546
|
-
|
|
12549
|
+
include: { effects: true, events: true }
|
|
12547
12550
|
});
|
|
12548
12551
|
}
|
|
12549
12552
|
/**
|
|
12550
|
-
*
|
|
12553
|
+
* 读取合约返回值(只读调用),返回第一个返回值的 BCS 字节
|
|
12551
12554
|
* @param func Move function 名
|
|
12552
12555
|
* @param typeArgs 类型参数
|
|
12553
12556
|
* @param args Move function 参数
|
|
@@ -12566,43 +12569,42 @@ var SuiContractClientBase = class {
|
|
|
12566
12569
|
return tx.pure(arg);
|
|
12567
12570
|
})
|
|
12568
12571
|
});
|
|
12569
|
-
|
|
12570
|
-
|
|
12571
|
-
|
|
12572
|
-
|
|
12572
|
+
tx.setSender(sender);
|
|
12573
|
+
const res = await this.client.simulateTransaction({
|
|
12574
|
+
transaction: tx,
|
|
12575
|
+
checksEnabled: false,
|
|
12576
|
+
include: { commandResults: true }
|
|
12573
12577
|
});
|
|
12574
12578
|
console.log(res, "res");
|
|
12575
|
-
if (
|
|
12579
|
+
if (res.$kind === "FailedTransaction") {
|
|
12580
|
+
throw new Error(`Failed to read ${func}: ${res.FailedTransaction.status.error?.message}`);
|
|
12581
|
+
}
|
|
12582
|
+
const returnValue = res.commandResults?.[0]?.returnValues?.[0]?.bcs;
|
|
12583
|
+
if (!returnValue) {
|
|
12576
12584
|
throw new Error(`Failed to read ${func}`);
|
|
12577
12585
|
}
|
|
12578
|
-
return
|
|
12586
|
+
return returnValue;
|
|
12579
12587
|
}
|
|
12580
12588
|
/**
|
|
12581
12589
|
* 查询 Distributor MoveObject 的 fields
|
|
12582
12590
|
*/
|
|
12583
12591
|
async getObjectFields(objectId) {
|
|
12584
|
-
const
|
|
12585
|
-
|
|
12586
|
-
|
|
12592
|
+
const { object } = await this.client.getObject({
|
|
12593
|
+
objectId,
|
|
12594
|
+
include: { json: true }
|
|
12587
12595
|
});
|
|
12588
|
-
if (
|
|
12596
|
+
if (!object.json) {
|
|
12589
12597
|
throw new Error(`Object ${objectId} is not a moveObject`);
|
|
12590
12598
|
}
|
|
12591
|
-
return
|
|
12599
|
+
return object.json;
|
|
12592
12600
|
}
|
|
12593
12601
|
async getSharedObjectRef(tx, objectId, mutable) {
|
|
12594
|
-
const
|
|
12595
|
-
|
|
12596
|
-
|
|
12597
|
-
});
|
|
12598
|
-
console.log(obj, "obj");
|
|
12599
|
-
if (!obj.data) {
|
|
12600
|
-
throw new Error(`Object ${objectId} not found`);
|
|
12601
|
-
}
|
|
12602
|
-
if (!obj.data.owner?.Shared) {
|
|
12602
|
+
const { object } = await this.client.getObject({ objectId });
|
|
12603
|
+
console.log(object, "obj");
|
|
12604
|
+
if (object.owner.$kind !== "Shared") {
|
|
12603
12605
|
throw new Error(`Object ${objectId} is not a shared object`);
|
|
12604
12606
|
}
|
|
12605
|
-
const initialSharedVersion =
|
|
12607
|
+
const initialSharedVersion = object.owner.Shared.initialSharedVersion;
|
|
12606
12608
|
return tx.sharedObjectRef({
|
|
12607
12609
|
objectId,
|
|
12608
12610
|
initialSharedVersion: Number(initialSharedVersion),
|
|
@@ -12614,6 +12616,7 @@ var SuiContractClientBase = class {
|
|
|
12614
12616
|
// src/contracts/sui/BaseDistributorClient.ts
|
|
12615
12617
|
var import_transactions2 = require("@mysten/sui/transactions");
|
|
12616
12618
|
var import_bcs2 = require("@mysten/sui/bcs");
|
|
12619
|
+
var import_utils20 = require("@mysten/sui/utils");
|
|
12617
12620
|
var SuiBaseDistributorClient = class extends SuiContractClientBase {
|
|
12618
12621
|
constructor(info) {
|
|
12619
12622
|
super({ ...info, moduleName: "base_distributor" });
|
|
@@ -12627,19 +12630,12 @@ var SuiBaseDistributorClient = class extends SuiContractClientBase {
|
|
|
12627
12630
|
arguments: [tx.pure(projectIdBytes), tx.object(projectRegistryId)]
|
|
12628
12631
|
});
|
|
12629
12632
|
const result = await this.signAndExecute(tx);
|
|
12630
|
-
|
|
12631
|
-
|
|
12632
|
-
|
|
12633
|
-
(obj) => obj.owner === "Shared" || obj.owner?.Shared
|
|
12634
|
-
// 某些版本字段是对象
|
|
12635
|
-
);
|
|
12636
|
-
if (createdObj) {
|
|
12637
|
-
distributorId = createdObj.reference.objectId;
|
|
12638
|
-
}
|
|
12639
|
-
}
|
|
12633
|
+
const createdObj = result.effects?.changedObjects.find(
|
|
12634
|
+
(obj) => obj.idOperation === "Created" && obj.outputOwner?.$kind === "Shared"
|
|
12635
|
+
);
|
|
12640
12636
|
return {
|
|
12641
12637
|
txResult: result,
|
|
12642
|
-
distributorId
|
|
12638
|
+
distributorId: createdObj?.objectId
|
|
12643
12639
|
};
|
|
12644
12640
|
}
|
|
12645
12641
|
async setBaseParams(coinType, startTime, endTime, authorizedSigner, ownerCapId) {
|
|
@@ -12667,20 +12663,20 @@ var SuiBaseDistributorClient = class extends SuiContractClientBase {
|
|
|
12667
12663
|
return this.signAndExecute(tx);
|
|
12668
12664
|
}
|
|
12669
12665
|
async getDistributorInfo() {
|
|
12670
|
-
const
|
|
12671
|
-
|
|
12672
|
-
|
|
12666
|
+
const { object } = await this.client.getObject({
|
|
12667
|
+
objectId: this.distributorId,
|
|
12668
|
+
include: { json: true }
|
|
12673
12669
|
});
|
|
12674
|
-
const
|
|
12675
|
-
const
|
|
12676
|
-
const match = content?.type.match(/<(.+)>$/);
|
|
12670
|
+
const fields = object.json;
|
|
12671
|
+
const match = object.type.match(/<(.+)>$/);
|
|
12677
12672
|
const coinType = match ? match[1] : "";
|
|
12678
12673
|
return {
|
|
12679
12674
|
startTime: fields?.start_time,
|
|
12680
12675
|
endTime: fields?.end_time,
|
|
12681
|
-
signer: fields?.
|
|
12676
|
+
signer: fields?.authorized_public_key,
|
|
12682
12677
|
ownerCapId: fields?.owner_cap_id,
|
|
12683
|
-
|
|
12678
|
+
// gRPC JSON 中 vector<u8> 以 base64 返回
|
|
12679
|
+
version: fields?.version ? new TextDecoder().decode((0, import_utils20.fromBase64)(fields.version)) : void 0,
|
|
12684
12680
|
feeCollector: fields?.fee_collector_config,
|
|
12685
12681
|
token: coinType,
|
|
12686
12682
|
tokenBalance: fields?.token_balance,
|
|
@@ -12700,34 +12696,23 @@ var SuiBaseDistributorClient = class extends SuiContractClientBase {
|
|
|
12700
12696
|
}
|
|
12701
12697
|
async batchFetchClaimed(coinType, claimIds) {
|
|
12702
12698
|
const claimIdsBytes = claimIds.map((id) => Array.from(new TextEncoder().encode(id)));
|
|
12703
|
-
const res = await this.readMoveFunction(
|
|
12704
|
-
|
|
12705
|
-
[coinType],
|
|
12706
|
-
[this.distributorId, claimIdsBytes]
|
|
12707
|
-
);
|
|
12708
|
-
const [data, type] = res;
|
|
12709
|
-
if (type === "vector<bool>" && data) {
|
|
12710
|
-
const uint8Array = new Uint8Array(data);
|
|
12711
|
-
return Array.from(import_bcs2.bcs.vector(import_bcs2.bcs.bool()).parse(uint8Array));
|
|
12712
|
-
}
|
|
12713
|
-
return [];
|
|
12699
|
+
const res = await this.readMoveFunction("get_claim_status", [coinType], [this.distributorId, claimIdsBytes]);
|
|
12700
|
+
return import_bcs2.bcs.vector(import_bcs2.bcs.bool()).parse(res);
|
|
12714
12701
|
}
|
|
12715
12702
|
async getDistributorId(projectId, projectRegistryId) {
|
|
12716
|
-
const
|
|
12703
|
+
const res = await this.readMoveFunction(
|
|
12717
12704
|
"get_distributor_by_project_id",
|
|
12718
12705
|
[],
|
|
12719
12706
|
[projectRegistryId, Array.from(Buffer.from(projectId, "utf8"))]
|
|
12720
12707
|
);
|
|
12721
|
-
return
|
|
12708
|
+
return import_bcs2.bcs.option(import_bcs2.bcs.Address).parse(res);
|
|
12722
12709
|
}
|
|
12723
12710
|
async getOwnerCapId() {
|
|
12724
|
-
const objects = await this.client.
|
|
12711
|
+
const { objects } = await this.client.listOwnedObjects({
|
|
12725
12712
|
owner: this.wallet.accounts[0].address,
|
|
12726
|
-
|
|
12727
|
-
StructType: `${this.packageId}::ownable::OwnerCap`
|
|
12728
|
-
}
|
|
12713
|
+
type: `${this.packageId}::ownable::OwnerCap`
|
|
12729
12714
|
});
|
|
12730
|
-
const ownerCapId = objects
|
|
12715
|
+
const ownerCapId = objects[0]?.objectId;
|
|
12731
12716
|
return ownerCapId;
|
|
12732
12717
|
}
|
|
12733
12718
|
};
|
|
@@ -12741,19 +12726,19 @@ var SuiDistributorWithFeeClient = class extends SuiContractClientBase {
|
|
|
12741
12726
|
}
|
|
12742
12727
|
async prepareFeePayment(totalFeesStr, feeTokenType, tx) {
|
|
12743
12728
|
const totalFees = BigInt(totalFeesStr);
|
|
12744
|
-
const coins = await this.client.
|
|
12729
|
+
const coins = await this.client.listCoins({
|
|
12745
12730
|
owner: this.wallet.accounts[0].address,
|
|
12746
12731
|
coinType: feeTokenType
|
|
12747
12732
|
});
|
|
12748
|
-
const suitableCoin = coins.
|
|
12733
|
+
const suitableCoin = coins.objects.find((coin) => BigInt(coin.balance) >= totalFees);
|
|
12749
12734
|
if (suitableCoin) {
|
|
12750
12735
|
if (BigInt(suitableCoin.balance) === totalFees) {
|
|
12751
|
-
return tx.object(suitableCoin.
|
|
12736
|
+
return tx.object(suitableCoin.objectId);
|
|
12752
12737
|
}
|
|
12753
|
-
const [feeCoin] = tx.splitCoins(tx.object(suitableCoin.
|
|
12738
|
+
const [feeCoin] = tx.splitCoins(tx.object(suitableCoin.objectId), [tx.pure(import_bcs3.bcs.u64().serialize(totalFees))]);
|
|
12754
12739
|
return feeCoin;
|
|
12755
12740
|
}
|
|
12756
|
-
throw new Error(`Insufficient balance. Required: ${totalFeesStr}, Available coins: ${coins.
|
|
12741
|
+
throw new Error(`Insufficient balance. Required: ${totalFeesStr}, Available coins: ${coins.objects.length}`);
|
|
12757
12742
|
}
|
|
12758
12743
|
async claimWithFee(coinType, feeCollector, data) {
|
|
12759
12744
|
const recipients = data.map((item) => item.recipient);
|
|
@@ -12780,12 +12765,12 @@ var SuiDistributorWithFeeClient = class extends SuiContractClientBase {
|
|
|
12780
12765
|
const clock = await this.getSharedObjectRef(tx, "0x6", false);
|
|
12781
12766
|
const hexToBytes = (hex) => Array.from(Buffer.from(hex.replace(/^0x/, ""), "hex"));
|
|
12782
12767
|
const feeTokenType = "0x2::sui::SUI";
|
|
12783
|
-
const gasBalance = await this.client.getBalance({
|
|
12768
|
+
const { balance: gasBalance } = await this.client.getBalance({
|
|
12784
12769
|
owner: this.wallet.accounts[0].address,
|
|
12785
12770
|
coinType: feeTokenType
|
|
12786
12771
|
});
|
|
12787
|
-
if (BigInt(gasBalance.
|
|
12788
|
-
throw new Error(`Insufficient SUI balance. Required: ${totalFees}, Available: ${gasBalance.
|
|
12772
|
+
if (BigInt(gasBalance.balance) < totalFees) {
|
|
12773
|
+
throw new Error(`Insufficient SUI balance. Required: ${totalFees}, Available: ${gasBalance.balance}`);
|
|
12789
12774
|
}
|
|
12790
12775
|
const [feeCoin] = tx.splitCoins(
|
|
12791
12776
|
tx.gas,
|