@swapkit/toolboxes 1.0.0-beta.19 → 1.0.0-beta.20
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/{chunk-vhc011em.js → chunk-12xtvbsp.js} +3 -3
- package/dist/{chunk-vhc011em.js.map → chunk-12xtvbsp.js.map} +1 -1
- package/dist/{chunk-cv69ewns.js → chunk-9bqegm61.js} +1 -1
- package/dist/chunk-kbnwrc5b.js +4 -0
- package/dist/chunk-kbnwrc5b.js.map +10 -0
- package/dist/{chunk-38ztynv0.js → chunk-s47y8512.js} +2 -2
- package/dist/{chunk-38ztynv0.js.map → chunk-s47y8512.js.map} +1 -1
- package/dist/chunk-vtd17cje.js +3 -0
- package/dist/chunk-vtd17cje.js.map +10 -0
- package/dist/src/cosmos/index.cjs +2 -2
- package/dist/src/cosmos/index.cjs.map +3 -3
- package/dist/src/cosmos/index.js +2 -2
- package/dist/src/cosmos/index.js.map +3 -3
- package/dist/src/evm/index.cjs +2 -2
- package/dist/src/evm/index.cjs.map +3 -3
- package/dist/src/evm/index.js +2 -2
- package/dist/src/evm/index.js.map +3 -3
- package/dist/src/index.cjs +2 -2
- package/dist/src/index.cjs.map +3 -3
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +3 -3
- package/dist/src/near/index.cjs +3 -0
- package/dist/src/near/index.cjs.map +13 -0
- package/dist/src/near/index.js +3 -0
- package/dist/src/near/index.js.map +13 -0
- package/dist/src/radix/index.js +2 -2
- package/dist/src/radix/index.js.map +1 -1
- package/dist/src/ripple/index.js +1 -1
- package/dist/src/solana/index.js +2 -2
- package/dist/src/solana/index.js.map +1 -1
- package/dist/src/substrate/index.js +2 -2
- package/dist/src/substrate/index.js.map +1 -1
- package/dist/src/tron/index.js +2 -2
- package/dist/src/tron/index.js.map +1 -1
- package/dist/src/utxo/index.cjs +2 -2
- package/dist/src/utxo/index.cjs.map +3 -3
- package/dist/src/utxo/index.js +2 -2
- package/dist/src/utxo/index.js.map +3 -3
- package/package.json +10 -2
- package/src/cosmos/toolbox/cosmos.ts +9 -2
- package/src/evm/toolbox/baseEVMToolbox.ts +19 -12
- package/src/index.ts +12 -0
- package/src/near/helpers/contractFactory.ts +22 -0
- package/src/near/helpers/core.ts +86 -0
- package/src/near/helpers/gasEstimation.ts +110 -0
- package/src/near/helpers/index.ts +5 -0
- package/src/near/helpers/nep141.ts +110 -0
- package/src/near/index.ts +24 -0
- package/src/near/toolbox.ts +497 -0
- package/src/near/types/contract.ts +48 -0
- package/src/near/types/nep141.ts +66 -0
- package/src/near/types.ts +58 -0
- package/src/utxo/toolbox/utxo.ts +3 -2
- /package/dist/{chunk-cv69ewns.js.map → chunk-9bqegm61.js.map} +0 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { Account, Contract } from "near-api-js";
|
|
2
|
+
import { createNearContract } from "./contractFactory";
|
|
3
|
+
|
|
4
|
+
const DEFAULT_STORAGE_DEPOSIT = "1250000000000000000000"; // 0.00125 NEAR
|
|
5
|
+
|
|
6
|
+
// Define NEP-141 contract interface
|
|
7
|
+
interface NEP141Contract extends Contract {
|
|
8
|
+
// View methods
|
|
9
|
+
ft_balance_of(args: { account_id: string }): Promise<string>;
|
|
10
|
+
ft_total_supply(): Promise<string>;
|
|
11
|
+
ft_metadata(): Promise<any>;
|
|
12
|
+
storage_balance_of(args: { account_id: string }): Promise<any>;
|
|
13
|
+
storage_balance_bounds(): Promise<any>;
|
|
14
|
+
|
|
15
|
+
// Change methods
|
|
16
|
+
ft_transfer(args: any, gas: any, deposit: any): Promise<any>;
|
|
17
|
+
ft_transfer_call(args: any, gas: any, deposit: any): Promise<any>;
|
|
18
|
+
storage_deposit(args: any, gas: any, deposit: any): Promise<any>;
|
|
19
|
+
storage_withdraw(args: any, gas: any, deposit: any): Promise<any>;
|
|
20
|
+
storage_unregister(force?: boolean, gas?: any): Promise<any>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function createNEP141Token({
|
|
24
|
+
contractId,
|
|
25
|
+
account,
|
|
26
|
+
}: {
|
|
27
|
+
contractId: string;
|
|
28
|
+
account: Account;
|
|
29
|
+
}) {
|
|
30
|
+
const BN = (await import("bn.js")).default;
|
|
31
|
+
|
|
32
|
+
const contract = await createNearContract<NEP141Contract>({
|
|
33
|
+
account,
|
|
34
|
+
contractId,
|
|
35
|
+
viewMethods: [
|
|
36
|
+
"ft_balance_of",
|
|
37
|
+
"ft_total_supply",
|
|
38
|
+
"ft_metadata",
|
|
39
|
+
"storage_balance_of",
|
|
40
|
+
"storage_balance_bounds",
|
|
41
|
+
],
|
|
42
|
+
changeMethods: [
|
|
43
|
+
"ft_transfer",
|
|
44
|
+
"ft_transfer_call",
|
|
45
|
+
"storage_deposit",
|
|
46
|
+
"storage_withdraw",
|
|
47
|
+
"storage_unregister",
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Helper to ensure storage before transfers
|
|
52
|
+
const ensureStorageFor = async (accountId: string) => {
|
|
53
|
+
const balance = await contract.storage_balance_of({ account_id: accountId });
|
|
54
|
+
if (!balance) {
|
|
55
|
+
// Get minimum storage requirement
|
|
56
|
+
const bounds = await contract.storage_balance_bounds();
|
|
57
|
+
const deposit = bounds?.min || DEFAULT_STORAGE_DEPOSIT;
|
|
58
|
+
|
|
59
|
+
await contract.storage_deposit(
|
|
60
|
+
{ account_id: accountId },
|
|
61
|
+
new BN("100000000000000"), // 100 TGas
|
|
62
|
+
new BN(deposit),
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
transfer: async (receiverId: string, amount: string, memo?: string) => {
|
|
69
|
+
// Ensure recipient has storage before transfer
|
|
70
|
+
await ensureStorageFor(receiverId);
|
|
71
|
+
|
|
72
|
+
return contract.ft_transfer(
|
|
73
|
+
{ receiver_id: receiverId, amount, memo },
|
|
74
|
+
new BN("100000000000000"), // 100 TGas
|
|
75
|
+
new BN("1"), // 1 yoctoNEAR for security
|
|
76
|
+
);
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
transferCall: async (receiverId: string, amount: string, msg: string, memo?: string) => {
|
|
80
|
+
// Ensure recipient has storage before transfer
|
|
81
|
+
await ensureStorageFor(receiverId);
|
|
82
|
+
|
|
83
|
+
return contract.ft_transfer_call(
|
|
84
|
+
{ receiver_id: receiverId, amount, memo, msg },
|
|
85
|
+
new BN("100000000000000"), // 100 TGas
|
|
86
|
+
new BN("1"), // 1 yoctoNEAR for security
|
|
87
|
+
);
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
balanceOf: (accountId: string) => contract.ft_balance_of({ account_id: accountId }),
|
|
91
|
+
|
|
92
|
+
totalSupply: () => contract.ft_total_supply(),
|
|
93
|
+
|
|
94
|
+
metadata: () => contract.ft_metadata(),
|
|
95
|
+
|
|
96
|
+
storageBalanceOf: (accountId: string) => contract.storage_balance_of({ account_id: accountId }),
|
|
97
|
+
|
|
98
|
+
storageDeposit: (accountId?: string, amount?: string) =>
|
|
99
|
+
contract.storage_deposit(
|
|
100
|
+
{ account_id: accountId },
|
|
101
|
+
new BN("100000000000000"),
|
|
102
|
+
new BN(amount || DEFAULT_STORAGE_DEPOSIT),
|
|
103
|
+
),
|
|
104
|
+
|
|
105
|
+
ensureStorage: ensureStorageFor,
|
|
106
|
+
|
|
107
|
+
// Raw contract access for advanced use cases
|
|
108
|
+
contract,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export * from "./toolbox";
|
|
2
|
+
export * from "./types";
|
|
3
|
+
export * from "./helpers";
|
|
4
|
+
|
|
5
|
+
import type { getNearToolbox } from "./toolbox";
|
|
6
|
+
|
|
7
|
+
export type NearWallet = Awaited<ReturnType<typeof getNearToolbox>>;
|
|
8
|
+
|
|
9
|
+
export type {
|
|
10
|
+
NearContractInterface,
|
|
11
|
+
NearCallParams,
|
|
12
|
+
NearGasEstimateParams,
|
|
13
|
+
} from "./types/contract";
|
|
14
|
+
export type {
|
|
15
|
+
FungibleTokenMetadata,
|
|
16
|
+
StorageBalance,
|
|
17
|
+
StorageBalanceBounds,
|
|
18
|
+
NEP141Contract,
|
|
19
|
+
TokenTransferParams,
|
|
20
|
+
} from "./types/nep141";
|
|
21
|
+
|
|
22
|
+
export { createNEP141Token } from "./helpers/nep141";
|
|
23
|
+
export { tgasToGas, gasToTGas } from "./helpers/gasEstimation";
|
|
24
|
+
export { createNearContract } from "./helpers/contractFactory";
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AssetValue,
|
|
3
|
+
BaseDecimal,
|
|
4
|
+
Chain,
|
|
5
|
+
type DerivationPathArray,
|
|
6
|
+
SKConfig,
|
|
7
|
+
SwapKitError,
|
|
8
|
+
} from "@swapkit/helpers";
|
|
9
|
+
import type { Account } from "near-api-js";
|
|
10
|
+
import type { SignedTransaction, Transaction } from "near-api-js/lib/transaction";
|
|
11
|
+
import {
|
|
12
|
+
getFullAccessPublicKey,
|
|
13
|
+
getNearSignerFromPhrase,
|
|
14
|
+
getNearSignerFromPrivateKey,
|
|
15
|
+
validateNearAddress,
|
|
16
|
+
} from "./helpers";
|
|
17
|
+
import {
|
|
18
|
+
GAS_COSTS,
|
|
19
|
+
estimateBatchGas,
|
|
20
|
+
getContractMethodGas,
|
|
21
|
+
isAccountCreation,
|
|
22
|
+
isBatchTransaction,
|
|
23
|
+
isContractCall,
|
|
24
|
+
isContractDeployment,
|
|
25
|
+
isCustomEstimator,
|
|
26
|
+
isSimpleTransfer,
|
|
27
|
+
} from "./helpers/gasEstimation";
|
|
28
|
+
import { createNEP141Token } from "./helpers/nep141";
|
|
29
|
+
import type {
|
|
30
|
+
NearCreateTransactionParams,
|
|
31
|
+
NearFunctionCallParams,
|
|
32
|
+
NearToolboxParams,
|
|
33
|
+
NearTransferParams,
|
|
34
|
+
} from "./types";
|
|
35
|
+
import type { NearContractInterface, NearGasEstimateParams } from "./types/contract";
|
|
36
|
+
|
|
37
|
+
export async function getNearToolbox(toolboxParams?: NearToolboxParams) {
|
|
38
|
+
const { P, match } = await import("ts-pattern");
|
|
39
|
+
const { providers } = await import("near-api-js");
|
|
40
|
+
const signer = await match(toolboxParams)
|
|
41
|
+
.with({ phrase: P.string }, async (params) => {
|
|
42
|
+
const signer = await getNearSignerFromPhrase(params);
|
|
43
|
+
return signer;
|
|
44
|
+
})
|
|
45
|
+
.with({ signer: P.any }, ({ signer }) => signer)
|
|
46
|
+
.otherwise(() => undefined);
|
|
47
|
+
|
|
48
|
+
const url = SKConfig.get("rpcUrls")[Chain.Near];
|
|
49
|
+
|
|
50
|
+
const provider = new providers.JsonRpcProvider({ url });
|
|
51
|
+
|
|
52
|
+
async function getAccount(address?: string) {
|
|
53
|
+
if (!signer) {
|
|
54
|
+
throw new SwapKitError("toolbox_near_no_signer");
|
|
55
|
+
}
|
|
56
|
+
const { Account } = await import("near-api-js");
|
|
57
|
+
|
|
58
|
+
const _address = address || (await getAddress());
|
|
59
|
+
|
|
60
|
+
const account = new Account(_address, provider, signer);
|
|
61
|
+
|
|
62
|
+
return account;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function getAddress() {
|
|
66
|
+
if (!signer) {
|
|
67
|
+
throw new SwapKitError("toolbox_near_no_signer");
|
|
68
|
+
}
|
|
69
|
+
const address = await signer.getAddress();
|
|
70
|
+
return address;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function transfer(params: NearTransferParams) {
|
|
74
|
+
if (!signer) {
|
|
75
|
+
throw new SwapKitError("toolbox_near_no_signer");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const { recipient, assetValue } = params;
|
|
79
|
+
|
|
80
|
+
if (!validateNearAddress(recipient)) {
|
|
81
|
+
throw new SwapKitError("toolbox_near_invalid_address");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const account = await getAccount();
|
|
85
|
+
|
|
86
|
+
if (assetValue.isGasAsset === false) {
|
|
87
|
+
// NEP-141 token transfer
|
|
88
|
+
const contractId = assetValue.address;
|
|
89
|
+
if (!contractId) {
|
|
90
|
+
throw new SwapKitError("toolbox_near_missing_contract_address");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const amount = assetValue.getBaseValue("string");
|
|
94
|
+
|
|
95
|
+
return callFunction({
|
|
96
|
+
contractId,
|
|
97
|
+
methodName: "ft_transfer",
|
|
98
|
+
args: {
|
|
99
|
+
receiver_id: recipient,
|
|
100
|
+
amount,
|
|
101
|
+
memo: params.memo,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const transferAmount = assetValue.getBaseValue("string");
|
|
108
|
+
|
|
109
|
+
const result = await account.transfer({
|
|
110
|
+
receiverId: recipient,
|
|
111
|
+
amount: transferAmount,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return result.transaction.hash;
|
|
115
|
+
} catch (error) {
|
|
116
|
+
throw new SwapKitError("toolbox_near_transfer_failed", { error });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function createTransaction(params: NearCreateTransactionParams) {
|
|
121
|
+
const { recipient, assetValue, memo, feeRate: gas, attachedDeposit, sender } = params;
|
|
122
|
+
|
|
123
|
+
const signerId = sender || (await getAddress());
|
|
124
|
+
const publicKey = await getFullAccessPublicKey(provider, signerId);
|
|
125
|
+
|
|
126
|
+
const accessKey = await provider.query({
|
|
127
|
+
request_type: "view_access_key",
|
|
128
|
+
finality: "final",
|
|
129
|
+
account_id: signerId,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const nonce = (accessKey as any).nonce + 1;
|
|
133
|
+
|
|
134
|
+
const baseAmount = assetValue.getBaseValue("bigint");
|
|
135
|
+
|
|
136
|
+
const { SCHEMA } = await import("near-api-js/lib/transaction");
|
|
137
|
+
const { transactions, utils } = await import("near-api-js");
|
|
138
|
+
|
|
139
|
+
const txActions = [transactions.transfer(baseAmount)];
|
|
140
|
+
|
|
141
|
+
if (memo && attachedDeposit) {
|
|
142
|
+
txActions.push(
|
|
143
|
+
transactions.functionCall("memo", { memo }, BigInt(gas), BigInt(attachedDeposit)),
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const block = await provider.block({ finality: "final" });
|
|
148
|
+
const blockHash = utils.serialize.base_decode(block.header.hash);
|
|
149
|
+
|
|
150
|
+
const transaction = transactions.createTransaction(
|
|
151
|
+
signerId,
|
|
152
|
+
publicKey,
|
|
153
|
+
recipient,
|
|
154
|
+
nonce,
|
|
155
|
+
txActions,
|
|
156
|
+
blockHash,
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const serializedTx = utils.serialize.serialize(SCHEMA.Transaction, transaction);
|
|
160
|
+
const serializedBase64 = Buffer.from(serializedTx).toString("base64");
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
serialized: serializedBase64,
|
|
164
|
+
publicKey: publicKey.toString(),
|
|
165
|
+
details: {
|
|
166
|
+
signerId: await getAddress(),
|
|
167
|
+
nonce: nonce,
|
|
168
|
+
blockHash: utils.serialize.base_encode(blockHash),
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function createContractFunctionCall(params: {
|
|
174
|
+
accountId: string;
|
|
175
|
+
contractId: string;
|
|
176
|
+
methodName: string;
|
|
177
|
+
args: any;
|
|
178
|
+
gas: string;
|
|
179
|
+
attachedDeposit: string;
|
|
180
|
+
}) {
|
|
181
|
+
const { accountId } = params;
|
|
182
|
+
|
|
183
|
+
const publicKey = await getFullAccessPublicKey(provider, accountId);
|
|
184
|
+
|
|
185
|
+
const accessKey = await provider.query({
|
|
186
|
+
request_type: "view_access_key",
|
|
187
|
+
finality: "final",
|
|
188
|
+
account_id: accountId,
|
|
189
|
+
public_key: publicKey.toString(),
|
|
190
|
+
});
|
|
191
|
+
const nonce = (accessKey as any).nonce + 1;
|
|
192
|
+
|
|
193
|
+
const { SCHEMA } = await import("near-api-js/lib/transaction");
|
|
194
|
+
const { transactions, utils } = await import("near-api-js");
|
|
195
|
+
const block = await provider.block({ finality: "final" });
|
|
196
|
+
const blockHash = utils.serialize.base_decode(block.header.hash);
|
|
197
|
+
|
|
198
|
+
const actions = [
|
|
199
|
+
transactions.functionCall(
|
|
200
|
+
params.methodName,
|
|
201
|
+
Buffer.from(JSON.stringify(params.args)),
|
|
202
|
+
BigInt(params.gas),
|
|
203
|
+
BigInt(params.attachedDeposit),
|
|
204
|
+
),
|
|
205
|
+
];
|
|
206
|
+
|
|
207
|
+
const transaction = transactions.createTransaction(
|
|
208
|
+
accountId,
|
|
209
|
+
publicKey,
|
|
210
|
+
params.contractId,
|
|
211
|
+
nonce,
|
|
212
|
+
actions,
|
|
213
|
+
blockHash,
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
const serializedTx = utils.serialize.serialize(SCHEMA.Transaction, transaction);
|
|
217
|
+
const serializedBase64 = Buffer.from(serializedTx).toString("base64");
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
serialized: serializedBase64,
|
|
221
|
+
publicKey: publicKey.toString(),
|
|
222
|
+
details: {
|
|
223
|
+
signerId: accountId,
|
|
224
|
+
receiverId: params.contractId,
|
|
225
|
+
methodName: params.methodName,
|
|
226
|
+
nonce: nonce,
|
|
227
|
+
blockHash: utils.serialize.base_encode(blockHash),
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async function signTransaction(transaction: Transaction) {
|
|
233
|
+
if (!signer) {
|
|
234
|
+
throw new SwapKitError("toolbox_near_no_signer");
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Use the new signer interface method
|
|
238
|
+
const [_hash, signedTx] = await signer.signTransaction(transaction);
|
|
239
|
+
return signedTx;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async function broadcastTransaction(signedTransaction: SignedTransaction) {
|
|
243
|
+
const result = await provider.sendTransaction(signedTransaction);
|
|
244
|
+
return result.transaction.hash;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async function estimateTransactionFee(params: NearTransferParams | NearGasEstimateParams) {
|
|
248
|
+
if ("assetValue" in params) {
|
|
249
|
+
const baseTransferCost = "115123062500"; // gas units for transfer
|
|
250
|
+
const receiptCreationCost = "108059500000"; // gas units for receipt
|
|
251
|
+
|
|
252
|
+
const totalGasUnits = BigInt(baseTransferCost) + BigInt(receiptCreationCost);
|
|
253
|
+
|
|
254
|
+
const gasPrice = await getCurrentGasPrice();
|
|
255
|
+
|
|
256
|
+
// NEAR doesn't support fee multipliers - gas price is fixed by the network
|
|
257
|
+
const totalCostYocto = totalGasUnits * BigInt(gasPrice.toString());
|
|
258
|
+
|
|
259
|
+
return AssetValue.from({
|
|
260
|
+
chain: Chain.Near,
|
|
261
|
+
value: totalCostYocto.toString(),
|
|
262
|
+
fromBaseDecimal: BaseDecimal[Chain.Near],
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Handle new gas estimation params
|
|
267
|
+
const account = signer ? await getAccount() : undefined;
|
|
268
|
+
return estimateGas(params, account);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
async function getCurrentGasPrice() {
|
|
272
|
+
try {
|
|
273
|
+
const result = await provider.query({
|
|
274
|
+
request_type: "call_function",
|
|
275
|
+
finality: "final",
|
|
276
|
+
account_id: "system",
|
|
277
|
+
method_name: "gas_price",
|
|
278
|
+
args_base64: "",
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
return result;
|
|
282
|
+
} catch {
|
|
283
|
+
return "100000000"; // 0.0001 NEAR per Tgas
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async function createSubAccount(subAccountId: string, publicKey: string, initialBalance: string) {
|
|
288
|
+
if (!signer) {
|
|
289
|
+
throw new SwapKitError("toolbox_near_no_signer");
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const account = await getAccount();
|
|
293
|
+
const { utils } = await import("near-api-js");
|
|
294
|
+
|
|
295
|
+
const balanceInYocto = utils.format.parseNearAmount(initialBalance) || "0";
|
|
296
|
+
|
|
297
|
+
const result = await account.createAccount(
|
|
298
|
+
subAccountId,
|
|
299
|
+
utils.PublicKey.fromString(publicKey),
|
|
300
|
+
BigInt(balanceInYocto),
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
return result.transaction.hash;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async function callFunction(params: NearFunctionCallParams) {
|
|
307
|
+
try {
|
|
308
|
+
if (!signer) {
|
|
309
|
+
throw new SwapKitError("toolbox_near_no_signer");
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const { transactions } = await import("near-api-js");
|
|
313
|
+
|
|
314
|
+
const { contractId, methodName, args, deposit } = params;
|
|
315
|
+
const account = await getAccount();
|
|
316
|
+
|
|
317
|
+
const estimatedGas = await estimateGas({
|
|
318
|
+
methodName,
|
|
319
|
+
args: args || {},
|
|
320
|
+
contractId,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const functionAction = transactions.functionCall(
|
|
324
|
+
methodName,
|
|
325
|
+
args || {},
|
|
326
|
+
estimatedGas.getBaseValue("bigint"),
|
|
327
|
+
BigInt(deposit || "0"),
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
const result = await account.signAndSendTransaction({
|
|
331
|
+
receiverId: contractId,
|
|
332
|
+
actions: [functionAction],
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
return result.transaction.hash;
|
|
336
|
+
} catch (error) {
|
|
337
|
+
throw new SwapKitError("toolbox_near_transfer_failed", { error });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Create typed contract interface
|
|
342
|
+
async function createContract(contractInterface: NearContractInterface) {
|
|
343
|
+
const { createNearContract } = await import("./helpers/contractFactory");
|
|
344
|
+
const account = await getAccount();
|
|
345
|
+
|
|
346
|
+
return createNearContract({
|
|
347
|
+
account,
|
|
348
|
+
contractId: contractInterface.contractId,
|
|
349
|
+
viewMethods: contractInterface.viewMethods,
|
|
350
|
+
changeMethods: contractInterface.changeMethods,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
async function executeBatchTransaction(batch: { receiverId: string; actions: any[] }) {
|
|
355
|
+
if (!signer) {
|
|
356
|
+
throw new SwapKitError("toolbox_near_no_signer");
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (batch.actions.length === 0) {
|
|
360
|
+
throw new SwapKitError("toolbox_near_empty_batch");
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const account = await getAccount();
|
|
364
|
+
|
|
365
|
+
// Use account.signAndSendTransaction for batch operations
|
|
366
|
+
const result = await account.signAndSendTransaction({
|
|
367
|
+
receiverId: batch.receiverId,
|
|
368
|
+
actions: batch.actions,
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
return result.transaction.hash;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
async function nep141(contractId: string) {
|
|
375
|
+
const account = await getAccount();
|
|
376
|
+
return createNEP141Token({ contractId, account });
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
async function getBalance(address: string) {
|
|
380
|
+
try {
|
|
381
|
+
const account = await getAccount(address);
|
|
382
|
+
|
|
383
|
+
let nativeBalance: AssetValue;
|
|
384
|
+
try {
|
|
385
|
+
const value = await account.getBalance();
|
|
386
|
+
|
|
387
|
+
nativeBalance = AssetValue.from({
|
|
388
|
+
chain: Chain.Near,
|
|
389
|
+
value,
|
|
390
|
+
fromBaseDecimal: BaseDecimal[Chain.Near],
|
|
391
|
+
});
|
|
392
|
+
} catch {
|
|
393
|
+
nativeBalance = AssetValue.from({
|
|
394
|
+
chain: Chain.Near,
|
|
395
|
+
value: "0",
|
|
396
|
+
fromBaseDecimal: BaseDecimal[Chain.Near],
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// // Then, fetch token balances from API
|
|
401
|
+
// let tokenBalances: AssetValue[] = [];
|
|
402
|
+
// try {
|
|
403
|
+
// const apiBalances = await SwapKitApi.getChainBalance({
|
|
404
|
+
// chain: Chain.Near,
|
|
405
|
+
// address,
|
|
406
|
+
// scamFilter,
|
|
407
|
+
// });
|
|
408
|
+
|
|
409
|
+
// tokenBalances = apiBalances
|
|
410
|
+
// .filter(({ identifier }) => identifier !== Chain.Near) // Filter out native NEAR
|
|
411
|
+
// .map(({ identifier, value, decimal }) => {
|
|
412
|
+
// return new AssetValue({
|
|
413
|
+
// decimal: decimal || BaseDecimal[Chain.Near],
|
|
414
|
+
// value,
|
|
415
|
+
// identifier,
|
|
416
|
+
// });
|
|
417
|
+
// });
|
|
418
|
+
// } catch (error) {
|
|
419
|
+
// // If API fails, just return on-chain balance
|
|
420
|
+
// console.warn("Failed to fetch token balances from API:", error);
|
|
421
|
+
// }
|
|
422
|
+
|
|
423
|
+
// Merge native balance with token balances
|
|
424
|
+
// return [nativeBalance, ...tokenBalances];
|
|
425
|
+
return [nativeBalance];
|
|
426
|
+
} catch (error) {
|
|
427
|
+
throw new SwapKitError("toolbox_near_balance_failed", { error });
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
async function estimateGas(params: NearGasEstimateParams, account?: Account) {
|
|
432
|
+
const gasInTGas = await match(params)
|
|
433
|
+
.when(isSimpleTransfer, () => GAS_COSTS.SIMPLE_TRANSFER)
|
|
434
|
+
.when(isContractCall, (p) => getContractMethodGas(p.methodName))
|
|
435
|
+
.when(isBatchTransaction, (p) => estimateBatchGas(p.actions))
|
|
436
|
+
.when(isAccountCreation, () => GAS_COSTS.ACCOUNT_CREATION)
|
|
437
|
+
.when(isContractDeployment, () => GAS_COSTS.CONTRACT_DEPLOYMENT)
|
|
438
|
+
.when(isCustomEstimator, (p) => {
|
|
439
|
+
if (!account) {
|
|
440
|
+
throw new SwapKitError("toolbox_near_no_account");
|
|
441
|
+
}
|
|
442
|
+
return p.customEstimator(account);
|
|
443
|
+
})
|
|
444
|
+
.otherwise(() => {
|
|
445
|
+
throw new SwapKitError("toolbox_near_invalid_gas_params");
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// Convert TGas to gas price in NEAR
|
|
449
|
+
const gasPrice = await getGasPrice();
|
|
450
|
+
const gasInUnits = BigInt(gasInTGas) * BigInt(10 ** 12); // Convert TGas to gas units
|
|
451
|
+
const costInYoctoNear = gasInUnits * BigInt(gasPrice);
|
|
452
|
+
|
|
453
|
+
return AssetValue.from({
|
|
454
|
+
chain: Chain.Near,
|
|
455
|
+
value: costInYoctoNear,
|
|
456
|
+
fromBaseDecimal: BaseDecimal[Chain.Near],
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Get current gas price from network
|
|
461
|
+
async function getGasPrice() {
|
|
462
|
+
try {
|
|
463
|
+
const result = await provider.gasPrice(null);
|
|
464
|
+
return result.gas_price || "100000000";
|
|
465
|
+
} catch (_error) {
|
|
466
|
+
// Fallback to default
|
|
467
|
+
return "100000000";
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return {
|
|
472
|
+
getAddress,
|
|
473
|
+
getPublicKey: async () => (signer ? (await signer.getPublicKey()).toString() : ""),
|
|
474
|
+
provider,
|
|
475
|
+
transfer,
|
|
476
|
+
createTransaction,
|
|
477
|
+
createContractFunctionCall,
|
|
478
|
+
estimateTransactionFee,
|
|
479
|
+
broadcastTransaction,
|
|
480
|
+
signTransaction,
|
|
481
|
+
getBalance,
|
|
482
|
+
validateAddress: validateNearAddress,
|
|
483
|
+
getSignerFromPhrase: (params: {
|
|
484
|
+
phrase: string;
|
|
485
|
+
derivationPath?: DerivationPathArray;
|
|
486
|
+
index?: number;
|
|
487
|
+
}) => getNearSignerFromPhrase(params),
|
|
488
|
+
getSignerFromPrivateKey: getNearSignerFromPrivateKey,
|
|
489
|
+
callFunction,
|
|
490
|
+
createSubAccount,
|
|
491
|
+
createContract,
|
|
492
|
+
executeBatchTransaction,
|
|
493
|
+
nep141,
|
|
494
|
+
getGasPrice,
|
|
495
|
+
estimateGas,
|
|
496
|
+
};
|
|
497
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Account } from "near-api-js";
|
|
2
|
+
|
|
3
|
+
// Custom interface for contract metadata (not in SDK)
|
|
4
|
+
export interface NearContractInterface {
|
|
5
|
+
contractId: string;
|
|
6
|
+
viewMethods: string[];
|
|
7
|
+
changeMethods: string[];
|
|
8
|
+
metadata?: {
|
|
9
|
+
version: string;
|
|
10
|
+
standards: string[]; // e.g., ["nep141", "nep171"]
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Enhanced call parameters
|
|
15
|
+
export interface NearCallParams {
|
|
16
|
+
contractId: string;
|
|
17
|
+
methodName: string;
|
|
18
|
+
args?: Record<string, any>;
|
|
19
|
+
gas?: string | any; // BN type
|
|
20
|
+
attachedDeposit?: string | any; // BN type
|
|
21
|
+
isView?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Gas estimation using discriminated unions for type inference
|
|
25
|
+
export type NearGasEstimateParams =
|
|
26
|
+
| {
|
|
27
|
+
recipient: string;
|
|
28
|
+
amount: string;
|
|
29
|
+
}
|
|
30
|
+
| {
|
|
31
|
+
contractId: string;
|
|
32
|
+
methodName: string;
|
|
33
|
+
args?: Record<string, any>;
|
|
34
|
+
attachedDeposit?: string;
|
|
35
|
+
}
|
|
36
|
+
| {
|
|
37
|
+
actions: any[]; // Action type from near-api-js
|
|
38
|
+
}
|
|
39
|
+
| {
|
|
40
|
+
newAccountId: string;
|
|
41
|
+
publicKey?: string;
|
|
42
|
+
}
|
|
43
|
+
| {
|
|
44
|
+
contractCode: Uint8Array;
|
|
45
|
+
}
|
|
46
|
+
| {
|
|
47
|
+
customEstimator: (account: Account) => Promise<string>;
|
|
48
|
+
};
|