@tomo-inc/chains-service 0.0.8 → 0.0.9
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/index.cjs +1258 -1035
- package/dist/index.d.cts +263 -90
- package/dist/index.d.ts +263 -90
- package/dist/index.js +1229 -1016
- package/package.json +2 -2
- package/src/api/network-data.ts +14 -0
- package/src/dogecoin/rpc.ts +10 -191
- package/src/dogecoin/service.ts +2 -16
- package/src/dogecoin/utils-doge.ts +19 -6
- package/src/index.ts +8 -4
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { ChainTypes, SupportedChainTypes,
|
|
2
|
-
import Bignumber, { BigNumber } from 'bignumber.js';
|
|
3
|
-
import { toHex, parseUnits, isAddressEqual, createPublicClient, http, hexToBigInt, numberToHex, isHex, fromHex, parseTransaction, formatUnits, encodeFunctionData, erc20Abi } from 'viem';
|
|
1
|
+
import { ChainTypes, SupportedChainTypes, TomoApiDomains, cache, getExplorerUrl } from '@tomo-inc/wallet-utils';
|
|
4
2
|
import axios from 'axios';
|
|
5
3
|
import CryptoJS from 'crypto-js';
|
|
4
|
+
import Bignumber, { BigNumber } from 'bignumber.js';
|
|
5
|
+
import { Psbt, Transaction, address } from 'bitcoinjs-lib';
|
|
6
|
+
import { toHex as toHex$1, parseUnits, isAddressEqual, createPublicClient, http, hexToBigInt, numberToHex, isHex, fromHex as fromHex$1, parseTransaction, formatUnits, encodeFunctionData, erc20Abi } from 'viem';
|
|
6
7
|
import { getAssociatedTokenAddress, createAssociatedTokenAccountInstruction, createTransferInstruction, TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
7
8
|
import { PublicKey, Connection, VersionedTransaction, sendAndConfirmRawTransaction, Transaction as Transaction$1, SystemProgram, LAMPORTS_PER_SOL } from '@solana/web3.js';
|
|
8
|
-
import { Psbt, Transaction, address } from 'bitcoinjs-lib';
|
|
9
9
|
|
|
10
10
|
var __create = Object.create;
|
|
11
11
|
var __defProp = Object.defineProperty;
|
|
@@ -16,6 +16,10 @@ var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
|
16
16
|
var __commonJS = (cb, mod) => function __require() {
|
|
17
17
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
18
18
|
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
22
|
+
};
|
|
19
23
|
var __copyProps = (to, from, except, desc) => {
|
|
20
24
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
21
25
|
for (let key of __getOwnPropNames(from))
|
|
@@ -3276,6 +3280,20 @@ var loadNetworks = (WALLET_DOMAIN) => {
|
|
|
3276
3280
|
supportGift: false,
|
|
3277
3281
|
supportHistory: true
|
|
3278
3282
|
},
|
|
3283
|
+
{
|
|
3284
|
+
chainId: 36888,
|
|
3285
|
+
chainIndex: 3688800,
|
|
3286
|
+
name: "ABCORE",
|
|
3287
|
+
chainName: "AB Core",
|
|
3288
|
+
rpcUrls: ["https://rpc1.core.ab.org"],
|
|
3289
|
+
blockExplorerUrl: "https://explorer.core.ab.org",
|
|
3290
|
+
platformType: "EVM",
|
|
3291
|
+
isTestnet: false,
|
|
3292
|
+
icon: "/assets/ab.svg",
|
|
3293
|
+
supportSwap: true,
|
|
3294
|
+
supportGift: false,
|
|
3295
|
+
supportHistory: true
|
|
3296
|
+
},
|
|
3279
3297
|
{
|
|
3280
3298
|
chainId: 6281971,
|
|
3281
3299
|
chainIndex: 628197100,
|
|
@@ -3914,571 +3932,903 @@ var BaseService = class {
|
|
|
3914
3932
|
this.approveParams = params;
|
|
3915
3933
|
}
|
|
3916
3934
|
};
|
|
3917
|
-
function getRPCClient(network2) {
|
|
3918
|
-
const { chainId, name, rpcUrls, nativeCurrencyDecimals, nativeCurrencyName, nativeCurrencySymbol } = network2;
|
|
3919
|
-
const myCustomChain = {
|
|
3920
|
-
id: Number(chainId) || chainId,
|
|
3921
|
-
name,
|
|
3922
|
-
nativeCurrency: {
|
|
3923
|
-
name: nativeCurrencyName,
|
|
3924
|
-
symbol: nativeCurrencySymbol,
|
|
3925
|
-
decimals: nativeCurrencyDecimals
|
|
3926
|
-
},
|
|
3927
|
-
rpcUrls: {
|
|
3928
|
-
default: {
|
|
3929
|
-
http: rpcUrls,
|
|
3930
|
-
webSocket: []
|
|
3931
|
-
},
|
|
3932
|
-
public: {
|
|
3933
|
-
http: rpcUrls,
|
|
3934
|
-
webSocket: []
|
|
3935
|
-
}
|
|
3936
|
-
},
|
|
3937
|
-
blockExplorers: {
|
|
3938
|
-
default: {
|
|
3939
|
-
name: "Explorer",
|
|
3940
|
-
url: rpcUrls[0]
|
|
3941
|
-
}
|
|
3942
|
-
}
|
|
3943
|
-
};
|
|
3944
|
-
const rpcClient = createPublicClient({
|
|
3945
|
-
chain: myCustomChain,
|
|
3946
|
-
pollingInterval: 1e4,
|
|
3947
|
-
cacheTime: 1e4,
|
|
3948
|
-
transport: http()
|
|
3949
|
-
});
|
|
3950
|
-
return { rpcClient };
|
|
3951
|
-
}
|
|
3952
|
-
|
|
3953
|
-
// src/types/account.ts
|
|
3954
|
-
var AccountType = /* @__PURE__ */ ((AccountType2) => {
|
|
3955
|
-
AccountType2["EOA"] = "EOA";
|
|
3956
|
-
AccountType2["SOCIAL"] = "SOCIAL";
|
|
3957
|
-
return AccountType2;
|
|
3958
|
-
})(AccountType || {});
|
|
3959
|
-
|
|
3960
|
-
// src/types/wallet.ts
|
|
3961
|
-
var TxTypes = /* @__PURE__ */ ((TxTypes2) => {
|
|
3962
|
-
TxTypes2[TxTypes2["swap"] = 1] = "swap";
|
|
3963
|
-
TxTypes2[TxTypes2["bridge"] = 2] = "bridge";
|
|
3964
|
-
TxTypes2[TxTypes2["receive"] = 31] = "receive";
|
|
3965
|
-
TxTypes2[TxTypes2["send"] = 32] = "send";
|
|
3966
|
-
TxTypes2[TxTypes2["approve"] = 4] = "approve";
|
|
3967
|
-
TxTypes2[TxTypes2["contractInteraction"] = 5] = "contractInteraction";
|
|
3968
|
-
TxTypes2[TxTypes2["redPocket"] = 6] = "redPocket";
|
|
3969
|
-
return TxTypes2;
|
|
3970
|
-
})(TxTypes || {});
|
|
3971
3935
|
|
|
3972
|
-
// src/
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
chainId = fromHex(chainId, "number").toString();
|
|
3980
|
-
return {
|
|
3981
|
-
chainId,
|
|
3982
|
-
chainIdHex: chainIdHex2,
|
|
3983
|
-
chainUid: `${chainType}:${chainId}`
|
|
3984
|
-
};
|
|
3936
|
+
// src/dogecoin/base.ts
|
|
3937
|
+
function fromHex(hex) {
|
|
3938
|
+
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
3939
|
+
const paddedHex = cleanHex.length % 2 === 0 ? cleanHex : "0" + cleanHex;
|
|
3940
|
+
const bytes = new Uint8Array(paddedHex.length / 2);
|
|
3941
|
+
for (let i = 0; i < paddedHex.length; i += 2) {
|
|
3942
|
+
bytes[i / 2] = parseInt(paddedHex.substr(i, 2), 16);
|
|
3985
3943
|
}
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
}
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
return
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
3944
|
+
return bytes;
|
|
3945
|
+
}
|
|
3946
|
+
function toHex(data) {
|
|
3947
|
+
if (typeof data === "string") {
|
|
3948
|
+
return data.startsWith("0x") ? data.slice(2) : data;
|
|
3949
|
+
}
|
|
3950
|
+
const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
3951
|
+
return buffer.toString("hex");
|
|
3952
|
+
}
|
|
3953
|
+
function toBase64(data) {
|
|
3954
|
+
if (typeof data === "string") {
|
|
3955
|
+
const buffer2 = Buffer.from(data, "hex");
|
|
3956
|
+
return buffer2.toString("base64");
|
|
3957
|
+
}
|
|
3958
|
+
const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
3959
|
+
return buffer.toString("base64");
|
|
3960
|
+
}
|
|
3961
|
+
function fromBase64(base64) {
|
|
3962
|
+
const buffer = Buffer.from(base64, "base64");
|
|
3963
|
+
return new Uint8Array(buffer);
|
|
3964
|
+
}
|
|
3965
|
+
function toBase58(data) {
|
|
3966
|
+
throw new Error("toBase58 requires bs58 package. Install it: pnpm add bs58");
|
|
4005
3967
|
}
|
|
3968
|
+
var BaseConfig = SupportedChainTypes[ChainTypes.DOGE];
|
|
3969
|
+
var BLOCK_CONFIRMATIONS = 1;
|
|
3970
|
+
var FEE_RATE_KB = 0.5;
|
|
3971
|
+
var DECIMALS = 1e8;
|
|
3972
|
+
var TRANSACTION_PAGE_SIZE = 10;
|
|
3973
|
+
var MYDOGE_BASE_URL = "https://api.mydoge.com";
|
|
3974
|
+
var RPC_URL = "https://api.bitcore.io/api/DOGE/mainnet";
|
|
3975
|
+
var RPC_TIMEOUT = 20 * 1e3;
|
|
3976
|
+
var TX_OVERHEAD = 10;
|
|
3977
|
+
var P2SH_INPUT_SIZE = 148;
|
|
3978
|
+
var TX_OUTPUT_SIZE = 34;
|
|
3979
|
+
var DEFAULT_OUTPUT_COUNT = 2;
|
|
3980
|
+
var TX_SIZE = 1 * P2SH_INPUT_SIZE + DEFAULT_OUTPUT_COUNT * TX_OUTPUT_SIZE + TX_OVERHEAD;
|
|
3981
|
+
var network = {
|
|
3982
|
+
messagePrefix: "Dogecoin Signed Message:\n",
|
|
3983
|
+
bech32: "dc",
|
|
3984
|
+
bip44: 3,
|
|
3985
|
+
bip32: {
|
|
3986
|
+
public: 49990397,
|
|
3987
|
+
private: 49988504
|
|
3988
|
+
},
|
|
3989
|
+
pubKeyHash: 30,
|
|
3990
|
+
scriptHash: 22,
|
|
3991
|
+
wif: 158
|
|
3992
|
+
};
|
|
4006
3993
|
|
|
4007
|
-
// src/
|
|
4008
|
-
var
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
3994
|
+
// src/dogecoin/rpc.ts
|
|
3995
|
+
var rpc_exports = {};
|
|
3996
|
+
__export(rpc_exports, {
|
|
3997
|
+
estimateSmartFee: () => estimateSmartFee,
|
|
3998
|
+
getBalance: () => getBalance,
|
|
3999
|
+
getDogeFeeByBlock: () => getDogeFeeByBlock,
|
|
4000
|
+
getInscriptionsUtxo: () => getInscriptionsUtxo,
|
|
4001
|
+
getInscriptionsUtxos: () => getInscriptionsUtxos,
|
|
4002
|
+
getSpendableUtxos: () => getSpendableUtxos,
|
|
4003
|
+
getTransactions: () => getTransactions,
|
|
4004
|
+
getTxDetail: () => getTxDetail,
|
|
4005
|
+
getUnSpentUtxos: () => getUnSpentUtxos,
|
|
4006
|
+
mydoge: () => mydoge,
|
|
4007
|
+
onCreateTransaction: () => onCreateTransaction,
|
|
4008
|
+
sendDogeTx: () => sendDogeTx,
|
|
4009
|
+
sendTransaction: () => sendTransaction
|
|
4010
|
+
});
|
|
4011
|
+
var KOINU_PER_DOGE = new BigNumber(DECIMALS);
|
|
4012
|
+
function toSatoshi(bitcion) {
|
|
4013
|
+
try {
|
|
4014
|
+
const amount = new BigNumber(bitcion);
|
|
4015
|
+
if (amount.isNaN() || amount.isNegative()) {
|
|
4016
|
+
throw new Error("Invalid amount");
|
|
4017
|
+
}
|
|
4018
|
+
return amount.times(KOINU_PER_DOGE).integerValue(BigNumber.ROUND_DOWN).toNumber();
|
|
4019
|
+
} catch (error) {
|
|
4020
|
+
throw new Error(`toSatoshi failed: ${error.message}`);
|
|
4014
4021
|
}
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4022
|
+
}
|
|
4023
|
+
function toBitcoin(satoshis) {
|
|
4024
|
+
try {
|
|
4025
|
+
const amount = new BigNumber(satoshis);
|
|
4026
|
+
if (amount.isNaN() || amount.isNegative()) {
|
|
4027
|
+
throw new Error("Invalid Koinu amount");
|
|
4018
4028
|
}
|
|
4019
|
-
return
|
|
4029
|
+
return amount.dividedBy(KOINU_PER_DOGE).toNumber();
|
|
4030
|
+
} catch (error) {
|
|
4031
|
+
throw new Error(`toBitcoin failed: ${error.message}`);
|
|
4020
4032
|
}
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4033
|
+
}
|
|
4034
|
+
function addUsedUtxos(newUsedUtxos) {
|
|
4035
|
+
const usedUtxos = cache.get("UsedUtxos") || {};
|
|
4036
|
+
for (const txid in newUsedUtxos) {
|
|
4037
|
+
usedUtxos[txid] = 1;
|
|
4024
4038
|
}
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4039
|
+
cache.set("UsedUtxos", usedUtxos, false);
|
|
4040
|
+
}
|
|
4041
|
+
function getUsedUtxos() {
|
|
4042
|
+
return cache.get("UsedUtxos") || {};
|
|
4043
|
+
}
|
|
4044
|
+
async function createPsbt({
|
|
4045
|
+
from,
|
|
4046
|
+
to,
|
|
4047
|
+
amount,
|
|
4048
|
+
fee,
|
|
4049
|
+
spendableUtxos
|
|
4050
|
+
}) {
|
|
4051
|
+
const utxos = spendableUtxos;
|
|
4052
|
+
if (!utxos || utxos.length === 0) {
|
|
4053
|
+
throw new Error("no spendable utxos");
|
|
4028
4054
|
}
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4055
|
+
const sendAmount = toSatoshi(amount);
|
|
4056
|
+
const sendCost = toSatoshi(fee);
|
|
4057
|
+
const totalNeeded = sendAmount + sendCost;
|
|
4058
|
+
const sortedUtxos = utxos.sort((a, b) => b.outputValue - a.outputValue);
|
|
4059
|
+
const selectedUtxos = [];
|
|
4060
|
+
let accumulatedAmount = 0;
|
|
4061
|
+
for (const utxo of sortedUtxos) {
|
|
4062
|
+
if (accumulatedAmount >= totalNeeded) break;
|
|
4063
|
+
selectedUtxos.push(utxo);
|
|
4064
|
+
accumulatedAmount += Number(utxo.outputValue);
|
|
4037
4065
|
}
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
const currentNetwork = await this.networks.getCurrentNetwork();
|
|
4041
|
-
return currentNetwork;
|
|
4066
|
+
if (accumulatedAmount < totalNeeded) {
|
|
4067
|
+
throw new Error("not enough funds to cover amount and fee");
|
|
4042
4068
|
}
|
|
4043
|
-
async
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4069
|
+
const utxoDetailPromises = selectedUtxos.map(async (utxo) => {
|
|
4070
|
+
try {
|
|
4071
|
+
const utxoDetail = await getTxDetail(utxo.txid);
|
|
4072
|
+
return { utxo, utxoDetail };
|
|
4073
|
+
} catch (error) {
|
|
4074
|
+
return { utxo, utxoDetail: null };
|
|
4048
4075
|
}
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
if (
|
|
4056
|
-
|
|
4076
|
+
});
|
|
4077
|
+
const utxoResults = await Promise.all(utxoDetailPromises);
|
|
4078
|
+
const inputs = [];
|
|
4079
|
+
const usingUtxos = {};
|
|
4080
|
+
let addedAmount = 0;
|
|
4081
|
+
for (const { utxo, utxoDetail } of utxoResults) {
|
|
4082
|
+
if (addedAmount >= totalNeeded) break;
|
|
4083
|
+
const { txid, vout, outputValue, address = from } = utxo;
|
|
4084
|
+
if (utxoDetail?.hex && !usingUtxos[txid]) {
|
|
4085
|
+
inputs.push({
|
|
4086
|
+
txId: txid,
|
|
4087
|
+
vOut: vout,
|
|
4088
|
+
amount: Number(outputValue),
|
|
4089
|
+
nonWitnessUtxo: utxoDetail.hex,
|
|
4090
|
+
address
|
|
4091
|
+
});
|
|
4092
|
+
usingUtxos[txid] = 1;
|
|
4093
|
+
addedAmount += Number(outputValue);
|
|
4057
4094
|
}
|
|
4058
|
-
const chainInfo = await this.networks.getNetworkByChainId(res.chainId);
|
|
4059
|
-
if (!chainInfo) {
|
|
4060
|
-
return false;
|
|
4061
|
-
}
|
|
4062
|
-
return isEvmChain(chainInfo);
|
|
4063
4095
|
}
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
if (!isAddressEqual(accounts[0].address, address)) {
|
|
4067
|
-
throw new Error("address is not the current account");
|
|
4068
|
-
}
|
|
4069
|
-
const signature = await this.accountInfo.signMessage(message);
|
|
4070
|
-
return signature;
|
|
4096
|
+
if (addedAmount < totalNeeded) {
|
|
4097
|
+
throw new Error("not enough funds to cover amount and fee");
|
|
4071
4098
|
}
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4099
|
+
const outputs = [
|
|
4100
|
+
{
|
|
4101
|
+
address: to,
|
|
4102
|
+
amount: sendAmount
|
|
4076
4103
|
}
|
|
4077
|
-
|
|
4078
|
-
|
|
4104
|
+
];
|
|
4105
|
+
const changeAmount = addedAmount - sendAmount - sendCost;
|
|
4106
|
+
if (changeAmount > 0) {
|
|
4107
|
+
outputs.push({
|
|
4108
|
+
address: from,
|
|
4109
|
+
amount: changeAmount
|
|
4110
|
+
});
|
|
4079
4111
|
}
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
const
|
|
4092
|
-
return
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
return "0";
|
|
4112
|
+
const params = {
|
|
4113
|
+
address: from,
|
|
4114
|
+
inputs,
|
|
4115
|
+
outputs
|
|
4116
|
+
};
|
|
4117
|
+
const psbtBase64 = DogecoinUtils.buildPsbtToBase64(params);
|
|
4118
|
+
return { psbtBase64, usingUtxos };
|
|
4119
|
+
}
|
|
4120
|
+
function decodePsbt(psbt, type = "hex") {
|
|
4121
|
+
try {
|
|
4122
|
+
if (type === "base64") {
|
|
4123
|
+
const psbtHex = toHex(fromBase64(psbt));
|
|
4124
|
+
return Psbt.fromHex(psbtHex, {
|
|
4125
|
+
network
|
|
4126
|
+
});
|
|
4096
4127
|
}
|
|
4128
|
+
return Psbt.fromHex(psbt, {
|
|
4129
|
+
network
|
|
4130
|
+
});
|
|
4131
|
+
} catch (error) {
|
|
4132
|
+
console.error("Failed to decode PSBT:", error);
|
|
4133
|
+
throw error;
|
|
4097
4134
|
}
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4135
|
+
}
|
|
4136
|
+
var TransactionParser = class {
|
|
4137
|
+
rawTx;
|
|
4138
|
+
constructor(rawTx) {
|
|
4139
|
+
this.rawTx = rawTx;
|
|
4140
|
+
}
|
|
4141
|
+
hexToText(hex) {
|
|
4142
|
+
let str = "";
|
|
4143
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
4144
|
+
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
|
4104
4145
|
}
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
const
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4146
|
+
return str;
|
|
4147
|
+
}
|
|
4148
|
+
extractOPReturnData() {
|
|
4149
|
+
const ordIndex = this.rawTx.indexOf("6f7264");
|
|
4150
|
+
if (ordIndex === -1) return null;
|
|
4151
|
+
const dataHex = this.rawTx.substring(ordIndex);
|
|
4152
|
+
const dataText = this.hexToText(dataHex);
|
|
4153
|
+
const jsonMatch = dataText.match(/\{.*?\}/);
|
|
4154
|
+
return jsonMatch ? JSON.parse(jsonMatch[0]) : null;
|
|
4155
|
+
}
|
|
4156
|
+
parseScript() {
|
|
4157
|
+
return {
|
|
4158
|
+
version: this.rawTx.substring(0, 8),
|
|
4159
|
+
inputCount: parseInt(this.rawTx.substring(8, 10)),
|
|
4160
|
+
inputs: this.parseInputs(),
|
|
4161
|
+
opReturnData: this.extractOPReturnData()
|
|
4115
4162
|
};
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
if (!success) {
|
|
4125
|
-
console.error("queryGasInfo evm", txData, queryGasParams, message, gasInfo);
|
|
4126
|
-
const BaseConfig3 = SupportedChainTypes[ChainTypes.EVM];
|
|
4127
|
-
const { gasFee } = BaseConfig3;
|
|
4128
|
-
return {
|
|
4129
|
-
success: true,
|
|
4130
|
-
gasFee: gasFee.toString()
|
|
4131
|
-
};
|
|
4132
|
-
}
|
|
4133
|
-
const nativeChainId = SupportedChainTypes[this.chainType].chainId;
|
|
4134
|
-
const { nativeCurrency } = await this.networks.getNetworkByChainId(nativeChainId);
|
|
4135
|
-
const { baseFee = 1, gasLimit = 0 } = gasInfo;
|
|
4136
|
-
const baseFeeBN = new BigNumber(baseFee);
|
|
4137
|
-
const calcFee = (feeLevel) => {
|
|
4138
|
-
const fee = baseFeeBN.plus(gasInfo[feeLevel] || 0);
|
|
4139
|
-
const gasFee = fee.times(gasLimit);
|
|
4140
|
-
return formatUnits(BigInt(gasFee.toNumber()), nativeCurrency?.decimals || 9);
|
|
4163
|
+
}
|
|
4164
|
+
parseInputs() {
|
|
4165
|
+
const inputs = [];
|
|
4166
|
+
const position = 10;
|
|
4167
|
+
const firstInput = {
|
|
4168
|
+
txid: this.rawTx.substring(position, position + 64),
|
|
4169
|
+
vout: this.rawTx.substring(position + 64, position + 72),
|
|
4170
|
+
scriptData: this.extractOPReturnData()
|
|
4141
4171
|
};
|
|
4172
|
+
inputs.push(firstInput);
|
|
4173
|
+
return inputs;
|
|
4174
|
+
}
|
|
4175
|
+
};
|
|
4176
|
+
|
|
4177
|
+
// src/dogecoin/rpc.ts
|
|
4178
|
+
var mydoge = axios.create({
|
|
4179
|
+
baseURL: MYDOGE_BASE_URL
|
|
4180
|
+
});
|
|
4181
|
+
var api = axios.create({
|
|
4182
|
+
baseURL: RPC_URL,
|
|
4183
|
+
timeout: RPC_TIMEOUT
|
|
4184
|
+
});
|
|
4185
|
+
async function getBalance(address) {
|
|
4186
|
+
if (!address) {
|
|
4142
4187
|
return {
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
low: calcFee("priorityFeeLow"),
|
|
4146
|
-
medium: calcFee("priorityFeeMedium"),
|
|
4147
|
-
high: calcFee("priorityFeeHigh")
|
|
4148
|
-
},
|
|
4149
|
-
gasFee: calcFee("priorityFeeMedium"),
|
|
4150
|
-
baseFee,
|
|
4151
|
-
gasLimit,
|
|
4152
|
-
priorityFee: {
|
|
4153
|
-
low: gasInfo.priorityFeeLow,
|
|
4154
|
-
medium: gasInfo.priorityFeeMedium,
|
|
4155
|
-
high: gasInfo.priorityFeeHigh
|
|
4156
|
-
}
|
|
4188
|
+
address: "",
|
|
4189
|
+
balance: 0
|
|
4157
4190
|
};
|
|
4158
4191
|
}
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4192
|
+
const path = `/address/${address}?page=1&pageSize=10`;
|
|
4193
|
+
const api2 = `${MYDOGE_BASE_URL}/wallet/info?route=` + encodeURIComponent(path);
|
|
4194
|
+
const res = await mydoge.get(api2);
|
|
4195
|
+
return res.data || {};
|
|
4196
|
+
}
|
|
4197
|
+
async function getTxDetail(txId) {
|
|
4198
|
+
if (!txId) {
|
|
4199
|
+
return {};
|
|
4200
|
+
}
|
|
4201
|
+
const path = `/tx/${txId}`;
|
|
4202
|
+
const api2 = `${MYDOGE_BASE_URL}/wallet/info?route=` + encodeURIComponent(path);
|
|
4203
|
+
const res = await mydoge.get(api2);
|
|
4204
|
+
return res.data || {};
|
|
4205
|
+
}
|
|
4206
|
+
async function getUtxos(address, cursor, result, filter, tx = null) {
|
|
4207
|
+
const query = (await mydoge.get(`${MYDOGE_BASE_URL}/utxos/${address}?filter=${filter}${cursor ? `&cursor=${cursor}` : ""}`)).data;
|
|
4208
|
+
let { utxos } = query;
|
|
4209
|
+
if (tx) {
|
|
4210
|
+
utxos = utxos.filter((utxo) => utxo.txid === tx?.txid && utxo.vout === tx?.vout);
|
|
4211
|
+
}
|
|
4212
|
+
result.push(
|
|
4213
|
+
...utxos.map((i) => ({
|
|
4214
|
+
txid: i.txid,
|
|
4215
|
+
vout: i.vout,
|
|
4216
|
+
outputValue: i.satoshis,
|
|
4217
|
+
script: i.script_pubkey,
|
|
4218
|
+
...filter === "inscriptions" && { inscriptions: i.inscriptions }
|
|
4219
|
+
}))
|
|
4220
|
+
);
|
|
4221
|
+
if (result.length && tx) {
|
|
4222
|
+
return;
|
|
4223
|
+
}
|
|
4224
|
+
result = result.sort((a, b) => toBitcoin(b.outputValue) - toBitcoin(a.outputValue));
|
|
4225
|
+
if (query.next_cursor) {
|
|
4226
|
+
return getUtxos(address, query.next_cursor, result, filter, tx);
|
|
4227
|
+
}
|
|
4228
|
+
}
|
|
4229
|
+
async function getInscriptionsUtxos(address) {
|
|
4230
|
+
const inscriptions = [];
|
|
4231
|
+
await getUtxos(address, 0, inscriptions, "inscriptions");
|
|
4232
|
+
return inscriptions;
|
|
4233
|
+
}
|
|
4234
|
+
async function getSpendableUtxos(address) {
|
|
4235
|
+
const utxos = [];
|
|
4236
|
+
await getUtxos(address, 0, utxos, "spendable");
|
|
4237
|
+
return utxos;
|
|
4238
|
+
}
|
|
4239
|
+
async function getUnSpentUtxos(address) {
|
|
4240
|
+
try {
|
|
4241
|
+
const result = await api.get(`/address/${address}/?unspent=true&limit=${0}`);
|
|
4242
|
+
const unSpentUtxo = result?.data;
|
|
4243
|
+
if (unSpentUtxo?.length) return unSpentUtxo.filter((utxo) => !utxo.spentTxid);
|
|
4244
|
+
return [];
|
|
4245
|
+
} catch (e) {
|
|
4246
|
+
return [];
|
|
4247
|
+
}
|
|
4248
|
+
}
|
|
4249
|
+
async function getInscriptionsUtxo(address, tx) {
|
|
4250
|
+
const inscriptions = [];
|
|
4251
|
+
await getUtxos(address, 0, inscriptions, "inscriptions", tx);
|
|
4252
|
+
return inscriptions[0];
|
|
4253
|
+
}
|
|
4254
|
+
async function sendTransaction({ signed, senderAddress }) {
|
|
4255
|
+
const jsonrpcReq = {
|
|
4256
|
+
jsonrpc: "2.0",
|
|
4257
|
+
id: `${senderAddress}_send_${Date.now()}`,
|
|
4258
|
+
method: "sendrawtransaction",
|
|
4259
|
+
params: [signed]
|
|
4260
|
+
};
|
|
4261
|
+
const jsonrpcRes = (await mydoge.post("/wallet/rpc", jsonrpcReq)).data;
|
|
4262
|
+
return jsonrpcRes;
|
|
4263
|
+
}
|
|
4264
|
+
async function estimateSmartFee({ senderAddress }) {
|
|
4265
|
+
const smartfeeReq = {
|
|
4266
|
+
jsonrpc: "2.0",
|
|
4267
|
+
id: `${senderAddress}_estimatesmartfee_${Date.now()}`,
|
|
4268
|
+
method: "estimatesmartfee",
|
|
4269
|
+
params: [BLOCK_CONFIRMATIONS]
|
|
4270
|
+
// confirm within x blocks
|
|
4271
|
+
};
|
|
4272
|
+
const feeData = (await mydoge.post("/wallet/rpc", smartfeeReq)).data;
|
|
4273
|
+
const feeRate = feeData?.result?.feerate || FEE_RATE_KB;
|
|
4274
|
+
const feePerKB = toSatoshi(feeRate * 2);
|
|
4275
|
+
return { feePerKB };
|
|
4276
|
+
}
|
|
4277
|
+
async function onCreateTransaction({ data, sendResponse }) {
|
|
4278
|
+
const amountSatoshi = toSatoshi(data.dogeAmount);
|
|
4279
|
+
const amount = toBitcoin(amountSatoshi);
|
|
4280
|
+
try {
|
|
4281
|
+
const response = await mydoge.post("/v3/tx/prepare", {
|
|
4282
|
+
sender: data.senderAddress,
|
|
4283
|
+
recipient: data.recipientAddress,
|
|
4284
|
+
amount
|
|
4285
|
+
});
|
|
4286
|
+
const { rawTx, fee, amount: resultAmount } = response.data;
|
|
4287
|
+
let amountMismatch = false;
|
|
4288
|
+
if (resultAmount < amount - fee) {
|
|
4289
|
+
amountMismatch = true;
|
|
4175
4290
|
}
|
|
4176
|
-
|
|
4177
|
-
|
|
4291
|
+
sendResponse?.({
|
|
4292
|
+
rawTx,
|
|
4293
|
+
fee,
|
|
4294
|
+
amount: resultAmount,
|
|
4295
|
+
amountMismatch
|
|
4178
4296
|
});
|
|
4297
|
+
} catch (err) {
|
|
4298
|
+
sendResponse?.(false);
|
|
4179
4299
|
}
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4300
|
+
}
|
|
4301
|
+
async function getTransactions(address, config) {
|
|
4302
|
+
const { pageSize = 10, pageNumber = 1 } = config || {};
|
|
4303
|
+
const size = Math.min(pageSize, TRANSACTION_PAGE_SIZE);
|
|
4304
|
+
let txIds = [];
|
|
4305
|
+
let totalPages;
|
|
4306
|
+
let page;
|
|
4307
|
+
try {
|
|
4308
|
+
const response = (await mydoge.get("/wallet/info", {
|
|
4309
|
+
params: {
|
|
4310
|
+
route: `/address/${address}?page=${pageNumber}&pageSize=${size}`
|
|
4311
|
+
}
|
|
4312
|
+
})).data;
|
|
4313
|
+
txIds = response.txids;
|
|
4314
|
+
totalPages = response.totalPages;
|
|
4315
|
+
page = response.page;
|
|
4316
|
+
const transactions = await Promise.all(
|
|
4317
|
+
txIds?.map(async (txId) => {
|
|
4318
|
+
const detail = await getTxDetail(txId);
|
|
4319
|
+
const tx = new TransactionParser(detail.hex);
|
|
4320
|
+
const parsedData = tx.parseScript();
|
|
4321
|
+
return {
|
|
4322
|
+
...detail,
|
|
4323
|
+
tick: parsedData?.opReturnData?.tick,
|
|
4324
|
+
tickAmount: parsedData?.opReturnData?.amt
|
|
4325
|
+
};
|
|
4326
|
+
}) || []
|
|
4327
|
+
);
|
|
4328
|
+
return { transactions, txIds, totalPages, page };
|
|
4329
|
+
} catch (err) {
|
|
4330
|
+
throw new Error("getTransactions failed");
|
|
4331
|
+
}
|
|
4332
|
+
}
|
|
4333
|
+
var getDogeFeeByBlock = async (address, n = 22) => {
|
|
4334
|
+
const res = await api.get(`/fee/${n}`);
|
|
4335
|
+
return (res.data?.feerate || 0.01) * TX_SIZE;
|
|
4336
|
+
};
|
|
4337
|
+
var sendDogeTx = async (rawTx) => {
|
|
4338
|
+
try {
|
|
4339
|
+
const res = await api.post("/tx/send", { rawTx });
|
|
4340
|
+
return res.data;
|
|
4341
|
+
} catch (e) {
|
|
4342
|
+
if (typeof e?.response?.data === "string") return Promise.reject(e?.response?.data);
|
|
4343
|
+
else return Promise.reject(e.message);
|
|
4344
|
+
}
|
|
4345
|
+
};
|
|
4346
|
+
|
|
4347
|
+
// src/dogecoin/utils-doge.ts
|
|
4348
|
+
var DogecoinAddress = class {
|
|
4349
|
+
static network = network;
|
|
4350
|
+
static generatePath(addressIndex) {
|
|
4351
|
+
return `m/44'/3'/0'/0/${addressIndex || 0}`;
|
|
4352
|
+
}
|
|
4353
|
+
static verifyAddress(address$1) {
|
|
4189
4354
|
try {
|
|
4190
|
-
const
|
|
4191
|
-
|
|
4192
|
-
return gas;
|
|
4355
|
+
const decoded = address.fromBase58Check(address$1);
|
|
4356
|
+
return decoded.version === network.pubKeyHash || decoded.version === network.scriptHash;
|
|
4193
4357
|
} catch (error) {
|
|
4194
|
-
|
|
4195
|
-
const BaseConfig3 = SupportedChainTypes[ChainTypes.EVM];
|
|
4196
|
-
const { gasFee } = BaseConfig3;
|
|
4197
|
-
return numberToHex(parseUnits(gasFee.toString(), 18));
|
|
4358
|
+
return false;
|
|
4198
4359
|
}
|
|
4199
4360
|
}
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
const
|
|
4212
|
-
|
|
4361
|
+
};
|
|
4362
|
+
var DogecoinUtils = class {
|
|
4363
|
+
/**
|
|
4364
|
+
* Build the PSBT from the transaction
|
|
4365
|
+
* @param tx utxoTx
|
|
4366
|
+
* @param _maximumFeeRate number (optional, currently unused)
|
|
4367
|
+
* @returns base64
|
|
4368
|
+
*/
|
|
4369
|
+
static buildPsbtToBase64(tx, _maximumFeeRate) {
|
|
4370
|
+
const psbt = new Psbt({ network });
|
|
4371
|
+
for (const input of tx.inputs) {
|
|
4372
|
+
const inputOptions = {
|
|
4373
|
+
hash: input.txId,
|
|
4374
|
+
index: input.vOut
|
|
4375
|
+
};
|
|
4376
|
+
if (input.nonWitnessUtxo) {
|
|
4377
|
+
inputOptions.nonWitnessUtxo = Buffer.from(input.nonWitnessUtxo, "hex");
|
|
4378
|
+
}
|
|
4379
|
+
psbt.addInput(inputOptions);
|
|
4380
|
+
}
|
|
4381
|
+
for (const output of tx.outputs) {
|
|
4382
|
+
psbt.addOutput({
|
|
4383
|
+
value: BigInt(output?.amount || 0),
|
|
4384
|
+
address: output.address
|
|
4385
|
+
});
|
|
4386
|
+
}
|
|
4387
|
+
const psbtHex = psbt.toHex();
|
|
4388
|
+
return toBase64(fromHex(psbtHex));
|
|
4389
|
+
}
|
|
4390
|
+
/**
|
|
4391
|
+
* Extract the transaction from the signed PSBT
|
|
4392
|
+
* @param signedPsbt base64
|
|
4393
|
+
* @param _maximumFeeRate number (optional, currently unused)
|
|
4394
|
+
* @returns transaction hex
|
|
4395
|
+
*/
|
|
4396
|
+
static extractPsbtTransaction(signedPsbt, _maximumFeeRate) {
|
|
4397
|
+
const signedPsbtHex = toHex(fromBase64(signedPsbt));
|
|
4398
|
+
const psbt = Psbt.fromHex(signedPsbtHex, {
|
|
4399
|
+
network
|
|
4400
|
+
});
|
|
4401
|
+
const maximumFeeRate = _maximumFeeRate || 1e5;
|
|
4402
|
+
psbt.setMaximumFeeRate(maximumFeeRate);
|
|
4403
|
+
psbt.finalizeAllInputs();
|
|
4404
|
+
const transaction = psbt.extractTransaction();
|
|
4405
|
+
return transaction.toHex();
|
|
4406
|
+
}
|
|
4407
|
+
/**
|
|
4408
|
+
* Convert raw transaction hex to PSBT base64
|
|
4409
|
+
* This method converts an unsigned raw transaction to PSBT format.
|
|
4410
|
+
* Note: The rawTx should be an unsigned transaction, and the nonWitnessUtxo
|
|
4411
|
+
* for each input will need to be fetched separately from the blockchain.
|
|
4412
|
+
* @param rawTx hex string of the raw transaction
|
|
4413
|
+
* @returns base64 string of the PSBT
|
|
4414
|
+
*/
|
|
4415
|
+
static async rawTxToPsbtBase64(rawTx) {
|
|
4416
|
+
try {
|
|
4417
|
+
const cleanHex = rawTx.startsWith("0x") ? rawTx.slice(2) : rawTx;
|
|
4418
|
+
const transaction = Transaction.fromHex(cleanHex);
|
|
4419
|
+
const psbt = new Psbt({ network });
|
|
4420
|
+
for (let i = 0; i < transaction.ins.length; i++) {
|
|
4421
|
+
const input = transaction.ins[i];
|
|
4422
|
+
const hash = Buffer.from(input.hash).toString("hex");
|
|
4423
|
+
const index = input.index;
|
|
4424
|
+
const inputOptions = {
|
|
4425
|
+
hash,
|
|
4426
|
+
index
|
|
4427
|
+
};
|
|
4428
|
+
try {
|
|
4429
|
+
const prevTxDetail = await getTxDetail(hash);
|
|
4430
|
+
if (prevTxDetail?.hex) {
|
|
4431
|
+
inputOptions.nonWitnessUtxo = Buffer.from(prevTxDetail.hex, "hex");
|
|
4432
|
+
} else {
|
|
4433
|
+
throw new Error(`Previous transaction ${hash} has no hex data`);
|
|
4434
|
+
}
|
|
4435
|
+
} catch (error) {
|
|
4436
|
+
throw new Error(
|
|
4437
|
+
`Failed to fetch previous transaction ${hash} for input #${i}. This is required for PSBT creation. Error: ${error instanceof Error ? error.message : String(error)}`
|
|
4438
|
+
);
|
|
4439
|
+
}
|
|
4440
|
+
psbt.addInput(inputOptions);
|
|
4441
|
+
}
|
|
4442
|
+
for (const output of transaction.outs) {
|
|
4443
|
+
try {
|
|
4444
|
+
const address$1 = address.fromOutputScript(output.script, network);
|
|
4445
|
+
psbt.addOutput({
|
|
4446
|
+
address: address$1,
|
|
4447
|
+
value: BigInt(output?.value || 0)
|
|
4448
|
+
});
|
|
4449
|
+
} catch (error) {
|
|
4450
|
+
psbt.addOutput({
|
|
4451
|
+
script: output.script,
|
|
4452
|
+
value: BigInt(output?.value || 0)
|
|
4453
|
+
});
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
const psbtHex = psbt.toHex();
|
|
4457
|
+
return toBase64(fromHex(psbtHex));
|
|
4213
4458
|
} catch (error) {
|
|
4214
|
-
console.
|
|
4215
|
-
throw new Error(
|
|
4459
|
+
console.warn("rawTxToPsbtBase64 failed:", error);
|
|
4460
|
+
throw new Error(
|
|
4461
|
+
`Failed to convert raw transaction to PSBT: ${error instanceof Error ? error.message : String(error)}`
|
|
4462
|
+
);
|
|
4216
4463
|
}
|
|
4217
4464
|
}
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
txData.gas = txData?.gas || txData?.gasLimit;
|
|
4233
|
-
txData.data = txData.data || "0x";
|
|
4234
|
-
txData.value = txData.value || "0x";
|
|
4235
|
-
txData.nonce = txData.nonce || "0x0";
|
|
4236
|
-
if (!txData?.gas || !txData?.to || !txData?.chainId) {
|
|
4237
|
-
throw new Error("gas or to or chainId is not set");
|
|
4465
|
+
};
|
|
4466
|
+
var DogecoinService = class _DogecoinService extends BaseService {
|
|
4467
|
+
static instance;
|
|
4468
|
+
chainType;
|
|
4469
|
+
rpcService;
|
|
4470
|
+
constructor(chainType, accountInfo, tomoAppInfo) {
|
|
4471
|
+
super(tomoAppInfo, accountInfo);
|
|
4472
|
+
this.chainType = chainType;
|
|
4473
|
+
this.rpcService = rpc_exports;
|
|
4474
|
+
}
|
|
4475
|
+
//singleton
|
|
4476
|
+
static getInstance(chainType, accountInfo, tomoAppInfo) {
|
|
4477
|
+
if (!_DogecoinService.instance) {
|
|
4478
|
+
_DogecoinService.instance = new _DogecoinService(chainType, accountInfo, tomoAppInfo);
|
|
4238
4479
|
}
|
|
4480
|
+
return _DogecoinService.instance;
|
|
4481
|
+
}
|
|
4482
|
+
async requestAccounts() {
|
|
4483
|
+
const addresses = await this.accountInfo.getCurrent();
|
|
4484
|
+
const { publicKey, address } = addresses?.[0] || {};
|
|
4485
|
+
if (!address) {
|
|
4486
|
+
throw new Error("address is not set");
|
|
4487
|
+
}
|
|
4488
|
+
const { balance = 0 } = await getBalance(address);
|
|
4489
|
+
return {
|
|
4490
|
+
address,
|
|
4491
|
+
balance,
|
|
4492
|
+
approved: true,
|
|
4493
|
+
publicKey
|
|
4494
|
+
};
|
|
4495
|
+
}
|
|
4496
|
+
async getAccounts() {
|
|
4239
4497
|
const accounts = await this.accountInfo.getCurrent();
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4498
|
+
return accounts.map((account) => account.address);
|
|
4499
|
+
}
|
|
4500
|
+
async getConnectionStatus() {
|
|
4501
|
+
const addresses = await this.accountInfo.getCurrent();
|
|
4502
|
+
const { address } = addresses?.[0] || {};
|
|
4503
|
+
if (!address) {
|
|
4504
|
+
throw new Error("address is not set");
|
|
4244
4505
|
}
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4506
|
+
return {
|
|
4507
|
+
connected: true,
|
|
4508
|
+
address,
|
|
4509
|
+
selectedWalletAddress: address
|
|
4249
4510
|
};
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4511
|
+
}
|
|
4512
|
+
async getBalance() {
|
|
4513
|
+
const addresses = await this.accountInfo.getCurrent();
|
|
4514
|
+
const { address } = addresses?.[0] || {};
|
|
4515
|
+
if (!address) {
|
|
4516
|
+
throw new Error("address is not set");
|
|
4254
4517
|
}
|
|
4255
|
-
|
|
4256
|
-
|
|
4518
|
+
const { balance = 0 } = await getBalance(address);
|
|
4519
|
+
return {
|
|
4520
|
+
address,
|
|
4521
|
+
balance
|
|
4522
|
+
};
|
|
4523
|
+
}
|
|
4524
|
+
async signMessage({ message, type }) {
|
|
4525
|
+
if (type) {
|
|
4526
|
+
throw new Error("bip322simple not support.");
|
|
4257
4527
|
}
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
}
|
|
4271
|
-
|
|
4528
|
+
const signature = await this.accountInfo.signMessage(message);
|
|
4529
|
+
return {
|
|
4530
|
+
signedMessage: signature
|
|
4531
|
+
};
|
|
4532
|
+
}
|
|
4533
|
+
async requestSignedMessage({
|
|
4534
|
+
message,
|
|
4535
|
+
type
|
|
4536
|
+
}) {
|
|
4537
|
+
return await this.signMessage({
|
|
4538
|
+
message,
|
|
4539
|
+
type
|
|
4540
|
+
});
|
|
4541
|
+
}
|
|
4542
|
+
async _queryGasInfo(txData) {
|
|
4543
|
+
const { chainId, amount = 0, decimals = 8 } = txData;
|
|
4544
|
+
const gasLimitParam = {
|
|
4545
|
+
from: txData.from,
|
|
4546
|
+
to: txData.to,
|
|
4547
|
+
value: toHex$1(parseUnits(amount.toString(), decimals))
|
|
4548
|
+
};
|
|
4549
|
+
const queryGasParams = {
|
|
4550
|
+
chainIndex: Number(chainId || BaseConfig.chainId),
|
|
4551
|
+
callData: "0x",
|
|
4552
|
+
gasLimitParam,
|
|
4553
|
+
addressList: [txData.from]
|
|
4554
|
+
};
|
|
4555
|
+
const {
|
|
4556
|
+
data: gasInfo,
|
|
4557
|
+
success,
|
|
4558
|
+
message
|
|
4559
|
+
} = await this.transactions.queryGasInfo({
|
|
4560
|
+
chainType: this.chainType,
|
|
4561
|
+
params: queryGasParams
|
|
4562
|
+
});
|
|
4563
|
+
if (!success) {
|
|
4564
|
+
console.error("queryGasInfo doge", success, txData, queryGasParams, gasInfo);
|
|
4565
|
+
const { gasFee } = BaseConfig;
|
|
4566
|
+
return {
|
|
4567
|
+
success: true,
|
|
4568
|
+
gasFee: gasFee.toString()
|
|
4569
|
+
};
|
|
4272
4570
|
}
|
|
4571
|
+
const { baseFee = 1, gasLimit = 1 } = gasInfo;
|
|
4572
|
+
const calcFee = (feeLevel) => {
|
|
4573
|
+
const gasFee = new BigNumber(gasInfo[feeLevel] || baseFee).times(gasLimit);
|
|
4574
|
+
return toBitcoin(gasFee.toNumber());
|
|
4575
|
+
};
|
|
4576
|
+
const fees = {
|
|
4577
|
+
low: calcFee("priorityFeeLow"),
|
|
4578
|
+
medium: calcFee("priorityFeeMedium"),
|
|
4579
|
+
high: calcFee("priorityFeeHigh")
|
|
4580
|
+
};
|
|
4581
|
+
return {
|
|
4582
|
+
success: true,
|
|
4583
|
+
fees,
|
|
4584
|
+
gasFee: fees.high
|
|
4585
|
+
};
|
|
4273
4586
|
}
|
|
4274
|
-
async
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4587
|
+
async requestPsbt({
|
|
4588
|
+
rawTx,
|
|
4589
|
+
signOnly
|
|
4590
|
+
}) {
|
|
4591
|
+
const psbtBase64 = await DogecoinUtils.rawTxToPsbtBase64(rawTx);
|
|
4592
|
+
const signedPsbt = await this.accountInfo.signTransaction(JSON.stringify({ psbtBase64 }));
|
|
4593
|
+
if (!signedPsbt) {
|
|
4594
|
+
return null;
|
|
4595
|
+
}
|
|
4596
|
+
const signedRawTx = DogecoinUtils.extractPsbtTransaction(signedPsbt, 1e5);
|
|
4597
|
+
if (signOnly) {
|
|
4598
|
+
return {
|
|
4599
|
+
signedRawTx
|
|
4600
|
+
};
|
|
4284
4601
|
}
|
|
4602
|
+
const { txid = "" } = await sendDogeTx(signedRawTx);
|
|
4603
|
+
return {
|
|
4604
|
+
txId: txid,
|
|
4605
|
+
signedRawTx
|
|
4606
|
+
};
|
|
4285
4607
|
}
|
|
4286
|
-
async
|
|
4287
|
-
|
|
4288
|
-
|
|
4608
|
+
async requestTransaction(txData) {
|
|
4609
|
+
const spendableUtxos = txData?.spendableUtxos;
|
|
4610
|
+
if (txData.amountMismatch) {
|
|
4611
|
+
throw new Error("balance_insufficient");
|
|
4612
|
+
}
|
|
4613
|
+
if (!spendableUtxos || spendableUtxos?.length === 0) {
|
|
4614
|
+
txData.spendableUtxos = await getSpendableUtxos(txData.from);
|
|
4615
|
+
}
|
|
4616
|
+
const { psbtBase64, usingUtxos } = await createPsbt(txData);
|
|
4617
|
+
const signedPsbt = await this.accountInfo.signTransaction(JSON.stringify({ psbtBase64 }));
|
|
4618
|
+
const signedTx = DogecoinUtils.extractPsbtTransaction(signedPsbt, 1e5);
|
|
4619
|
+
if (signedTx === "") {
|
|
4620
|
+
throw new Error("Error: sign transaction err.");
|
|
4289
4621
|
}
|
|
4290
4622
|
try {
|
|
4291
|
-
const
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
} catch (error) {
|
|
4297
|
-
console.error("Failed to send transaction via RPC:", error, hash);
|
|
4298
|
-
throw error;
|
|
4623
|
+
const { txid } = await sendDogeTx(signedTx);
|
|
4624
|
+
addUsedUtxos(usingUtxos);
|
|
4625
|
+
return { txId: txid };
|
|
4626
|
+
} catch (err) {
|
|
4627
|
+
throw new Error("Error: send transaction err." + JSON.stringify(err));
|
|
4299
4628
|
}
|
|
4300
4629
|
}
|
|
4301
|
-
}
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
return Buffer.from(
|
|
4315
|
-
tx.serialize({
|
|
4316
|
-
requireAllSignatures: false,
|
|
4317
|
-
verifySignatures: false
|
|
4318
|
-
})
|
|
4319
|
-
).toString("hex");
|
|
4630
|
+
async getTransactionStatus({ txId }) {
|
|
4631
|
+
const transaction = await getTxDetail(txId);
|
|
4632
|
+
if (!transaction?.txid) {
|
|
4633
|
+
return null;
|
|
4634
|
+
}
|
|
4635
|
+
return {
|
|
4636
|
+
txId: transaction.txid,
|
|
4637
|
+
confirmations: transaction.confirmations,
|
|
4638
|
+
status: transaction.confirmations > 0 ? "confirmed" : "pending",
|
|
4639
|
+
dogeAmount: transaction.vout[0]?.value,
|
|
4640
|
+
blockTime: transaction.blockTime,
|
|
4641
|
+
address: transaction.vout[0]?.addresses[0]
|
|
4642
|
+
};
|
|
4320
4643
|
}
|
|
4321
|
-
return tx;
|
|
4322
4644
|
};
|
|
4323
|
-
|
|
4324
|
-
const
|
|
4325
|
-
const
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
decimals = 6
|
|
4349
|
-
}, connection) {
|
|
4350
|
-
try {
|
|
4351
|
-
const fromPubkey = new PublicKey(from);
|
|
4352
|
-
const toPubkey = new PublicKey(to);
|
|
4353
|
-
const tokenPublicKey = new PublicKey(tokenAddress);
|
|
4354
|
-
const fromTokenPubKey = await getAssociatedTokenAddress(tokenPublicKey, fromPubkey);
|
|
4355
|
-
const toTokenPubKey = await getAssociatedTokenAddress(tokenPublicKey, toPubkey);
|
|
4356
|
-
const { blockhash } = await connection.getLatestBlockhash("confirmed");
|
|
4357
|
-
const transaction = new Transaction$1();
|
|
4358
|
-
transaction.feePayer = fromPubkey;
|
|
4359
|
-
transaction.recentBlockhash = blockhash;
|
|
4360
|
-
try {
|
|
4361
|
-
const instruction = createAssociatedTokenAccountInstruction(fromPubkey, toTokenPubKey, toPubkey, tokenPublicKey);
|
|
4362
|
-
transaction.add(instruction);
|
|
4363
|
-
} catch (error) {
|
|
4364
|
-
console.error(error);
|
|
4365
|
-
throw error;
|
|
4645
|
+
function getRPCClient(network2) {
|
|
4646
|
+
const { chainId, name, rpcUrls, nativeCurrencyDecimals, nativeCurrencyName, nativeCurrencySymbol } = network2;
|
|
4647
|
+
const myCustomChain = {
|
|
4648
|
+
id: Number(chainId) || chainId,
|
|
4649
|
+
name,
|
|
4650
|
+
nativeCurrency: {
|
|
4651
|
+
name: nativeCurrencyName,
|
|
4652
|
+
symbol: nativeCurrencySymbol,
|
|
4653
|
+
decimals: nativeCurrencyDecimals
|
|
4654
|
+
},
|
|
4655
|
+
rpcUrls: {
|
|
4656
|
+
default: {
|
|
4657
|
+
http: rpcUrls,
|
|
4658
|
+
webSocket: []
|
|
4659
|
+
},
|
|
4660
|
+
public: {
|
|
4661
|
+
http: rpcUrls,
|
|
4662
|
+
webSocket: []
|
|
4663
|
+
}
|
|
4664
|
+
},
|
|
4665
|
+
blockExplorers: {
|
|
4666
|
+
default: {
|
|
4667
|
+
name: "Explorer",
|
|
4668
|
+
url: rpcUrls[0]
|
|
4669
|
+
}
|
|
4366
4670
|
}
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
}
|
|
4671
|
+
};
|
|
4672
|
+
const rpcClient = createPublicClient({
|
|
4673
|
+
chain: myCustomChain,
|
|
4674
|
+
pollingInterval: 1e4,
|
|
4675
|
+
cacheTime: 1e4,
|
|
4676
|
+
transport: http()
|
|
4677
|
+
});
|
|
4678
|
+
return { rpcClient };
|
|
4376
4679
|
}
|
|
4377
4680
|
|
|
4378
|
-
// src/
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4681
|
+
// src/types/account.ts
|
|
4682
|
+
var AccountType = /* @__PURE__ */ ((AccountType2) => {
|
|
4683
|
+
AccountType2["EOA"] = "EOA";
|
|
4684
|
+
AccountType2["SOCIAL"] = "SOCIAL";
|
|
4685
|
+
return AccountType2;
|
|
4686
|
+
})(AccountType || {});
|
|
4687
|
+
|
|
4688
|
+
// src/types/wallet.ts
|
|
4689
|
+
var TxTypes = /* @__PURE__ */ ((TxTypes2) => {
|
|
4690
|
+
TxTypes2[TxTypes2["swap"] = 1] = "swap";
|
|
4691
|
+
TxTypes2[TxTypes2["bridge"] = 2] = "bridge";
|
|
4692
|
+
TxTypes2[TxTypes2["receive"] = 31] = "receive";
|
|
4693
|
+
TxTypes2[TxTypes2["send"] = 32] = "send";
|
|
4694
|
+
TxTypes2[TxTypes2["approve"] = 4] = "approve";
|
|
4695
|
+
TxTypes2[TxTypes2["contractInteraction"] = 5] = "contractInteraction";
|
|
4696
|
+
TxTypes2[TxTypes2["redPocket"] = 6] = "redPocket";
|
|
4697
|
+
return TxTypes2;
|
|
4698
|
+
})(TxTypes || {});
|
|
4699
|
+
|
|
4700
|
+
// src/evm/utils.ts
|
|
4701
|
+
var isEvmChain = (network2) => {
|
|
4702
|
+
return network2 && network2?.platformType === "EVM";
|
|
4703
|
+
};
|
|
4704
|
+
var getAllTypeChainIds = ({ chainId, chainType }) => {
|
|
4705
|
+
if (isHex(chainId)) {
|
|
4706
|
+
const chainIdHex2 = chainId;
|
|
4707
|
+
chainId = fromHex$1(chainId, "number").toString();
|
|
4708
|
+
return {
|
|
4709
|
+
chainId,
|
|
4710
|
+
chainIdHex: chainIdHex2,
|
|
4711
|
+
chainUid: `${chainType}:${chainId}`
|
|
4712
|
+
};
|
|
4399
4713
|
}
|
|
4400
|
-
const
|
|
4401
|
-
return
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
}
|
|
4407
|
-
function
|
|
4408
|
-
|
|
4714
|
+
const chainIdHex = toHex$1(Number(chainId));
|
|
4715
|
+
return {
|
|
4716
|
+
chainId,
|
|
4717
|
+
chainIdHex,
|
|
4718
|
+
chainUid: `${chainType}:${chainId}`
|
|
4719
|
+
};
|
|
4720
|
+
};
|
|
4721
|
+
function createErc20TxData(params, token) {
|
|
4722
|
+
const { decimals, address: tokenAddress } = token;
|
|
4723
|
+
const value = parseUnits(params?.amount.toString(), decimals);
|
|
4724
|
+
const callData = encodeFunctionData({
|
|
4725
|
+
abi: erc20Abi,
|
|
4726
|
+
functionName: "transfer",
|
|
4727
|
+
args: [params.to, value]
|
|
4728
|
+
});
|
|
4729
|
+
return {
|
|
4730
|
+
...params,
|
|
4731
|
+
...{ amount: 0, data: callData, to: tokenAddress }
|
|
4732
|
+
};
|
|
4409
4733
|
}
|
|
4410
4734
|
|
|
4411
|
-
// src/
|
|
4412
|
-
var
|
|
4735
|
+
// src/evm/service.ts
|
|
4736
|
+
var EvmService = class _EvmService extends BaseService {
|
|
4413
4737
|
static instance;
|
|
4414
4738
|
chainType;
|
|
4415
|
-
rpcUrl;
|
|
4416
|
-
connection;
|
|
4417
4739
|
constructor(chainType, accountInfo, tomoAppInfo) {
|
|
4418
4740
|
super(tomoAppInfo, accountInfo);
|
|
4419
4741
|
this.chainType = chainType;
|
|
4420
|
-
const config = {
|
|
4421
|
-
commitment: "confirmed",
|
|
4422
|
-
disableRetryOnRateLimit: false,
|
|
4423
|
-
confirmTransactionInitialTimeout: 12e4,
|
|
4424
|
-
fetch: (url, options) => {
|
|
4425
|
-
return fetch(url, { ...options });
|
|
4426
|
-
}
|
|
4427
|
-
};
|
|
4428
|
-
const domain = TomoApiDomains[tomoAppInfo.tomoStage];
|
|
4429
|
-
const rpcUrl = `${domain}/rpc/v1/solana`;
|
|
4430
|
-
this.rpcUrl = rpcUrl;
|
|
4431
|
-
this.connection = new Connection(rpcUrl, config);
|
|
4432
4742
|
}
|
|
4433
4743
|
static getInstance(chainType, accountInfo, tomoAppInfo) {
|
|
4434
|
-
if (!
|
|
4435
|
-
|
|
4744
|
+
if (!_EvmService.instance) {
|
|
4745
|
+
_EvmService.instance = new _EvmService(chainType, accountInfo, tomoAppInfo);
|
|
4436
4746
|
}
|
|
4437
|
-
return
|
|
4747
|
+
return _EvmService.instance;
|
|
4438
4748
|
}
|
|
4439
|
-
async
|
|
4440
|
-
|
|
4749
|
+
async eth_requestAccounts() {
|
|
4750
|
+
const res = await this.eth_accounts();
|
|
4751
|
+
return res;
|
|
4441
4752
|
}
|
|
4442
|
-
async
|
|
4443
|
-
const
|
|
4444
|
-
return
|
|
4753
|
+
async eth_accounts() {
|
|
4754
|
+
const accounts = await this.accountInfo.getCurrent();
|
|
4755
|
+
return accounts.map((account) => account.address);
|
|
4445
4756
|
}
|
|
4446
|
-
async
|
|
4447
|
-
const
|
|
4448
|
-
const
|
|
4757
|
+
async eth_chainId() {
|
|
4758
|
+
const chainType = this.chainType;
|
|
4759
|
+
const currentNetwork = await this.getCurrentChain();
|
|
4760
|
+
const { chainIdHex } = getAllTypeChainIds({
|
|
4761
|
+
chainId: currentNetwork?.chainId,
|
|
4762
|
+
chainType
|
|
4763
|
+
});
|
|
4764
|
+
return chainIdHex;
|
|
4765
|
+
}
|
|
4766
|
+
async getCurrentChain() {
|
|
4767
|
+
this.networks.setChainType(this.chainType);
|
|
4768
|
+
const currentNetwork = await this.networks.getCurrentNetwork();
|
|
4769
|
+
return currentNetwork;
|
|
4770
|
+
}
|
|
4771
|
+
async wallet_switchEthereumChain(networks) {
|
|
4772
|
+
const { chainId } = networks[0];
|
|
4773
|
+
const isSupported = await this.isChainSupported(chainId);
|
|
4774
|
+
if (!isSupported) {
|
|
4775
|
+
throw new Error(`Chain ${chainId} is not supported`);
|
|
4776
|
+
}
|
|
4777
|
+
return await this.networks.setCurrentNetwork(chainId);
|
|
4778
|
+
}
|
|
4779
|
+
//evm chains
|
|
4780
|
+
async isChainSupported(chainId) {
|
|
4781
|
+
const chainType = this.chainType;
|
|
4782
|
+
const res = getAllTypeChainIds({ chainId, chainType });
|
|
4783
|
+
if (!res.chainId) {
|
|
4784
|
+
return false;
|
|
4785
|
+
}
|
|
4786
|
+
const chainInfo = await this.networks.getNetworkByChainId(res.chainId);
|
|
4787
|
+
if (!chainInfo) {
|
|
4788
|
+
return false;
|
|
4789
|
+
}
|
|
4790
|
+
return isEvmChain(chainInfo);
|
|
4791
|
+
}
|
|
4792
|
+
async personal_sign([message, address]) {
|
|
4793
|
+
const accounts = await this.accountInfo.getCurrent();
|
|
4794
|
+
if (!isAddressEqual(accounts[0].address, address)) {
|
|
4795
|
+
throw new Error("address is not the current account");
|
|
4796
|
+
}
|
|
4449
4797
|
const signature = await this.accountInfo.signMessage(message);
|
|
4450
|
-
return
|
|
4451
|
-
message: MSG_PREFIX + message,
|
|
4452
|
-
signature,
|
|
4453
|
-
publicKey: publicKey || currentAddress
|
|
4454
|
-
};
|
|
4798
|
+
return signature;
|
|
4455
4799
|
}
|
|
4456
|
-
async
|
|
4457
|
-
const
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
signedMessage: MSG_PREFIX + params.message
|
|
4464
|
-
};
|
|
4800
|
+
async eth_signTypedData_v4([address, typedData]) {
|
|
4801
|
+
const accounts = await this.accountInfo.getCurrent();
|
|
4802
|
+
if (!isAddressEqual(accounts[0].address, address)) {
|
|
4803
|
+
throw new Error("address is not the current account");
|
|
4804
|
+
}
|
|
4805
|
+
const signature = await this.accountInfo.signTypedData(typedData);
|
|
4806
|
+
return signature;
|
|
4465
4807
|
}
|
|
4466
|
-
async
|
|
4467
|
-
|
|
4468
|
-
|
|
4808
|
+
async eth_getBalance([address, type]) {
|
|
4809
|
+
const accounts = await this.accountInfo.getCurrent();
|
|
4810
|
+
if (!isAddressEqual(accounts[0].address, address)) {
|
|
4811
|
+
throw new Error("address is not the current account");
|
|
4812
|
+
}
|
|
4813
|
+
if (type !== "latest") {
|
|
4814
|
+
throw new Error("type is not supported");
|
|
4815
|
+
}
|
|
4816
|
+
const chainInfo = await this.getCurrentChain();
|
|
4817
|
+
const { rpcClient } = getRPCClient(chainInfo);
|
|
4818
|
+
try {
|
|
4819
|
+
const balance = await rpcClient.getBalance({ address });
|
|
4820
|
+
return balance?.toString() || "0";
|
|
4821
|
+
} catch (error) {
|
|
4822
|
+
console.error(error);
|
|
4823
|
+
return "0";
|
|
4469
4824
|
}
|
|
4470
|
-
return this[method](params);
|
|
4471
4825
|
}
|
|
4472
4826
|
async _queryGasInfo(txData) {
|
|
4473
4827
|
const { tokenAddress, chainId, amount = 0, decimals = 9 } = txData;
|
|
4474
|
-
const value = tokenAddress ? "0x1" : toHex(parseUnits(amount.toString(), decimals));
|
|
4828
|
+
const value = tokenAddress ? "0x1" : toHex$1(parseUnits(amount.toString(), decimals));
|
|
4475
4829
|
let callData = "0x";
|
|
4476
4830
|
if (tokenAddress) {
|
|
4477
|
-
|
|
4478
|
-
callData = "0x" + txToHex(transaction);
|
|
4479
|
-
} else {
|
|
4480
|
-
const transaction = await createLegacyTx(txData, this.connection);
|
|
4481
|
-
callData = "0x" + txToHex(transaction);
|
|
4831
|
+
callData = createErc20TxData(txData, { decimals, address: tokenAddress })?.data;
|
|
4482
4832
|
}
|
|
4483
4833
|
const gasLimitParam = {
|
|
4484
4834
|
from: txData.from,
|
|
@@ -4500,8 +4850,9 @@ var SolanaService = class _SolanaService extends BaseService {
|
|
|
4500
4850
|
params: queryGasParams
|
|
4501
4851
|
});
|
|
4502
4852
|
if (!success) {
|
|
4503
|
-
console.error("queryGasInfo
|
|
4504
|
-
const
|
|
4853
|
+
console.error("queryGasInfo evm", txData, queryGasParams, message, gasInfo);
|
|
4854
|
+
const BaseConfig3 = SupportedChainTypes[ChainTypes.EVM];
|
|
4855
|
+
const { gasFee } = BaseConfig3;
|
|
4505
4856
|
return {
|
|
4506
4857
|
success: true,
|
|
4507
4858
|
gasFee: gasFee.toString()
|
|
@@ -4510,528 +4861,326 @@ var SolanaService = class _SolanaService extends BaseService {
|
|
|
4510
4861
|
const nativeChainId = SupportedChainTypes[this.chainType].chainId;
|
|
4511
4862
|
const { nativeCurrency } = await this.networks.getNetworkByChainId(nativeChainId);
|
|
4512
4863
|
const { baseFee = 1, gasLimit = 0 } = gasInfo;
|
|
4513
|
-
const baseFeeBN = new BigNumber(baseFee)
|
|
4514
|
-
const gasLimitBN = new BigNumber(gasLimit);
|
|
4864
|
+
const baseFeeBN = new BigNumber(baseFee);
|
|
4515
4865
|
const calcFee = (feeLevel) => {
|
|
4516
|
-
const
|
|
4517
|
-
const gasFee =
|
|
4866
|
+
const fee = baseFeeBN.plus(gasInfo[feeLevel] || 0);
|
|
4867
|
+
const gasFee = fee.times(gasLimit);
|
|
4518
4868
|
return formatUnits(BigInt(gasFee.toNumber()), nativeCurrency?.decimals || 9);
|
|
4519
4869
|
};
|
|
4520
4870
|
return {
|
|
4521
|
-
success
|
|
4871
|
+
success,
|
|
4522
4872
|
fees: {
|
|
4523
4873
|
low: calcFee("priorityFeeLow"),
|
|
4524
4874
|
medium: calcFee("priorityFeeMedium"),
|
|
4525
4875
|
high: calcFee("priorityFeeHigh")
|
|
4526
|
-
},
|
|
4527
|
-
gasFee: calcFee("
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
} catch (error) {
|
|
4537
|
-
const base58Buffer = Buffer.from(toBase58());
|
|
4538
|
-
VersionedTransaction.deserialize(base58Buffer);
|
|
4539
|
-
rawTx = base58Buffer;
|
|
4540
|
-
}
|
|
4541
|
-
const transaction = VersionedTransaction.deserialize(rawTx);
|
|
4542
|
-
if (!transaction.signatures || transaction.signatures.length === 0) {
|
|
4543
|
-
throw new Error("lack of sign");
|
|
4544
|
-
}
|
|
4545
|
-
const confirmationStrategy = {
|
|
4546
|
-
commitment: "confirmed",
|
|
4547
|
-
preflightCommitment: "processed",
|
|
4548
|
-
skipPreflight: false,
|
|
4549
|
-
maxRetries: 5
|
|
4550
|
-
};
|
|
4551
|
-
try {
|
|
4552
|
-
const simulation = await this.connection.simulateTransaction(transaction);
|
|
4553
|
-
if (simulation.value.err) {
|
|
4554
|
-
const logs = simulation.value.logs || [];
|
|
4555
|
-
const message = logs[logs.length - 1] || simulation.value.err || "Unknown error occurred";
|
|
4556
|
-
console.error("send err logs:", logs, message);
|
|
4557
|
-
throw new Error(`Transaction failed: ${message}`);
|
|
4558
|
-
}
|
|
4559
|
-
const signature = await sendAndConfirmRawTransaction(this.connection, rawTx, confirmationStrategy);
|
|
4560
|
-
return signature;
|
|
4561
|
-
} catch (error) {
|
|
4562
|
-
if (error.message.includes("TransactionExpiredTimeoutError")) {
|
|
4563
|
-
const status = await this.connection.getSignatureStatus(transaction.signatures[0].toString());
|
|
4564
|
-
if (status.value?.confirmationStatus === "confirmed") {
|
|
4565
|
-
return transaction.signatures[0].toString();
|
|
4566
|
-
}
|
|
4567
|
-
}
|
|
4568
|
-
throw error;
|
|
4569
|
-
}
|
|
4570
|
-
}
|
|
4571
|
-
async signTransaction({ rawTransaction }) {
|
|
4572
|
-
const params = {
|
|
4573
|
-
rawTransaction,
|
|
4574
|
-
walletId: -1,
|
|
4575
|
-
rpcUrl: this.rpcUrl
|
|
4576
|
-
};
|
|
4577
|
-
const signature = await this.accountInfo.signTransaction(JSON.stringify(params));
|
|
4578
|
-
return signature;
|
|
4579
|
-
}
|
|
4580
|
-
async signAndSendTransaction({ rawTransaction }) {
|
|
4581
|
-
const signedTx = await this.signTransaction({ rawTransaction });
|
|
4582
|
-
if (!signedTx) {
|
|
4583
|
-
return "";
|
|
4584
|
-
}
|
|
4585
|
-
const signature = await this.sendSignedTx(signedTx);
|
|
4586
|
-
return signature;
|
|
4587
|
-
}
|
|
4588
|
-
async signAllTransactions({ rawTransactions }) {
|
|
4589
|
-
throw new Error("no support");
|
|
4590
|
-
}
|
|
4591
|
-
async signAndSendAllTransactions({ rawTransactions }) {
|
|
4592
|
-
throw new Error("no support");
|
|
4593
|
-
}
|
|
4594
|
-
async queryRent(params) {
|
|
4595
|
-
const MIN_ACCOUNT_ACTIVATION_SOL = "0.0009";
|
|
4596
|
-
const SPL_TOKEN_ACCOUNT_CREATION_FEE = "0.001";
|
|
4597
|
-
try {
|
|
4598
|
-
const { toAddress, tokenAddress } = params;
|
|
4599
|
-
let minTransferAmount = "0";
|
|
4600
|
-
let createSplTokenFee = null;
|
|
4601
|
-
if (tokenAddress) {
|
|
4602
|
-
const tokenAccountExists = await this.checkTokenAccount(toAddress, tokenAddress);
|
|
4603
|
-
if (!tokenAccountExists) {
|
|
4604
|
-
createSplTokenFee = SPL_TOKEN_ACCOUNT_CREATION_FEE;
|
|
4605
|
-
}
|
|
4606
|
-
} else {
|
|
4607
|
-
const accountExists = await this.checkAccountExists(toAddress);
|
|
4608
|
-
if (!accountExists) {
|
|
4609
|
-
minTransferAmount = MIN_ACCOUNT_ACTIVATION_SOL;
|
|
4610
|
-
}
|
|
4611
|
-
}
|
|
4612
|
-
const rentInfo = {
|
|
4613
|
-
minTransferAmount,
|
|
4614
|
-
createSplTokenFee
|
|
4615
|
-
};
|
|
4616
|
-
return rentInfo;
|
|
4617
|
-
} catch (error) {
|
|
4618
|
-
console.error("queryRent error:", error);
|
|
4619
|
-
const defaultRentInfo = {
|
|
4620
|
-
minTransferAmount: "0",
|
|
4621
|
-
createSplTokenFee: null
|
|
4622
|
-
};
|
|
4623
|
-
return defaultRentInfo;
|
|
4624
|
-
}
|
|
4876
|
+
},
|
|
4877
|
+
gasFee: calcFee("priorityFeeMedium"),
|
|
4878
|
+
baseFee,
|
|
4879
|
+
gasLimit,
|
|
4880
|
+
priorityFee: {
|
|
4881
|
+
low: gasInfo.priorityFeeLow,
|
|
4882
|
+
medium: gasInfo.priorityFeeMedium,
|
|
4883
|
+
high: gasInfo.priorityFeeHigh
|
|
4884
|
+
}
|
|
4885
|
+
};
|
|
4625
4886
|
}
|
|
4626
|
-
async
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4887
|
+
async createPublicClient({ chainId, rpcUrl }) {
|
|
4888
|
+
if (rpcUrl) {
|
|
4889
|
+
return createPublicClient({
|
|
4890
|
+
transport: http(rpcUrl)
|
|
4891
|
+
});
|
|
4892
|
+
}
|
|
4893
|
+
if (chainId) {
|
|
4894
|
+
this.networks.setChainType(this.chainType);
|
|
4895
|
+
const chainInfo = await this.networks.getNetworkByChainId(chainId);
|
|
4896
|
+
rpcUrl = chainInfo.rpcUrls[0];
|
|
4897
|
+
} else {
|
|
4898
|
+
const chainInfo = await this.getCurrentChain();
|
|
4899
|
+
rpcUrl = chainInfo.rpcUrls[0];
|
|
4900
|
+
}
|
|
4901
|
+
if (!rpcUrl) {
|
|
4902
|
+
throw new Error("rpcUrl is not set");
|
|
4633
4903
|
}
|
|
4904
|
+
return createPublicClient({
|
|
4905
|
+
transport: http(rpcUrl)
|
|
4906
|
+
});
|
|
4634
4907
|
}
|
|
4635
|
-
async
|
|
4908
|
+
async eth_estimateGas(txs) {
|
|
4909
|
+
const { from, to, value = "0x1", chainId } = txs[0] || {};
|
|
4910
|
+
const accounts = await this.accountInfo.getCurrent();
|
|
4911
|
+
if (accounts[0].address !== from) {
|
|
4912
|
+
throw new Error("address is not the current account");
|
|
4913
|
+
}
|
|
4914
|
+
if (!to) {
|
|
4915
|
+
throw new Error("to is not set");
|
|
4916
|
+
}
|
|
4636
4917
|
try {
|
|
4637
|
-
const
|
|
4638
|
-
const
|
|
4639
|
-
|
|
4640
|
-
const accountInfo = await this.connection.getAccountInfo(associatedTokenAddress);
|
|
4641
|
-
return accountInfo !== null;
|
|
4918
|
+
const rpcClient = await this.createPublicClient({ chainId: chainId?.toString() });
|
|
4919
|
+
const gas = await rpcClient.estimateGas({ account: from, to, value: hexToBigInt(value) });
|
|
4920
|
+
return gas;
|
|
4642
4921
|
} catch (error) {
|
|
4643
|
-
console.warn("Failed to
|
|
4644
|
-
|
|
4922
|
+
console.warn("Failed to estimate gas:", error);
|
|
4923
|
+
const BaseConfig3 = SupportedChainTypes[ChainTypes.EVM];
|
|
4924
|
+
const { gasFee } = BaseConfig3;
|
|
4925
|
+
return numberToHex(parseUnits(gasFee.toString(), 18));
|
|
4645
4926
|
}
|
|
4646
4927
|
}
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
var RPC_TIMEOUT = 20 * 1e3;
|
|
4653
|
-
var network = {
|
|
4654
|
-
messagePrefix: "Dogecoin Signed Message:\n",
|
|
4655
|
-
bech32: "dc",
|
|
4656
|
-
bip44: 3,
|
|
4657
|
-
bip32: {
|
|
4658
|
-
public: 49990397,
|
|
4659
|
-
private: 49988504
|
|
4660
|
-
},
|
|
4661
|
-
pubKeyHash: 30,
|
|
4662
|
-
scriptHash: 22,
|
|
4663
|
-
wif: 158
|
|
4664
|
-
};
|
|
4665
|
-
|
|
4666
|
-
// src/dogecoin/utils-doge.ts
|
|
4667
|
-
var DogecoinUtils = class {
|
|
4668
|
-
/**
|
|
4669
|
-
* Build the PSBT from the transaction
|
|
4670
|
-
* @param tx utxoTx
|
|
4671
|
-
* @param _maximumFeeRate number (optional, currently unused)
|
|
4672
|
-
* @returns base64
|
|
4673
|
-
*/
|
|
4674
|
-
static buildPsbtToBase64(tx, _maximumFeeRate) {
|
|
4675
|
-
const psbt = new Psbt({ network });
|
|
4676
|
-
for (const input of tx.inputs) {
|
|
4677
|
-
const inputOptions = {
|
|
4678
|
-
hash: input.txId,
|
|
4679
|
-
index: input.vOut
|
|
4680
|
-
};
|
|
4681
|
-
if (input.nonWitnessUtxo) {
|
|
4682
|
-
inputOptions.nonWitnessUtxo = Buffer.from(input.nonWitnessUtxo, "hex");
|
|
4683
|
-
}
|
|
4684
|
-
psbt.addInput(inputOptions);
|
|
4928
|
+
// Get nonce for current account
|
|
4929
|
+
async eth_getTransactionCount([address, type]) {
|
|
4930
|
+
const accounts = await this.accountInfo.getCurrent();
|
|
4931
|
+
if (accounts[0].address !== address) {
|
|
4932
|
+
throw new Error("address is not the current account");
|
|
4685
4933
|
}
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
value: output.amount,
|
|
4689
|
-
address: output.address
|
|
4690
|
-
});
|
|
4934
|
+
if (type !== "latest" && type !== "pending") {
|
|
4935
|
+
throw new Error("type is not supported");
|
|
4691
4936
|
}
|
|
4692
|
-
const psbtHex = psbt.toHex();
|
|
4693
|
-
return toBase64(fromHex3(psbtHex));
|
|
4694
|
-
}
|
|
4695
|
-
/**
|
|
4696
|
-
* Extract the transaction from the signed PSBT
|
|
4697
|
-
* @param signedPsbt base64
|
|
4698
|
-
* @param _maximumFeeRate number (optional, currently unused)
|
|
4699
|
-
* @returns transaction hex
|
|
4700
|
-
*/
|
|
4701
|
-
static extractPsbtTransaction(signedPsbt, _maximumFeeRate) {
|
|
4702
|
-
const signedPsbtHex = toHex3(fromBase64(signedPsbt));
|
|
4703
|
-
const psbt = Psbt.fromHex(signedPsbtHex, {
|
|
4704
|
-
network
|
|
4705
|
-
});
|
|
4706
|
-
const maximumFeeRate = _maximumFeeRate || 1e5;
|
|
4707
|
-
psbt.setMaximumFeeRate(maximumFeeRate);
|
|
4708
|
-
psbt.finalizeAllInputs();
|
|
4709
|
-
const transaction = psbt.extractTransaction();
|
|
4710
|
-
return transaction.toHex();
|
|
4711
|
-
}
|
|
4712
|
-
/**
|
|
4713
|
-
* Convert raw transaction hex to PSBT base64
|
|
4714
|
-
* This method converts an unsigned raw transaction to PSBT format.
|
|
4715
|
-
* Note: The rawTx should be an unsigned transaction, and the nonWitnessUtxo
|
|
4716
|
-
* for each input will need to be fetched separately from the blockchain.
|
|
4717
|
-
* @param rawTx hex string of the raw transaction
|
|
4718
|
-
* @returns base64 string of the PSBT
|
|
4719
|
-
*/
|
|
4720
|
-
static async rawTxToPsbtBase64(rawTx) {
|
|
4721
4937
|
try {
|
|
4722
|
-
const
|
|
4723
|
-
const
|
|
4724
|
-
|
|
4725
|
-
for (let i = 0; i < transaction.ins.length; i++) {
|
|
4726
|
-
const input = transaction.ins[i];
|
|
4727
|
-
const hash = Buffer.from(input.hash).reverse().toString("hex");
|
|
4728
|
-
const index = input.index;
|
|
4729
|
-
const inputOptions = {
|
|
4730
|
-
hash,
|
|
4731
|
-
index,
|
|
4732
|
-
nonWitnessUtxo: input.script
|
|
4733
|
-
};
|
|
4734
|
-
psbt.addInput(inputOptions);
|
|
4735
|
-
}
|
|
4736
|
-
for (const output of transaction.outs) {
|
|
4737
|
-
try {
|
|
4738
|
-
const address$1 = address.fromOutputScript(output.script, network);
|
|
4739
|
-
psbt.addOutput({
|
|
4740
|
-
address: address$1,
|
|
4741
|
-
value: Number(output.value)
|
|
4742
|
-
});
|
|
4743
|
-
} catch (error) {
|
|
4744
|
-
psbt.addOutput({
|
|
4745
|
-
script: output.script,
|
|
4746
|
-
value: Number(output.value)
|
|
4747
|
-
});
|
|
4748
|
-
}
|
|
4749
|
-
}
|
|
4750
|
-
const psbtHex = psbt.toHex();
|
|
4751
|
-
return toBase64(fromHex3(psbtHex));
|
|
4938
|
+
const rpcClient = await this.createPublicClient({});
|
|
4939
|
+
const nonce = await rpcClient.getTransactionCount({ address });
|
|
4940
|
+
return nonce;
|
|
4752
4941
|
} catch (error) {
|
|
4753
|
-
console.
|
|
4754
|
-
throw new Error(
|
|
4755
|
-
`Failed to convert raw transaction to PSBT: ${error instanceof Error ? error.message : String(error)}`
|
|
4756
|
-
);
|
|
4942
|
+
console.error("Failed to get nonce:", error);
|
|
4943
|
+
throw new Error(`Failed to get nonce: ${error}`);
|
|
4757
4944
|
}
|
|
4758
4945
|
}
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4946
|
+
//https://docs.metamask.io/snaps/reference/keyring-api/chain-methods/#eth_signtransaction
|
|
4947
|
+
async eth_signTransaction(txParams) {
|
|
4948
|
+
const preparedTxPropsType = {
|
|
4949
|
+
chainId: "number",
|
|
4950
|
+
to: "string",
|
|
4951
|
+
value: "bigint",
|
|
4952
|
+
data: "string",
|
|
4953
|
+
nonce: "number",
|
|
4954
|
+
maxPriorityFeePerGas: "bigint",
|
|
4955
|
+
maxFeePerGas: "bigint",
|
|
4956
|
+
gasPrice: "bigint",
|
|
4957
|
+
gas: "bigint"
|
|
4958
|
+
};
|
|
4959
|
+
const txData = txParams?.[0];
|
|
4960
|
+
txData.gas = txData?.gas || txData?.gasLimit;
|
|
4961
|
+
txData.data = txData.data || "0x";
|
|
4962
|
+
txData.value = txData.value || "0x";
|
|
4963
|
+
txData.nonce = txData.nonce || "0x0";
|
|
4964
|
+
if (!txData?.gas || !txData?.to || !txData?.chainId) {
|
|
4965
|
+
throw new Error("gas or to or chainId is not set");
|
|
4766
4966
|
}
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4967
|
+
const accounts = await this.accountInfo.getCurrent();
|
|
4968
|
+
const address = accounts[0].address;
|
|
4969
|
+
if (txData?.from && !isAddressEqual(txData?.from, address)) {
|
|
4970
|
+
console.error("eth_signTransaction error data: from is not the current account", txData);
|
|
4971
|
+
throw new Error(`eth_signTransaction error data: from is not the current account`);
|
|
4972
|
+
}
|
|
4973
|
+
delete txData?.from;
|
|
4974
|
+
delete txData?.gasLimit;
|
|
4975
|
+
const preparedTx = {
|
|
4976
|
+
gas: txData?.gas
|
|
4977
|
+
};
|
|
4978
|
+
for (const key in preparedTxPropsType) {
|
|
4979
|
+
if (txData?.[key] && isHex(txData?.[key])) {
|
|
4980
|
+
preparedTx[key] = preparedTxPropsType[key] === "number" ? fromHex$1(txData[key], "number") : txData[key];
|
|
4981
|
+
}
|
|
4982
|
+
}
|
|
4983
|
+
if (txData?.type !== "legacy") {
|
|
4984
|
+
delete preparedTx.gasPrice;
|
|
4777
4985
|
}
|
|
4778
|
-
return amount.dividedBy(KOINU_PER_DOGE).toNumber();
|
|
4779
|
-
} catch (error) {
|
|
4780
|
-
throw new Error(`toBitcoin failed: ${error.message}`);
|
|
4781
|
-
}
|
|
4782
|
-
}
|
|
4783
|
-
function addUsedUtxos(newUsedUtxos) {
|
|
4784
|
-
const usedUtxos = cache.get("UsedUtxos") || {};
|
|
4785
|
-
for (const txid in newUsedUtxos) {
|
|
4786
|
-
usedUtxos[txid] = 1;
|
|
4787
|
-
}
|
|
4788
|
-
cache.set("UsedUtxos", usedUtxos, false);
|
|
4789
|
-
}
|
|
4790
|
-
async function createPsbt({
|
|
4791
|
-
from,
|
|
4792
|
-
to,
|
|
4793
|
-
amount,
|
|
4794
|
-
fee,
|
|
4795
|
-
spendableUtxos
|
|
4796
|
-
}) {
|
|
4797
|
-
const utxos = spendableUtxos;
|
|
4798
|
-
if (!utxos || utxos.length === 0) {
|
|
4799
|
-
throw new Error("no spendable utxos");
|
|
4800
|
-
}
|
|
4801
|
-
const sendAmount = toSatoshi(amount);
|
|
4802
|
-
const sendCost = toSatoshi(fee);
|
|
4803
|
-
const totalNeeded = sendAmount + sendCost;
|
|
4804
|
-
const sortedUtxos = utxos.sort((a, b) => b.outputValue - a.outputValue);
|
|
4805
|
-
const selectedUtxos = [];
|
|
4806
|
-
let accumulatedAmount = 0;
|
|
4807
|
-
for (const utxo of sortedUtxos) {
|
|
4808
|
-
if (accumulatedAmount >= totalNeeded) break;
|
|
4809
|
-
selectedUtxos.push(utxo);
|
|
4810
|
-
accumulatedAmount += Number(utxo.outputValue);
|
|
4811
|
-
}
|
|
4812
|
-
if (accumulatedAmount < totalNeeded) {
|
|
4813
|
-
throw new Error("not enough funds to cover amount and fee");
|
|
4814
|
-
}
|
|
4815
|
-
const utxoDetailPromises = selectedUtxos.map(async (utxo) => {
|
|
4816
4986
|
try {
|
|
4817
|
-
const
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4987
|
+
const serializedTransaction = await this.accountInfo.signTransaction(
|
|
4988
|
+
JSON.stringify({
|
|
4989
|
+
data: preparedTx,
|
|
4990
|
+
types: preparedTxPropsType
|
|
4991
|
+
})
|
|
4992
|
+
);
|
|
4993
|
+
if (serializedTransaction === "") {
|
|
4994
|
+
throw new Error(`eth_signTransaction error data: ${JSON.stringify(txParams)}`);
|
|
4995
|
+
}
|
|
4996
|
+
const data = parseTransaction(serializedTransaction);
|
|
4997
|
+
return data;
|
|
4998
|
+
} catch (err) {
|
|
4999
|
+
throw new Error("eth_signTransaction error" + err);
|
|
4821
5000
|
}
|
|
4822
|
-
}
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
if (addedAmount >= totalNeeded) break;
|
|
4829
|
-
const { txid, vout, outputValue, address = from } = utxo;
|
|
4830
|
-
if (utxoDetail?.hex && !usingUtxos[txid]) {
|
|
4831
|
-
inputs.push({
|
|
4832
|
-
txId: txid,
|
|
4833
|
-
vOut: vout,
|
|
4834
|
-
amount: Number(outputValue),
|
|
4835
|
-
nonWitnessUtxo: utxoDetail.hex,
|
|
4836
|
-
address
|
|
5001
|
+
}
|
|
5002
|
+
async eth_sendRawTransaction([serializedTransaction], rpcUrl) {
|
|
5003
|
+
try {
|
|
5004
|
+
const rpcClient = await this.createPublicClient({ rpcUrl });
|
|
5005
|
+
const hash = await rpcClient.sendRawTransaction({
|
|
5006
|
+
serializedTransaction
|
|
4837
5007
|
});
|
|
4838
|
-
|
|
4839
|
-
|
|
5008
|
+
return hash;
|
|
5009
|
+
} catch (error) {
|
|
5010
|
+
console.error("Failed to send transaction via RPC:", error, rpcUrl);
|
|
5011
|
+
throw error;
|
|
4840
5012
|
}
|
|
4841
5013
|
}
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
{
|
|
4847
|
-
|
|
4848
|
-
|
|
5014
|
+
async getTransaction(hash) {
|
|
5015
|
+
if (!hash || !isHex(hash)) {
|
|
5016
|
+
throw new Error("txId is not valid");
|
|
5017
|
+
}
|
|
5018
|
+
try {
|
|
5019
|
+
const rpcClient = await this.createPublicClient({});
|
|
5020
|
+
const tx = await rpcClient.getTransaction({
|
|
5021
|
+
hash
|
|
5022
|
+
});
|
|
5023
|
+
return tx;
|
|
5024
|
+
} catch (error) {
|
|
5025
|
+
console.error("Failed to send transaction via RPC:", error, hash);
|
|
5026
|
+
throw error;
|
|
4849
5027
|
}
|
|
4850
|
-
];
|
|
4851
|
-
const changeAmount = addedAmount - sendAmount - sendCost;
|
|
4852
|
-
if (changeAmount > 0) {
|
|
4853
|
-
outputs.push({
|
|
4854
|
-
address: from,
|
|
4855
|
-
amount: changeAmount
|
|
4856
|
-
});
|
|
4857
|
-
}
|
|
4858
|
-
const params = {
|
|
4859
|
-
address: from,
|
|
4860
|
-
inputs,
|
|
4861
|
-
outputs
|
|
4862
|
-
};
|
|
4863
|
-
const psbtBase64 = DogecoinUtils.buildPsbtToBase64(params);
|
|
4864
|
-
return { psbtBase64, usingUtxos };
|
|
4865
|
-
}
|
|
4866
|
-
var mydoge = axios.create({
|
|
4867
|
-
baseURL: MYDOGE_BASE_URL
|
|
4868
|
-
});
|
|
4869
|
-
var api = axios.create({
|
|
4870
|
-
baseURL: RPC_URL,
|
|
4871
|
-
timeout: RPC_TIMEOUT
|
|
4872
|
-
});
|
|
4873
|
-
async function getBalance(address) {
|
|
4874
|
-
if (!address) {
|
|
4875
|
-
return {
|
|
4876
|
-
address: "",
|
|
4877
|
-
balance: 0
|
|
4878
|
-
};
|
|
4879
5028
|
}
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
5029
|
+
};
|
|
5030
|
+
var BaseConfig2 = SupportedChainTypes[ChainTypes.SOL];
|
|
5031
|
+
var TOKEN_METADATA_PROGRAM_ID = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s";
|
|
5032
|
+
var MSG_PREFIX = "\xFFsolana offchain";
|
|
5033
|
+
|
|
5034
|
+
// src/solana/utils.ts
|
|
5035
|
+
__toESM(require_bn());
|
|
5036
|
+
new PublicKey(TOKEN_METADATA_PROGRAM_ID);
|
|
5037
|
+
var txToHex = (tx) => {
|
|
5038
|
+
if (tx instanceof VersionedTransaction) {
|
|
5039
|
+
return Buffer.from(tx.serialize()).toString("hex");
|
|
4888
5040
|
}
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
async function getUtxos(address, cursor, result, filter, tx = null) {
|
|
4897
|
-
const query = (await mydoge.get(`${MYDOGE_BASE_URL}/utxos/${address}?filter=${filter}${cursor ? `&cursor=${cursor}` : ""}`)).data;
|
|
4898
|
-
let { utxos } = query;
|
|
4899
|
-
if (tx) {
|
|
4900
|
-
utxos = utxos.filter((utxo) => utxo.txid === tx?.txid && utxo.vout === tx?.vout);
|
|
5041
|
+
if (tx instanceof Transaction$1) {
|
|
5042
|
+
return Buffer.from(
|
|
5043
|
+
tx.serialize({
|
|
5044
|
+
requireAllSignatures: false,
|
|
5045
|
+
verifySignatures: false
|
|
5046
|
+
})
|
|
5047
|
+
).toString("hex");
|
|
4901
5048
|
}
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
5049
|
+
return tx;
|
|
5050
|
+
};
|
|
5051
|
+
async function createLegacyTx({ from = "", to = "", amount = 0 }, connection) {
|
|
5052
|
+
const fromPubkey = new PublicKey(from);
|
|
5053
|
+
const toPubkey = new PublicKey(to);
|
|
5054
|
+
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
|
|
5055
|
+
const transaction = new Transaction$1().add(
|
|
5056
|
+
SystemProgram.transfer({
|
|
5057
|
+
fromPubkey,
|
|
5058
|
+
//payer
|
|
5059
|
+
toPubkey,
|
|
5060
|
+
//toAccount
|
|
5061
|
+
lamports: amount * LAMPORTS_PER_SOL
|
|
5062
|
+
})
|
|
4910
5063
|
);
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
if (query.next_cursor) {
|
|
4916
|
-
return getUtxos(address, query.next_cursor, result, filter, tx);
|
|
4917
|
-
}
|
|
4918
|
-
}
|
|
4919
|
-
async function getSpendableUtxos(address) {
|
|
4920
|
-
const utxos = [];
|
|
4921
|
-
await getUtxos(address, 0, utxos, "spendable");
|
|
4922
|
-
return utxos;
|
|
5064
|
+
transaction.feePayer = fromPubkey;
|
|
5065
|
+
transaction.recentBlockhash = blockhash;
|
|
5066
|
+
transaction.lastValidBlockHeight = lastValidBlockHeight;
|
|
5067
|
+
return transaction;
|
|
4923
5068
|
}
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
5069
|
+
async function createTokenLegacyTransaction2({
|
|
5070
|
+
from = "",
|
|
5071
|
+
to = "",
|
|
5072
|
+
amount = 0,
|
|
5073
|
+
tokenAddress = "",
|
|
5074
|
+
priorityFee = 0,
|
|
5075
|
+
// microLamports (1 SOL = 1e6 microLamports)
|
|
5076
|
+
decimals = 6
|
|
5077
|
+
}, connection) {
|
|
4927
5078
|
try {
|
|
4928
|
-
const
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
5079
|
+
const fromPubkey = new PublicKey(from);
|
|
5080
|
+
const toPubkey = new PublicKey(to);
|
|
5081
|
+
const tokenPublicKey = new PublicKey(tokenAddress);
|
|
5082
|
+
const fromTokenPubKey = await getAssociatedTokenAddress(tokenPublicKey, fromPubkey);
|
|
5083
|
+
const toTokenPubKey = await getAssociatedTokenAddress(tokenPublicKey, toPubkey);
|
|
5084
|
+
const { blockhash } = await connection.getLatestBlockhash("confirmed");
|
|
5085
|
+
const transaction = new Transaction$1();
|
|
5086
|
+
transaction.feePayer = fromPubkey;
|
|
5087
|
+
transaction.recentBlockhash = blockhash;
|
|
5088
|
+
try {
|
|
5089
|
+
const instruction = createAssociatedTokenAccountInstruction(fromPubkey, toTokenPubKey, toPubkey, tokenPublicKey);
|
|
5090
|
+
transaction.add(instruction);
|
|
5091
|
+
} catch (error) {
|
|
5092
|
+
console.error(error);
|
|
5093
|
+
throw error;
|
|
5094
|
+
}
|
|
5095
|
+
const tokenAmount = new Bignumber(amount).multipliedBy(new Bignumber(10).pow(decimals)).toNumber();
|
|
5096
|
+
transaction.add(
|
|
5097
|
+
createTransferInstruction(fromTokenPubKey, toTokenPubKey, fromPubkey, tokenAmount, [], TOKEN_PROGRAM_ID)
|
|
5098
|
+
);
|
|
5099
|
+
return transaction;
|
|
5100
|
+
} catch (error) {
|
|
5101
|
+
console.error("Error creating transaction:", error);
|
|
5102
|
+
throw error;
|
|
4933
5103
|
}
|
|
4934
|
-
}
|
|
4935
|
-
|
|
4936
|
-
// src/dogecoin/service.ts
|
|
4937
|
-
var DogecoinService = class _DogecoinService extends BaseService {
|
|
5104
|
+
}
|
|
5105
|
+
var SolanaService = class _SolanaService extends BaseService {
|
|
4938
5106
|
static instance;
|
|
4939
5107
|
chainType;
|
|
5108
|
+
rpcUrl;
|
|
5109
|
+
connection;
|
|
4940
5110
|
constructor(chainType, accountInfo, tomoAppInfo) {
|
|
4941
5111
|
super(tomoAppInfo, accountInfo);
|
|
4942
5112
|
this.chainType = chainType;
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
}
|
|
4951
|
-
async requestAccounts() {
|
|
4952
|
-
const addresses = await this.accountInfo.getCurrent();
|
|
4953
|
-
const { publicKey, address } = addresses?.[0] || {};
|
|
4954
|
-
if (!address) {
|
|
4955
|
-
throw new Error("address is not set");
|
|
4956
|
-
}
|
|
4957
|
-
const { balance = 0 } = await getBalance(address);
|
|
4958
|
-
return {
|
|
4959
|
-
address,
|
|
4960
|
-
balance,
|
|
4961
|
-
approved: true,
|
|
4962
|
-
publicKey
|
|
4963
|
-
};
|
|
4964
|
-
}
|
|
4965
|
-
async getAccounts() {
|
|
4966
|
-
const accounts = await this.accountInfo.getCurrent();
|
|
4967
|
-
return accounts.map((account) => account.address);
|
|
4968
|
-
}
|
|
4969
|
-
async getConnectionStatus() {
|
|
4970
|
-
const addresses = await this.accountInfo.getCurrent();
|
|
4971
|
-
const { address } = addresses?.[0] || {};
|
|
4972
|
-
if (!address) {
|
|
4973
|
-
throw new Error("address is not set");
|
|
4974
|
-
}
|
|
4975
|
-
return {
|
|
4976
|
-
connected: true,
|
|
4977
|
-
address,
|
|
4978
|
-
selectedWalletAddress: address
|
|
5113
|
+
const config = {
|
|
5114
|
+
commitment: "confirmed",
|
|
5115
|
+
disableRetryOnRateLimit: false,
|
|
5116
|
+
confirmTransactionInitialTimeout: 12e4,
|
|
5117
|
+
fetch: (url, options) => {
|
|
5118
|
+
return fetch(url, { ...options });
|
|
5119
|
+
}
|
|
4979
5120
|
};
|
|
5121
|
+
const domain = TomoApiDomains[tomoAppInfo.tomoStage];
|
|
5122
|
+
const rpcUrl = `${domain}/rpc/v1/solana`;
|
|
5123
|
+
this.rpcUrl = rpcUrl;
|
|
5124
|
+
this.connection = new Connection(rpcUrl, config);
|
|
4980
5125
|
}
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
if (!address) {
|
|
4985
|
-
throw new Error("address is not set");
|
|
5126
|
+
static getInstance(chainType, accountInfo, tomoAppInfo) {
|
|
5127
|
+
if (!_SolanaService.instance) {
|
|
5128
|
+
_SolanaService.instance = new _SolanaService(chainType, accountInfo, tomoAppInfo);
|
|
4986
5129
|
}
|
|
4987
|
-
|
|
4988
|
-
return {
|
|
4989
|
-
address,
|
|
4990
|
-
balance
|
|
4991
|
-
};
|
|
5130
|
+
return _SolanaService.instance;
|
|
4992
5131
|
}
|
|
4993
|
-
async
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
5132
|
+
async getCurrentWalletAccount() {
|
|
5133
|
+
return await this.accountInfo.getCurrent();
|
|
5134
|
+
}
|
|
5135
|
+
async getAccount() {
|
|
5136
|
+
const { address: currentAddress, publicKey } = await this.accountInfo.getCurrent();
|
|
5137
|
+
return { publicKey: publicKey || currentAddress, address: currentAddress };
|
|
5138
|
+
}
|
|
5139
|
+
async signMessage(params) {
|
|
5140
|
+
const { address: currentAddress, publicKey } = await this.accountInfo.getCurrent();
|
|
5141
|
+
const { message } = params;
|
|
4997
5142
|
const signature = await this.accountInfo.signMessage(message);
|
|
4998
5143
|
return {
|
|
4999
|
-
|
|
5144
|
+
message: MSG_PREFIX + message,
|
|
5145
|
+
signature,
|
|
5146
|
+
publicKey: publicKey || currentAddress
|
|
5000
5147
|
};
|
|
5001
5148
|
}
|
|
5002
|
-
async
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5149
|
+
async signIn(params) {
|
|
5150
|
+
const { address: currentAddress, publicKey } = await this.accountInfo.getCurrent();
|
|
5151
|
+
const { signature = "" } = await this.signMessage(params);
|
|
5152
|
+
return {
|
|
5153
|
+
address: currentAddress,
|
|
5154
|
+
publicKey: publicKey || currentAddress,
|
|
5155
|
+
signature,
|
|
5156
|
+
signedMessage: MSG_PREFIX + params.message
|
|
5157
|
+
};
|
|
5010
5158
|
}
|
|
5011
|
-
async
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
throw new Error("decryptedMessage is not supported");
|
|
5015
|
-
}
|
|
5016
|
-
const unsignRes = await this.accountInfo?.decryptedMessage(message);
|
|
5017
|
-
const { text = "" } = JSON.parse(unsignRes);
|
|
5018
|
-
return {
|
|
5019
|
-
decryptedMessage: text
|
|
5020
|
-
};
|
|
5021
|
-
} catch (err) {
|
|
5022
|
-
throw new Error("requestDecryptedMessage err:" + JSON.stringify(err));
|
|
5159
|
+
async request({ method, params }) {
|
|
5160
|
+
if (!this[method]) {
|
|
5161
|
+
throw new Error(`${method} in request is not supported`);
|
|
5023
5162
|
}
|
|
5163
|
+
return this[method](params);
|
|
5024
5164
|
}
|
|
5025
5165
|
async _queryGasInfo(txData) {
|
|
5026
|
-
const { chainId, amount = 0, decimals =
|
|
5166
|
+
const { tokenAddress, chainId, amount = 0, decimals = 9 } = txData;
|
|
5167
|
+
const value = tokenAddress ? "0x1" : toHex$1(parseUnits(amount.toString(), decimals));
|
|
5168
|
+
let callData = "0x";
|
|
5169
|
+
if (tokenAddress) {
|
|
5170
|
+
const transaction = await createTokenLegacyTransaction2(txData, this.connection);
|
|
5171
|
+
callData = "0x" + txToHex(transaction);
|
|
5172
|
+
} else {
|
|
5173
|
+
const transaction = await createLegacyTx(txData, this.connection);
|
|
5174
|
+
callData = "0x" + txToHex(transaction);
|
|
5175
|
+
}
|
|
5027
5176
|
const gasLimitParam = {
|
|
5028
5177
|
from: txData.from,
|
|
5029
5178
|
to: txData.to,
|
|
5030
|
-
value
|
|
5179
|
+
value
|
|
5031
5180
|
};
|
|
5032
5181
|
const queryGasParams = {
|
|
5033
|
-
chainIndex: Number(chainId
|
|
5034
|
-
callData
|
|
5182
|
+
chainIndex: Number(chainId),
|
|
5183
|
+
callData,
|
|
5035
5184
|
gasLimitParam,
|
|
5036
5185
|
addressList: [txData.from]
|
|
5037
5186
|
};
|
|
@@ -5044,85 +5193,149 @@ var DogecoinService = class _DogecoinService extends BaseService {
|
|
|
5044
5193
|
params: queryGasParams
|
|
5045
5194
|
});
|
|
5046
5195
|
if (!success) {
|
|
5047
|
-
console.error("queryGasInfo
|
|
5196
|
+
console.error("queryGasInfo solana", txData, message, gasInfo);
|
|
5048
5197
|
const { gasFee } = BaseConfig2;
|
|
5049
5198
|
return {
|
|
5050
5199
|
success: true,
|
|
5051
5200
|
gasFee: gasFee.toString()
|
|
5052
5201
|
};
|
|
5053
5202
|
}
|
|
5054
|
-
const
|
|
5203
|
+
const nativeChainId = SupportedChainTypes[this.chainType].chainId;
|
|
5204
|
+
const { nativeCurrency } = await this.networks.getNetworkByChainId(nativeChainId);
|
|
5205
|
+
const { baseFee = 1, gasLimit = 0 } = gasInfo;
|
|
5206
|
+
const baseFeeBN = new BigNumber(baseFee).times(2);
|
|
5207
|
+
const gasLimitBN = new BigNumber(gasLimit);
|
|
5055
5208
|
const calcFee = (feeLevel) => {
|
|
5056
|
-
const
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
const fees = {
|
|
5060
|
-
low: calcFee("priorityFeeLow"),
|
|
5061
|
-
medium: calcFee("priorityFeeMedium"),
|
|
5062
|
-
high: calcFee("priorityFeeHigh")
|
|
5209
|
+
const priorityFee = gasLimitBN.times(gasInfo[feeLevel] || 0).dividedBy(1e6).integerValue(BigNumber.ROUND_DOWN);
|
|
5210
|
+
const gasFee = baseFeeBN.plus(priorityFee);
|
|
5211
|
+
return formatUnits(BigInt(gasFee.toNumber()), nativeCurrency?.decimals || 9);
|
|
5063
5212
|
};
|
|
5064
5213
|
return {
|
|
5065
5214
|
success: true,
|
|
5066
|
-
fees
|
|
5067
|
-
|
|
5215
|
+
fees: {
|
|
5216
|
+
low: calcFee("priorityFeeLow"),
|
|
5217
|
+
medium: calcFee("priorityFeeMedium"),
|
|
5218
|
+
high: calcFee("priorityFeeHigh")
|
|
5219
|
+
},
|
|
5220
|
+
gasFee: calcFee("priorityFeeHigh")
|
|
5068
5221
|
};
|
|
5069
5222
|
}
|
|
5070
|
-
async
|
|
5071
|
-
rawTx
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5223
|
+
async sendSignedTx(signedTx) {
|
|
5224
|
+
let rawTx;
|
|
5225
|
+
try {
|
|
5226
|
+
const hexBuffer = Buffer.from(signedTx, "hex");
|
|
5227
|
+
VersionedTransaction.deserialize(hexBuffer);
|
|
5228
|
+
rawTx = hexBuffer;
|
|
5229
|
+
} catch (error) {
|
|
5230
|
+
const base58Buffer = Buffer.from(toBase58());
|
|
5231
|
+
VersionedTransaction.deserialize(base58Buffer);
|
|
5232
|
+
rawTx = base58Buffer;
|
|
5078
5233
|
}
|
|
5079
|
-
const
|
|
5080
|
-
if (
|
|
5081
|
-
|
|
5082
|
-
signedRawTx
|
|
5083
|
-
};
|
|
5234
|
+
const transaction = VersionedTransaction.deserialize(rawTx);
|
|
5235
|
+
if (!transaction.signatures || transaction.signatures.length === 0) {
|
|
5236
|
+
throw new Error("lack of sign");
|
|
5084
5237
|
}
|
|
5085
|
-
const
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5238
|
+
const confirmationStrategy = {
|
|
5239
|
+
commitment: "confirmed",
|
|
5240
|
+
preflightCommitment: "processed",
|
|
5241
|
+
skipPreflight: false,
|
|
5242
|
+
maxRetries: 5
|
|
5089
5243
|
};
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5244
|
+
try {
|
|
5245
|
+
const simulation = await this.connection.simulateTransaction(transaction);
|
|
5246
|
+
if (simulation.value.err) {
|
|
5247
|
+
const logs = simulation.value.logs || [];
|
|
5248
|
+
const message = logs[logs.length - 1] || simulation.value.err || "Unknown error occurred";
|
|
5249
|
+
console.error("send err logs:", logs, message);
|
|
5250
|
+
throw new Error(`Transaction failed: ${message}`);
|
|
5251
|
+
}
|
|
5252
|
+
const signature = await sendAndConfirmRawTransaction(this.connection, rawTx, confirmationStrategy);
|
|
5253
|
+
return signature;
|
|
5254
|
+
} catch (error) {
|
|
5255
|
+
if (error.message.includes("TransactionExpiredTimeoutError")) {
|
|
5256
|
+
const status = await this.connection.getSignatureStatus(transaction.signatures[0].toString());
|
|
5257
|
+
if (status.value?.confirmationStatus === "confirmed") {
|
|
5258
|
+
return transaction.signatures[0].toString();
|
|
5259
|
+
}
|
|
5260
|
+
}
|
|
5261
|
+
throw error;
|
|
5095
5262
|
}
|
|
5096
|
-
|
|
5097
|
-
|
|
5263
|
+
}
|
|
5264
|
+
async signTransaction({ rawTransaction }) {
|
|
5265
|
+
const params = {
|
|
5266
|
+
rawTransaction,
|
|
5267
|
+
walletId: -1,
|
|
5268
|
+
rpcUrl: this.rpcUrl
|
|
5269
|
+
};
|
|
5270
|
+
const signature = await this.accountInfo.signTransaction(JSON.stringify(params));
|
|
5271
|
+
return signature;
|
|
5272
|
+
}
|
|
5273
|
+
async signAndSendTransaction({ rawTransaction }) {
|
|
5274
|
+
const signedTx = await this.signTransaction({ rawTransaction });
|
|
5275
|
+
if (!signedTx) {
|
|
5276
|
+
return "";
|
|
5098
5277
|
}
|
|
5099
|
-
const
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5278
|
+
const signature = await this.sendSignedTx(signedTx);
|
|
5279
|
+
return signature;
|
|
5280
|
+
}
|
|
5281
|
+
async signAllTransactions({ rawTransactions }) {
|
|
5282
|
+
throw new Error("no support");
|
|
5283
|
+
}
|
|
5284
|
+
async signAndSendAllTransactions({ rawTransactions }) {
|
|
5285
|
+
throw new Error("no support");
|
|
5286
|
+
}
|
|
5287
|
+
async queryRent(params) {
|
|
5288
|
+
const MIN_ACCOUNT_ACTIVATION_SOL = "0.0009";
|
|
5289
|
+
const SPL_TOKEN_ACCOUNT_CREATION_FEE = "0.001";
|
|
5290
|
+
try {
|
|
5291
|
+
const { toAddress, tokenAddress } = params;
|
|
5292
|
+
let minTransferAmount = "0";
|
|
5293
|
+
let createSplTokenFee = null;
|
|
5294
|
+
if (tokenAddress) {
|
|
5295
|
+
const tokenAccountExists = await this.checkTokenAccount(toAddress, tokenAddress);
|
|
5296
|
+
if (!tokenAccountExists) {
|
|
5297
|
+
createSplTokenFee = SPL_TOKEN_ACCOUNT_CREATION_FEE;
|
|
5298
|
+
}
|
|
5299
|
+
} else {
|
|
5300
|
+
const accountExists = await this.checkAccountExists(toAddress);
|
|
5301
|
+
if (!accountExists) {
|
|
5302
|
+
minTransferAmount = MIN_ACCOUNT_ACTIVATION_SOL;
|
|
5303
|
+
}
|
|
5304
|
+
}
|
|
5305
|
+
const rentInfo = {
|
|
5306
|
+
minTransferAmount,
|
|
5307
|
+
createSplTokenFee
|
|
5308
|
+
};
|
|
5309
|
+
return rentInfo;
|
|
5310
|
+
} catch (error) {
|
|
5311
|
+
console.error("queryRent error:", error);
|
|
5312
|
+
const defaultRentInfo = {
|
|
5313
|
+
minTransferAmount: "0",
|
|
5314
|
+
createSplTokenFee: null
|
|
5315
|
+
};
|
|
5316
|
+
return defaultRentInfo;
|
|
5104
5317
|
}
|
|
5318
|
+
}
|
|
5319
|
+
async checkAccountExists(address) {
|
|
5105
5320
|
try {
|
|
5106
|
-
const
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5321
|
+
const accountInfo = await this.connection.getAccountInfo(new PublicKey(address));
|
|
5322
|
+
return accountInfo !== null;
|
|
5323
|
+
} catch (error) {
|
|
5324
|
+
console.warn("Failed to check account exists:", error);
|
|
5325
|
+
return false;
|
|
5111
5326
|
}
|
|
5112
5327
|
}
|
|
5113
|
-
async
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5328
|
+
async checkTokenAccount(ownerAddress, tokenMint) {
|
|
5329
|
+
try {
|
|
5330
|
+
const owner = new PublicKey(ownerAddress);
|
|
5331
|
+
const mint = new PublicKey(tokenMint);
|
|
5332
|
+
const associatedTokenAddress = await getAssociatedTokenAddress(mint, owner);
|
|
5333
|
+
const accountInfo = await this.connection.getAccountInfo(associatedTokenAddress);
|
|
5334
|
+
return accountInfo !== null;
|
|
5335
|
+
} catch (error) {
|
|
5336
|
+
console.warn("Failed to check token account:", error);
|
|
5337
|
+
return false;
|
|
5117
5338
|
}
|
|
5118
|
-
return {
|
|
5119
|
-
txId: transaction.txid,
|
|
5120
|
-
confirmations: transaction.confirmations,
|
|
5121
|
-
status: transaction.confirmations > 0 ? "confirmed" : "pending",
|
|
5122
|
-
dogeAmount: transaction.vout[0]?.value,
|
|
5123
|
-
blockTime: transaction.blockTime,
|
|
5124
|
-
address: transaction.vout[0]?.addresses[0]
|
|
5125
|
-
};
|
|
5126
5339
|
}
|
|
5127
5340
|
};
|
|
5128
5341
|
var TomoWallet = class _TomoWallet extends BaseService {
|
|
@@ -5216,4 +5429,4 @@ var ChainTypeServices = {
|
|
|
5216
5429
|
[ChainTypes.DOGE]: DogecoinService
|
|
5217
5430
|
};
|
|
5218
5431
|
|
|
5219
|
-
export { AccountType, ChainTypeServices, DogecoinService, EvmService, SolanaService, TomoWallet, TxTypes };
|
|
5432
|
+
export { AccountType, ChainTypeServices, rpc_exports as DogecoinAPI, DogecoinAddress, DogecoinService, DogecoinUtils, EvmService, SolanaService, TomoWallet, TransactionParser, TxTypes, addUsedUtxos, createPsbt, decodePsbt, getUsedUtxos, toBitcoin, toSatoshi };
|