btc-wallet 0.4.4-beta → 0.4.6-beta
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/README.md +0 -1
- package/dist/core/btcUtils.d.ts +26 -16
- package/dist/index.js +195 -49
- package/dist/index.js.map +3 -3
- package/dist/utils/satoshi.d.ts +1 -0
- package/esm/index.js +195 -49
- package/esm/index.js.map +2 -2
- package/package.json +3 -1
package/dist/utils/satoshi.d.ts
CHANGED
@@ -19,4 +19,5 @@ export declare function checkBtcTransactionStatus(url: string, sig: string): Pro
|
|
19
19
|
NearHashList: string[];
|
20
20
|
}>;
|
21
21
|
export declare function getWhitelist(url: string): Promise<string[]>;
|
22
|
+
export declare function receiveWithdrawMsg(url: string, txHash: string): Promise<any>;
|
22
23
|
export {};
|
package/esm/index.js
CHANGED
@@ -2354,6 +2354,7 @@ function BtcWalletSelectorContextProvider({
|
|
2354
2354
|
const [isProcessing, setIsProcessing] = useState8(false);
|
2355
2355
|
const connectors = [
|
2356
2356
|
new UnisatConnector(),
|
2357
|
+
new XverseConnector(),
|
2357
2358
|
new OKXConnector(),
|
2358
2359
|
new BitgetConnector()
|
2359
2360
|
];
|
@@ -3193,9 +3194,10 @@ Dialog.style = `
|
|
3193
3194
|
`;
|
3194
3195
|
|
3195
3196
|
// src/core/btcUtils.ts
|
3196
|
-
|
3197
|
+
import bitcoin from "bitcoinjs-lib";
|
3198
|
+
import coinselect from "coinselect";
|
3197
3199
|
var NEAR_STORAGE_DEPOSIT_AMOUNT = "1250000000000000000000";
|
3198
|
-
var NBTC_STORAGE_DEPOSIT_AMOUNT =
|
3200
|
+
var NBTC_STORAGE_DEPOSIT_AMOUNT = "3000";
|
3199
3201
|
var GAS_LIMIT = "50000000000000";
|
3200
3202
|
function getBtcProvider() {
|
3201
3203
|
if (typeof window === "undefined" || !window.btcContext) {
|
@@ -3253,11 +3255,11 @@ function checkGasTokenBalance(csna, gasToken, minAmount, env) {
|
|
3253
3255
|
}
|
3254
3256
|
});
|
3255
3257
|
}
|
3256
|
-
function
|
3258
|
+
function checkGasTokenDebt(accountInfo, env, autoDeposit) {
|
3257
3259
|
return __async(this, null, function* () {
|
3258
3260
|
var _a, _b, _c;
|
3259
3261
|
const debtAmount = new Big(((_a = accountInfo == null ? void 0 : accountInfo.debt_info) == null ? void 0 : _a.near_gas_debt_amount) || 0).plus(((_b = accountInfo == null ? void 0 : accountInfo.debt_info) == null ? void 0 : _b.protocol_fee_debt_amount) || 0).toString();
|
3260
|
-
const relayerFeeAmount = ((_c = accountInfo == null ? void 0 : accountInfo.relayer_fee) == null ? void 0 : _c.amount) ||
|
3262
|
+
const relayerFeeAmount = !(accountInfo == null ? void 0 : accountInfo.nonce) ? NBTC_STORAGE_DEPOSIT_AMOUNT : ((_c = accountInfo == null ? void 0 : accountInfo.relayer_fee) == null ? void 0 : _c.amount) || 0;
|
3261
3263
|
const hasDebtArrears = new Big(debtAmount).gt(0);
|
3262
3264
|
const hasRelayerFeeArrears = new Big(relayerFeeAmount).gt(0);
|
3263
3265
|
if (!hasDebtArrears && !hasRelayerFeeArrears)
|
@@ -3267,7 +3269,7 @@ function checkGasTokenArrears(accountInfo, env, autoDeposit) {
|
|
3267
3269
|
console.log("get_account:", accountInfo);
|
3268
3270
|
const action = {
|
3269
3271
|
receiver_id: config.accountContractId,
|
3270
|
-
amount: transferAmount,
|
3272
|
+
amount: transferAmount.toString(),
|
3271
3273
|
msg: JSON.stringify(hasDebtArrears ? "Repay" : "RelayerFee")
|
3272
3274
|
};
|
3273
3275
|
if (!autoDeposit)
|
@@ -3287,14 +3289,6 @@ function checkGasTokenArrears(accountInfo, env, autoDeposit) {
|
|
3287
3289
|
}
|
3288
3290
|
});
|
3289
3291
|
}
|
3290
|
-
function queryGasTokenArrears(env) {
|
3291
|
-
return __async(this, null, function* () {
|
3292
|
-
const config = yield getConfig(env);
|
3293
|
-
const csna = yield getCsnaAccountId(env);
|
3294
|
-
const accountInfo = yield getAccountInfo(csna, config.accountContractId);
|
3295
|
-
return accountInfo == null ? void 0 : accountInfo.debt_info;
|
3296
|
-
});
|
3297
|
-
}
|
3298
3292
|
function getBtcGasPrice() {
|
3299
3293
|
return __async(this, null, function* () {
|
3300
3294
|
const network = yield getNetwork();
|
@@ -3336,6 +3330,18 @@ function getBtcBalance() {
|
|
3336
3330
|
};
|
3337
3331
|
});
|
3338
3332
|
}
|
3333
|
+
function getNBTCBalance(address, env) {
|
3334
|
+
return __async(this, null, function* () {
|
3335
|
+
const config = yield getConfig(env || "mainnet");
|
3336
|
+
const rawBalance = yield nearCall(config.token, "ft_balance_of", {
|
3337
|
+
account_id: address
|
3338
|
+
});
|
3339
|
+
const balance = new Big(rawBalance).div(__pow(10, 8)).round(8, Big.roundDown).toNumber();
|
3340
|
+
const rawAvailableBalance = new Big(rawBalance).minus(1e3).toNumber();
|
3341
|
+
const availableBalance = new Big(rawAvailableBalance).div(__pow(10, 8)).round(8, Big.roundDown).toNumber();
|
3342
|
+
return { balance, availableBalance, rawBalance, rawAvailableBalance };
|
3343
|
+
});
|
3344
|
+
}
|
3339
3345
|
function sendBitcoin(address, amount, feeRate) {
|
3340
3346
|
return __async(this, null, function* () {
|
3341
3347
|
const { sendBitcoin: sendBitcoin2 } = getBtcProvider();
|
@@ -3345,28 +3351,29 @@ function sendBitcoin(address, amount, feeRate) {
|
|
3345
3351
|
}
|
3346
3352
|
function estimateDepositAmount(amount, option) {
|
3347
3353
|
return __async(this, null, function* () {
|
3348
|
-
|
3349
|
-
const csna = yield getCsnaAccountId((option == null ? void 0 : option.env) || "mainnet");
|
3350
|
-
const accountInfo = yield getAccountInfo(csna, config.accountContractId);
|
3351
|
-
const { receiveAmount } = yield getDepositAmount(amount, __spreadProps(__spreadValues({}, option), { isEstimate: true }));
|
3352
|
-
return (accountInfo == null ? void 0 : accountInfo.nonce) ? receiveAmount : new Big(receiveAmount).minus(NBTC_STORAGE_DEPOSIT_AMOUNT).round(0, Big.roundDown).toNumber();
|
3354
|
+
return amount;
|
3353
3355
|
});
|
3354
3356
|
}
|
3355
3357
|
function getDepositAmount(amount, option) {
|
3356
3358
|
return __async(this, null, function* () {
|
3357
|
-
const
|
3359
|
+
const env = (option == null ? void 0 : option.env) || "mainnet";
|
3360
|
+
const config = yield getConfig(env);
|
3361
|
+
const csna = yield getCsnaAccountId(env);
|
3362
|
+
const accountInfo = yield getAccountInfo(csna, config.accountContractId);
|
3363
|
+
const debtAction = yield checkGasTokenDebt(accountInfo, env, false);
|
3364
|
+
const repayAmount = (debtAction == null ? void 0 : debtAction.amount) || 0;
|
3358
3365
|
const {
|
3359
3366
|
deposit_bridge_fee: { fee_min, fee_rate },
|
3360
3367
|
min_deposit_amount
|
3361
3368
|
} = yield nearCall(config.bridgeContractId, "get_config", {});
|
3362
|
-
const depositAmount =
|
3363
|
-
const
|
3364
|
-
const
|
3365
|
-
console.log("getDepositAmount:", { depositAmount, receiveAmount, fee });
|
3369
|
+
const depositAmount = Math.max(Number(min_deposit_amount), Number(amount));
|
3370
|
+
const protocolFee = Math.max(Number(fee_min), Number(depositAmount) * fee_rate);
|
3371
|
+
const totalDepositAmount = new Big(depositAmount).plus(protocolFee).plus(repayAmount).round(0, Big.roundDown).toNumber();
|
3366
3372
|
return {
|
3367
3373
|
depositAmount,
|
3368
|
-
|
3369
|
-
|
3374
|
+
totalDepositAmount,
|
3375
|
+
protocolFee,
|
3376
|
+
repayAmount
|
3370
3377
|
};
|
3371
3378
|
});
|
3372
3379
|
}
|
@@ -3390,7 +3397,6 @@ function executeBTCDepositAndAction(_0) {
|
|
3390
3397
|
action,
|
3391
3398
|
amount,
|
3392
3399
|
feeRate,
|
3393
|
-
fixedAmount = true,
|
3394
3400
|
pollResult = true,
|
3395
3401
|
registerDeposit,
|
3396
3402
|
env = "mainnet"
|
@@ -3407,24 +3413,23 @@ function executeBTCDepositAndAction(_0) {
|
|
3407
3413
|
throw new Error("amount or action is required");
|
3408
3414
|
}
|
3409
3415
|
const csna = yield getCsnaAccountId(env);
|
3410
|
-
const
|
3411
|
-
if (new Big(
|
3416
|
+
const depositAmount = (_a = action ? action.amount : amount) != null ? _a : "0";
|
3417
|
+
if (new Big(depositAmount).lt(0)) {
|
3412
3418
|
throw new Error("amount must be greater than 0");
|
3413
3419
|
}
|
3414
|
-
const {
|
3420
|
+
const { totalDepositAmount, protocolFee, repayAmount } = yield getDepositAmount(depositAmount, {
|
3415
3421
|
env
|
3416
3422
|
});
|
3417
3423
|
const accountInfo = yield getAccountInfo(csna, config.accountContractId);
|
3418
3424
|
const newActions = [];
|
3419
|
-
const
|
3420
|
-
if (
|
3421
|
-
newActions.push(__spreadProps(__spreadValues({},
|
3425
|
+
const debtAction = yield checkGasTokenDebt(accountInfo, env, false);
|
3426
|
+
if (debtAction) {
|
3427
|
+
newActions.push(__spreadProps(__spreadValues({}, debtAction), {
|
3422
3428
|
gas: GAS_LIMIT
|
3423
3429
|
}));
|
3424
3430
|
}
|
3425
3431
|
if (action) {
|
3426
3432
|
newActions.push(__spreadProps(__spreadValues({}, action), {
|
3427
|
-
amount: (arrearsAction == null ? void 0 : arrearsAction.amount) && !fixedAmount ? new Big(receiveAmount).minus(arrearsAction.amount).toString() : receiveAmount.toString(),
|
3428
3433
|
gas: GAS_LIMIT
|
3429
3434
|
}));
|
3430
3435
|
}
|
@@ -3441,12 +3446,6 @@ function executeBTCDepositAndAction(_0) {
|
|
3441
3446
|
}
|
3442
3447
|
if (!(accountInfo == null ? void 0 : accountInfo.nonce)) {
|
3443
3448
|
storageDepositMsg.btc_public_key = btcPublicKey;
|
3444
|
-
newActions.push({
|
3445
|
-
receiver_id: config.accountContractId,
|
3446
|
-
amount: NBTC_STORAGE_DEPOSIT_AMOUNT.toString(),
|
3447
|
-
msg: JSON.stringify("RelayerFee"),
|
3448
|
-
gas: GAS_LIMIT
|
3449
|
-
});
|
3450
3449
|
}
|
3451
3450
|
const depositMsg = {
|
3452
3451
|
recipient_id: csna,
|
@@ -3460,10 +3459,14 @@ function executeBTCDepositAndAction(_0) {
|
|
3460
3459
|
{ deposit_msg: depositMsg }
|
3461
3460
|
);
|
3462
3461
|
const _feeRate = feeRate || (yield getBtcGasPrice());
|
3463
|
-
|
3464
|
-
|
3465
|
-
|
3466
|
-
|
3462
|
+
console.table({
|
3463
|
+
"User Deposit Address": userDepositAddress,
|
3464
|
+
"Deposit Amount": depositAmount,
|
3465
|
+
"Protocol Fee": protocolFee,
|
3466
|
+
"Repay Amount": repayAmount,
|
3467
|
+
"Total Deposit Amount": totalDepositAmount,
|
3468
|
+
"Fee Rate": _feeRate
|
3469
|
+
});
|
3467
3470
|
const postActionsStr = newActions.length > 0 ? JSON.stringify(newActions) : void 0;
|
3468
3471
|
yield preReceiveDepositMsg(config.base_url, {
|
3469
3472
|
btcPublicKey,
|
@@ -3471,7 +3474,7 @@ function executeBTCDepositAndAction(_0) {
|
|
3471
3474
|
postActions: postActionsStr,
|
3472
3475
|
extraMsg: depositMsg.extra_msg
|
3473
3476
|
});
|
3474
|
-
const txHash = yield sendBitcoin(userDepositAddress,
|
3477
|
+
const txHash = yield sendBitcoin(userDepositAddress, totalDepositAmount, _feeRate);
|
3475
3478
|
yield receiveDepositMsg(config.base_url, {
|
3476
3479
|
btcPublicKey,
|
3477
3480
|
txHash,
|
@@ -3516,6 +3519,148 @@ Sign up now: <a style="color: #ff7a00; text-decoration: underline;" href="https:
|
|
3516
3519
|
}
|
3517
3520
|
});
|
3518
3521
|
}
|
3522
|
+
function getWithdrawTransaction(_0) {
|
3523
|
+
return __async(this, arguments, function* ({
|
3524
|
+
amount,
|
3525
|
+
feeRate,
|
3526
|
+
env = "mainnet"
|
3527
|
+
}) {
|
3528
|
+
const provider = getBtcProvider();
|
3529
|
+
const btcAddress = yield provider.account;
|
3530
|
+
const config = yield getConfig(env);
|
3531
|
+
const brgConfig = yield nearCall(config.bridgeContractId, "get_config", {});
|
3532
|
+
if (brgConfig.min_withdraw_amount) {
|
3533
|
+
if (Number(amount) < Number(brgConfig.min_withdraw_amount)) {
|
3534
|
+
throw new Error("Mini withdraw amount is " + brgConfig.min_withdraw_amount);
|
3535
|
+
}
|
3536
|
+
}
|
3537
|
+
const feePercent = Number(brgConfig.withdraw_bridge_fee.fee_rate) * Number(amount);
|
3538
|
+
const withdrawFee = feePercent > Number(brgConfig.withdraw_bridge_fee.fee_min) ? feePercent : Number(brgConfig.withdraw_bridge_fee.fee_min);
|
3539
|
+
const allUTXO = yield nearCall(config.bridgeContractId, "get_utxos_paged", {});
|
3540
|
+
if (!allUTXO || Object.keys(allUTXO).length === 0) {
|
3541
|
+
throw new Error("The network is busy, please try again later.");
|
3542
|
+
}
|
3543
|
+
const utxos = Object.keys(allUTXO).map((key) => {
|
3544
|
+
const txid = key.split("@");
|
3545
|
+
return {
|
3546
|
+
txid: txid[0],
|
3547
|
+
vout: allUTXO[key].vout,
|
3548
|
+
value: Number(allUTXO[key].balance),
|
3549
|
+
script: allUTXO[key].script
|
3550
|
+
};
|
3551
|
+
});
|
3552
|
+
const _feeRate = feeRate || (yield getBtcGasPrice());
|
3553
|
+
const { inputs, outputs, fee } = coinselect(
|
3554
|
+
utxos,
|
3555
|
+
[{ address: btcAddress, value: Number(amount) }],
|
3556
|
+
Math.ceil(_feeRate)
|
3557
|
+
);
|
3558
|
+
if (!outputs || !inputs) {
|
3559
|
+
throw new Error("The network is busy, please try again later.");
|
3560
|
+
}
|
3561
|
+
const maxBtcFee = Number(brgConfig.max_btc_gas_fee);
|
3562
|
+
const newFee = fee;
|
3563
|
+
const withdrawChangeAddress = brgConfig.change_address;
|
3564
|
+
if (newFee > maxBtcFee) {
|
3565
|
+
throw new Error("Gas exceeds maximum value");
|
3566
|
+
}
|
3567
|
+
let userOutput, noUserOutput;
|
3568
|
+
for (let i = 0; i < outputs.length; i++) {
|
3569
|
+
const output = outputs[i];
|
3570
|
+
if (output.value.toString() === amount.toString()) {
|
3571
|
+
userOutput = output;
|
3572
|
+
} else {
|
3573
|
+
noUserOutput = output;
|
3574
|
+
}
|
3575
|
+
if (!output.address) {
|
3576
|
+
output.address = withdrawChangeAddress;
|
3577
|
+
}
|
3578
|
+
}
|
3579
|
+
userOutput.value = new Big(userOutput.value).minus(newFee).minus(withdrawFee).toNumber();
|
3580
|
+
if (noUserOutput) {
|
3581
|
+
noUserOutput.value = new Big(noUserOutput.value).plus(newFee).plus(withdrawFee).toNumber();
|
3582
|
+
} else {
|
3583
|
+
noUserOutput = {
|
3584
|
+
address: withdrawChangeAddress,
|
3585
|
+
value: new Big(newFee).plus(withdrawFee).toNumber()
|
3586
|
+
};
|
3587
|
+
outputs.push(noUserOutput);
|
3588
|
+
}
|
3589
|
+
const insufficientOutput = outputs.some((item) => item.value < 0);
|
3590
|
+
if (insufficientOutput) {
|
3591
|
+
throw new Error("Not enough gas");
|
3592
|
+
}
|
3593
|
+
const inputSum = inputs.reduce((sum, cur) => sum + Number(cur.value), 0);
|
3594
|
+
const outputSum = outputs.reduce((sum, cur) => sum + Number(cur.value), 0);
|
3595
|
+
if (newFee + outputSum !== inputSum) {
|
3596
|
+
throw new Error("compute error");
|
3597
|
+
}
|
3598
|
+
const network = yield getNetwork();
|
3599
|
+
const btcNetwork = network === "mainnet" ? bitcoin.networks.bitcoin : bitcoin.networks.testnet;
|
3600
|
+
const psbt = new bitcoin.Psbt({ network: btcNetwork });
|
3601
|
+
const btcRpcUrl = yield getBtcRpcUrl();
|
3602
|
+
for (let i = 0; i < inputs.length; i++) {
|
3603
|
+
const input = inputs[i];
|
3604
|
+
const txData = yield fetch(`${btcRpcUrl}/tx/${input.txid}`).then((res) => res.json());
|
3605
|
+
const inputOptions = {
|
3606
|
+
hash: input.txid,
|
3607
|
+
index: input.vout,
|
3608
|
+
sequence: 4294967293,
|
3609
|
+
witnessUtxo: {
|
3610
|
+
script: Buffer.from(txData.vout[input.vout].scriptpubkey, "hex"),
|
3611
|
+
value: input.value
|
3612
|
+
}
|
3613
|
+
};
|
3614
|
+
psbt.addInput(inputOptions);
|
3615
|
+
}
|
3616
|
+
outputs.forEach((output) => {
|
3617
|
+
psbt.addOutput({
|
3618
|
+
address: output.address,
|
3619
|
+
value: output.value
|
3620
|
+
});
|
3621
|
+
});
|
3622
|
+
const _inputs = inputs.map((item) => {
|
3623
|
+
return `${item.txid}:${item.vout}`;
|
3624
|
+
});
|
3625
|
+
const txOutputs = psbt.txOutputs.map((item) => {
|
3626
|
+
return {
|
3627
|
+
script_pubkey: uint8ArrayToHex(item.script),
|
3628
|
+
value: item.value
|
3629
|
+
};
|
3630
|
+
});
|
3631
|
+
const msg = {
|
3632
|
+
Withdraw: {
|
3633
|
+
target_btc_address: btcAddress,
|
3634
|
+
input: _inputs,
|
3635
|
+
output: txOutputs
|
3636
|
+
}
|
3637
|
+
};
|
3638
|
+
const csna = yield getCsnaAccountId(env);
|
3639
|
+
const transaction = {
|
3640
|
+
receiverId: config.token,
|
3641
|
+
signerId: csna,
|
3642
|
+
actions: [
|
3643
|
+
{
|
3644
|
+
type: "FunctionCall",
|
3645
|
+
params: {
|
3646
|
+
methodName: "ft_transfer_call",
|
3647
|
+
args: {
|
3648
|
+
receiver_id: config.bridgeContractId,
|
3649
|
+
amount: amount.toString(),
|
3650
|
+
msg: JSON.stringify(msg)
|
3651
|
+
},
|
3652
|
+
gas: "300000000000000",
|
3653
|
+
deposit: "1"
|
3654
|
+
}
|
3655
|
+
}
|
3656
|
+
]
|
3657
|
+
};
|
3658
|
+
return transaction;
|
3659
|
+
});
|
3660
|
+
}
|
3661
|
+
function uint8ArrayToHex(uint8Array) {
|
3662
|
+
return Array.from(uint8Array).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
3663
|
+
}
|
3519
3664
|
|
3520
3665
|
// src/core/setupBTCWallet.ts
|
3521
3666
|
var { transfer, functionCall } = actionCreators;
|
@@ -3741,7 +3886,7 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
|
|
3741
3886
|
const btcContext = window.btcContext;
|
3742
3887
|
const accountId = state.getAccount();
|
3743
3888
|
const accountInfo = yield getAccountInfo(accountId, currentConfig.accountContractId);
|
3744
|
-
yield
|
3889
|
+
yield checkGasTokenDebt(accountInfo, env, true);
|
3745
3890
|
const trans = [...params.transactions];
|
3746
3891
|
console.log("raw trans:", trans);
|
3747
3892
|
const gasTokenBalance = (accountInfo == null ? void 0 : accountInfo.gas_token[currentConfig.token]) || "0";
|
@@ -3950,7 +4095,7 @@ function setupBTCWallet({
|
|
3950
4095
|
if (!hasShownNotice) {
|
3951
4096
|
Dialog.alert({
|
3952
4097
|
title: "Notice",
|
3953
|
-
message: "You are currently using Satoshi Private Mainnet. This is a private version for testing. Please try a small amount of assets in
|
4098
|
+
message: "You are currently using Satoshi Private Mainnet. This is a private version for testing. Please try a small amount of assets in Ramp"
|
3954
4099
|
});
|
3955
4100
|
localStorage.setItem("satoshi_private_mainnet_notice", "true");
|
3956
4101
|
}
|
@@ -3979,7 +4124,7 @@ function setupBTCWallet({
|
|
3979
4124
|
|
3980
4125
|
// src/index.ts
|
3981
4126
|
var getVersion = () => {
|
3982
|
-
return "0.4.
|
4127
|
+
return "0.4.6-beta";
|
3983
4128
|
};
|
3984
4129
|
if (typeof window !== "undefined") {
|
3985
4130
|
window.__BTC_WALLET_VERSION = getVersion();
|
@@ -3997,8 +4142,8 @@ export {
|
|
3997
4142
|
UnisatConnector,
|
3998
4143
|
WizzConnector,
|
3999
4144
|
XverseConnector,
|
4000
|
-
checkGasTokenArrears,
|
4001
4145
|
checkGasTokenBalance,
|
4146
|
+
checkGasTokenDebt,
|
4002
4147
|
checkSatoshiWhitelist,
|
4003
4148
|
estimateDepositAmount,
|
4004
4149
|
executeBTCDepositAndAction,
|
@@ -4007,8 +4152,9 @@ export {
|
|
4007
4152
|
getBtcGasPrice,
|
4008
4153
|
getCsnaAccountId,
|
4009
4154
|
getDepositAmount,
|
4155
|
+
getNBTCBalance,
|
4010
4156
|
getVersion,
|
4011
|
-
|
4157
|
+
getWithdrawTransaction,
|
4012
4158
|
sendBitcoin,
|
4013
4159
|
setupBTCWallet,
|
4014
4160
|
useAccountContract,
|