@tomo-inc/chains-service 0.0.7 → 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/CHANGELOG.md +4 -0
- package/dist/index.cjs +837 -107
- package/dist/index.d.cts +293 -46
- package/dist/index.d.ts +293 -46
- package/dist/index.js +834 -115
- package/package.json +2 -2
- package/src/api/network-data.ts +33 -5
- package/src/api/token.ts +11 -6
- package/src/base/service.ts +4 -4
- package/src/base/token.ts +8 -9
- package/src/dogecoin/rpc.ts +10 -191
- package/src/dogecoin/service.ts +44 -264
- package/src/dogecoin/type.ts +12 -0
- package/src/dogecoin/utils-doge.ts +88 -2
- package/src/dogecoin/utils.ts +3 -380
- package/src/evm/service.ts +57 -73
- package/src/index.ts +10 -5
- package/src/solana/service.ts +6 -6
- package/src/types/account.ts +4 -3
- package/src/types/index.ts +3 -3
- package/src/utils/index.ts +7 -0
package/dist/index.cjs
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var walletUtils = require('@tomo-inc/wallet-utils');
|
|
4
|
-
var Bignumber = require('bignumber.js');
|
|
5
|
-
var viem = require('viem');
|
|
6
4
|
var axios = require('axios');
|
|
7
5
|
var CryptoJS = require('crypto-js');
|
|
6
|
+
var Bignumber = require('bignumber.js');
|
|
7
|
+
var bitcoinjsLib = require('bitcoinjs-lib');
|
|
8
|
+
var viem = require('viem');
|
|
8
9
|
var splToken = require('@solana/spl-token');
|
|
9
10
|
var web3_js = require('@solana/web3.js');
|
|
10
11
|
|
|
11
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
13
|
|
|
13
|
-
var Bignumber__default = /*#__PURE__*/_interopDefault(Bignumber);
|
|
14
14
|
var axios__default = /*#__PURE__*/_interopDefault(axios);
|
|
15
15
|
var CryptoJS__default = /*#__PURE__*/_interopDefault(CryptoJS);
|
|
16
|
+
var Bignumber__default = /*#__PURE__*/_interopDefault(Bignumber);
|
|
16
17
|
|
|
17
18
|
var __create = Object.create;
|
|
18
19
|
var __defProp = Object.defineProperty;
|
|
@@ -23,6 +24,10 @@ var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
|
23
24
|
var __commonJS = (cb, mod) => function __require() {
|
|
24
25
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
25
26
|
};
|
|
27
|
+
var __export = (target, all) => {
|
|
28
|
+
for (var name in all)
|
|
29
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
30
|
+
};
|
|
26
31
|
var __copyProps = (to, from, except, desc) => {
|
|
27
32
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
28
33
|
for (let key of __getOwnPropNames(from))
|
|
@@ -2804,18 +2809,18 @@ var Networks = class {
|
|
|
2804
2809
|
return networks;
|
|
2805
2810
|
}
|
|
2806
2811
|
async getNetworkByChainId(chainId) {
|
|
2807
|
-
const
|
|
2808
|
-
if (!
|
|
2812
|
+
const network2 = await this.networkAPIs.getNetworkByChainId(chainId);
|
|
2813
|
+
if (!network2) {
|
|
2809
2814
|
throw new Error("Network not found");
|
|
2810
2815
|
}
|
|
2811
|
-
return
|
|
2816
|
+
return network2;
|
|
2812
2817
|
}
|
|
2813
2818
|
async getNetworkByChainIndex(chainIndex) {
|
|
2814
|
-
const
|
|
2815
|
-
if (!
|
|
2819
|
+
const network2 = await this.networkAPIs.getNetworkByChainIndex(chainIndex);
|
|
2820
|
+
if (!network2) {
|
|
2816
2821
|
throw new Error("Network not found");
|
|
2817
2822
|
}
|
|
2818
|
-
return
|
|
2823
|
+
return network2;
|
|
2819
2824
|
}
|
|
2820
2825
|
async getCurrentNetwork() {
|
|
2821
2826
|
const chainType = this.chainType;
|
|
@@ -2838,8 +2843,8 @@ var Tokens = class {
|
|
|
2838
2843
|
constructor(tokenService) {
|
|
2839
2844
|
this.tokenAPIs = tokenService;
|
|
2840
2845
|
}
|
|
2841
|
-
async searchTokens({ chainIndex,
|
|
2842
|
-
const { data: tokens = [] } = await this.tokenAPIs.queryRemoteTokens({ keyword
|
|
2846
|
+
async searchTokens({ chainIndex, keyword }) {
|
|
2847
|
+
const { data: tokens = [] } = await this.tokenAPIs.queryRemoteTokens({ keyword, chainIndex });
|
|
2843
2848
|
return tokens;
|
|
2844
2849
|
}
|
|
2845
2850
|
// public async addToken(tokenInfo: Omit<TokenInfo, "id">): Promise<TokenInfo> {
|
|
@@ -2847,10 +2852,8 @@ var Tokens = class {
|
|
|
2847
2852
|
// return tokenInfoData;
|
|
2848
2853
|
// }
|
|
2849
2854
|
async getTokenInfo({ address, chainIndex }) {
|
|
2850
|
-
const {
|
|
2851
|
-
|
|
2852
|
-
} = await this.tokenAPIs.getTokenInfo({ address, chainIndex });
|
|
2853
|
-
return tokenInfo;
|
|
2855
|
+
const res = await this.tokenAPIs.getTokenInfo({ address, chainIndex });
|
|
2856
|
+
return res?.data?.data;
|
|
2854
2857
|
}
|
|
2855
2858
|
async getTokenRiskInfo(_params) {
|
|
2856
2859
|
const { data: tokenRiskInfo } = await this.tokenAPIs.getTokenRisk(_params);
|
|
@@ -2980,7 +2983,7 @@ var BasePublicService = class {
|
|
|
2980
2983
|
this.apiBase = publicApiBase;
|
|
2981
2984
|
this.tomoAppInfo = tomoAppInfo;
|
|
2982
2985
|
[this.tokenApi, this.txApi, this.walletApi].map(
|
|
2983
|
-
(
|
|
2986
|
+
(api2, i) => api2.interceptors.request.use((params) => {
|
|
2984
2987
|
const { tokenBaseUrl, txBaseUrl, walletBaseUrl } = publicApiBase;
|
|
2985
2988
|
params.baseURL = [tokenBaseUrl, txBaseUrl, walletBaseUrl][i];
|
|
2986
2989
|
return signRequest(params, tomoAppInfo.tomoClientId, tomoAppInfo);
|
|
@@ -3021,10 +3024,15 @@ var TokenAPIs = class _TokenAPIs extends BasePublicService {
|
|
|
3021
3024
|
}
|
|
3022
3025
|
}
|
|
3023
3026
|
async getTokenRisk(params) {
|
|
3024
|
-
if (typeof params.chainIndex !== "number" || !params.
|
|
3027
|
+
if (typeof params.chainIndex !== "number" || !params.address) {
|
|
3025
3028
|
throw new Error("chainName or tokenAddress is required");
|
|
3026
3029
|
}
|
|
3027
|
-
const res = await this.tokenApi.post("/v1/market/risk/details", [
|
|
3030
|
+
const res = await this.tokenApi.post("/v1/market/risk/details", [
|
|
3031
|
+
{
|
|
3032
|
+
chainIndex: params.chainIndex,
|
|
3033
|
+
tokenAddress: params.address
|
|
3034
|
+
}
|
|
3035
|
+
]);
|
|
3028
3036
|
return {
|
|
3029
3037
|
success: res?.data?.code === "0",
|
|
3030
3038
|
message: res?.data?.msg,
|
|
@@ -3112,10 +3120,10 @@ var TokenAPIs = class _TokenAPIs extends BasePublicService {
|
|
|
3112
3120
|
}
|
|
3113
3121
|
}
|
|
3114
3122
|
async getTokenDetail(params) {
|
|
3115
|
-
const { chainIndex,
|
|
3123
|
+
const { chainIndex, address } = params;
|
|
3116
3124
|
const res = await this.tokenApi.get(`/v1/market/token/detail`, {
|
|
3117
3125
|
params: {
|
|
3118
|
-
tokenAddress,
|
|
3126
|
+
tokenAddress: address,
|
|
3119
3127
|
chainIndex
|
|
3120
3128
|
}
|
|
3121
3129
|
});
|
|
@@ -3267,12 +3275,40 @@ var loadNetworks = (WALLET_DOMAIN) => {
|
|
|
3267
3275
|
supportHistory: false
|
|
3268
3276
|
},
|
|
3269
3277
|
{
|
|
3270
|
-
chainId:
|
|
3271
|
-
chainIndex:
|
|
3272
|
-
name: "
|
|
3273
|
-
chainName: "
|
|
3278
|
+
chainId: 26888,
|
|
3279
|
+
chainIndex: 2688800,
|
|
3280
|
+
name: "ABCORE_TESTNET",
|
|
3281
|
+
chainName: "AB Core Testnet",
|
|
3282
|
+
rpcUrls: ["https://rpc.core.testnet.ab.org"],
|
|
3283
|
+
blockExplorerUrl: "https://explorer.core.testnet.ab.org",
|
|
3284
|
+
platformType: "EVM",
|
|
3285
|
+
isTestnet: true,
|
|
3286
|
+
icon: "/assets/ab.svg",
|
|
3287
|
+
supportSwap: true,
|
|
3288
|
+
supportGift: false,
|
|
3289
|
+
supportHistory: true
|
|
3290
|
+
},
|
|
3291
|
+
{
|
|
3292
|
+
chainId: 36888,
|
|
3293
|
+
chainIndex: 3688800,
|
|
3294
|
+
name: "ABCORE",
|
|
3295
|
+
chainName: "AB Core",
|
|
3296
|
+
rpcUrls: ["https://rpc1.core.ab.org"],
|
|
3297
|
+
blockExplorerUrl: "https://explorer.core.ab.org",
|
|
3298
|
+
platformType: "EVM",
|
|
3299
|
+
isTestnet: false,
|
|
3300
|
+
icon: "/assets/ab.svg",
|
|
3301
|
+
supportSwap: true,
|
|
3302
|
+
supportGift: false,
|
|
3303
|
+
supportHistory: true
|
|
3304
|
+
},
|
|
3305
|
+
{
|
|
3306
|
+
chainId: 6281971,
|
|
3307
|
+
chainIndex: 628197100,
|
|
3308
|
+
name: "DOGEOS_TESTNET",
|
|
3309
|
+
chainName: "DogeOS Testnet",
|
|
3274
3310
|
rpcUrls: [`${WALLET_DOMAIN}/rpc/v1/doge_test`],
|
|
3275
|
-
blockExplorerUrl: "https://
|
|
3311
|
+
blockExplorerUrl: "https://rpc.testnet.dogeos.com",
|
|
3276
3312
|
platformType: "EVM",
|
|
3277
3313
|
isTestnet: true,
|
|
3278
3314
|
icon: "/assets/dogeos.svg",
|
|
@@ -3894,7 +3930,7 @@ var BaseService = class {
|
|
|
3894
3930
|
}
|
|
3895
3931
|
const baseUrlConfig = CONFIG[tomoAppInfo.tomoStage];
|
|
3896
3932
|
const { tokenAPIs, transactionAPIs, networkAPIs } = tomoPublicApiService(baseUrlConfig, tomoAppInfo);
|
|
3897
|
-
this.accountInfo = accountInfo;
|
|
3933
|
+
this.accountInfo = accountInfo || null;
|
|
3898
3934
|
this.networks = new Networks(networkAPIs);
|
|
3899
3935
|
this.tokens = new Tokens(tokenAPIs);
|
|
3900
3936
|
this.transactions = new Transactions(transactionAPIs);
|
|
@@ -3904,8 +3940,718 @@ var BaseService = class {
|
|
|
3904
3940
|
this.approveParams = params;
|
|
3905
3941
|
}
|
|
3906
3942
|
};
|
|
3907
|
-
|
|
3908
|
-
|
|
3943
|
+
|
|
3944
|
+
// src/dogecoin/base.ts
|
|
3945
|
+
function fromHex(hex) {
|
|
3946
|
+
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
3947
|
+
const paddedHex = cleanHex.length % 2 === 0 ? cleanHex : "0" + cleanHex;
|
|
3948
|
+
const bytes = new Uint8Array(paddedHex.length / 2);
|
|
3949
|
+
for (let i = 0; i < paddedHex.length; i += 2) {
|
|
3950
|
+
bytes[i / 2] = parseInt(paddedHex.substr(i, 2), 16);
|
|
3951
|
+
}
|
|
3952
|
+
return bytes;
|
|
3953
|
+
}
|
|
3954
|
+
function toHex(data) {
|
|
3955
|
+
if (typeof data === "string") {
|
|
3956
|
+
return data.startsWith("0x") ? data.slice(2) : data;
|
|
3957
|
+
}
|
|
3958
|
+
const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
3959
|
+
return buffer.toString("hex");
|
|
3960
|
+
}
|
|
3961
|
+
function toBase64(data) {
|
|
3962
|
+
if (typeof data === "string") {
|
|
3963
|
+
const buffer2 = Buffer.from(data, "hex");
|
|
3964
|
+
return buffer2.toString("base64");
|
|
3965
|
+
}
|
|
3966
|
+
const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
3967
|
+
return buffer.toString("base64");
|
|
3968
|
+
}
|
|
3969
|
+
function fromBase64(base64) {
|
|
3970
|
+
const buffer = Buffer.from(base64, "base64");
|
|
3971
|
+
return new Uint8Array(buffer);
|
|
3972
|
+
}
|
|
3973
|
+
function toBase58(data) {
|
|
3974
|
+
throw new Error("toBase58 requires bs58 package. Install it: pnpm add bs58");
|
|
3975
|
+
}
|
|
3976
|
+
var BaseConfig = walletUtils.SupportedChainTypes[walletUtils.ChainTypes.DOGE];
|
|
3977
|
+
var BLOCK_CONFIRMATIONS = 1;
|
|
3978
|
+
var FEE_RATE_KB = 0.5;
|
|
3979
|
+
var DECIMALS = 1e8;
|
|
3980
|
+
var TRANSACTION_PAGE_SIZE = 10;
|
|
3981
|
+
var MYDOGE_BASE_URL = "https://api.mydoge.com";
|
|
3982
|
+
var RPC_URL = "https://api.bitcore.io/api/DOGE/mainnet";
|
|
3983
|
+
var RPC_TIMEOUT = 20 * 1e3;
|
|
3984
|
+
var TX_OVERHEAD = 10;
|
|
3985
|
+
var P2SH_INPUT_SIZE = 148;
|
|
3986
|
+
var TX_OUTPUT_SIZE = 34;
|
|
3987
|
+
var DEFAULT_OUTPUT_COUNT = 2;
|
|
3988
|
+
var TX_SIZE = 1 * P2SH_INPUT_SIZE + DEFAULT_OUTPUT_COUNT * TX_OUTPUT_SIZE + TX_OVERHEAD;
|
|
3989
|
+
var network = {
|
|
3990
|
+
messagePrefix: "Dogecoin Signed Message:\n",
|
|
3991
|
+
bech32: "dc",
|
|
3992
|
+
bip44: 3,
|
|
3993
|
+
bip32: {
|
|
3994
|
+
public: 49990397,
|
|
3995
|
+
private: 49988504
|
|
3996
|
+
},
|
|
3997
|
+
pubKeyHash: 30,
|
|
3998
|
+
scriptHash: 22,
|
|
3999
|
+
wif: 158
|
|
4000
|
+
};
|
|
4001
|
+
|
|
4002
|
+
// src/dogecoin/rpc.ts
|
|
4003
|
+
var rpc_exports = {};
|
|
4004
|
+
__export(rpc_exports, {
|
|
4005
|
+
estimateSmartFee: () => estimateSmartFee,
|
|
4006
|
+
getBalance: () => getBalance,
|
|
4007
|
+
getDogeFeeByBlock: () => getDogeFeeByBlock,
|
|
4008
|
+
getInscriptionsUtxo: () => getInscriptionsUtxo,
|
|
4009
|
+
getInscriptionsUtxos: () => getInscriptionsUtxos,
|
|
4010
|
+
getSpendableUtxos: () => getSpendableUtxos,
|
|
4011
|
+
getTransactions: () => getTransactions,
|
|
4012
|
+
getTxDetail: () => getTxDetail,
|
|
4013
|
+
getUnSpentUtxos: () => getUnSpentUtxos,
|
|
4014
|
+
mydoge: () => mydoge,
|
|
4015
|
+
onCreateTransaction: () => onCreateTransaction,
|
|
4016
|
+
sendDogeTx: () => sendDogeTx,
|
|
4017
|
+
sendTransaction: () => sendTransaction
|
|
4018
|
+
});
|
|
4019
|
+
var KOINU_PER_DOGE = new Bignumber.BigNumber(DECIMALS);
|
|
4020
|
+
function toSatoshi(bitcion) {
|
|
4021
|
+
try {
|
|
4022
|
+
const amount = new Bignumber.BigNumber(bitcion);
|
|
4023
|
+
if (amount.isNaN() || amount.isNegative()) {
|
|
4024
|
+
throw new Error("Invalid amount");
|
|
4025
|
+
}
|
|
4026
|
+
return amount.times(KOINU_PER_DOGE).integerValue(Bignumber.BigNumber.ROUND_DOWN).toNumber();
|
|
4027
|
+
} catch (error) {
|
|
4028
|
+
throw new Error(`toSatoshi failed: ${error.message}`);
|
|
4029
|
+
}
|
|
4030
|
+
}
|
|
4031
|
+
function toBitcoin(satoshis) {
|
|
4032
|
+
try {
|
|
4033
|
+
const amount = new Bignumber.BigNumber(satoshis);
|
|
4034
|
+
if (amount.isNaN() || amount.isNegative()) {
|
|
4035
|
+
throw new Error("Invalid Koinu amount");
|
|
4036
|
+
}
|
|
4037
|
+
return amount.dividedBy(KOINU_PER_DOGE).toNumber();
|
|
4038
|
+
} catch (error) {
|
|
4039
|
+
throw new Error(`toBitcoin failed: ${error.message}`);
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
function addUsedUtxos(newUsedUtxos) {
|
|
4043
|
+
const usedUtxos = walletUtils.cache.get("UsedUtxos") || {};
|
|
4044
|
+
for (const txid in newUsedUtxos) {
|
|
4045
|
+
usedUtxos[txid] = 1;
|
|
4046
|
+
}
|
|
4047
|
+
walletUtils.cache.set("UsedUtxos", usedUtxos, false);
|
|
4048
|
+
}
|
|
4049
|
+
function getUsedUtxos() {
|
|
4050
|
+
return walletUtils.cache.get("UsedUtxos") || {};
|
|
4051
|
+
}
|
|
4052
|
+
async function createPsbt({
|
|
4053
|
+
from,
|
|
4054
|
+
to,
|
|
4055
|
+
amount,
|
|
4056
|
+
fee,
|
|
4057
|
+
spendableUtxos
|
|
4058
|
+
}) {
|
|
4059
|
+
const utxos = spendableUtxos;
|
|
4060
|
+
if (!utxos || utxos.length === 0) {
|
|
4061
|
+
throw new Error("no spendable utxos");
|
|
4062
|
+
}
|
|
4063
|
+
const sendAmount = toSatoshi(amount);
|
|
4064
|
+
const sendCost = toSatoshi(fee);
|
|
4065
|
+
const totalNeeded = sendAmount + sendCost;
|
|
4066
|
+
const sortedUtxos = utxos.sort((a, b) => b.outputValue - a.outputValue);
|
|
4067
|
+
const selectedUtxos = [];
|
|
4068
|
+
let accumulatedAmount = 0;
|
|
4069
|
+
for (const utxo of sortedUtxos) {
|
|
4070
|
+
if (accumulatedAmount >= totalNeeded) break;
|
|
4071
|
+
selectedUtxos.push(utxo);
|
|
4072
|
+
accumulatedAmount += Number(utxo.outputValue);
|
|
4073
|
+
}
|
|
4074
|
+
if (accumulatedAmount < totalNeeded) {
|
|
4075
|
+
throw new Error("not enough funds to cover amount and fee");
|
|
4076
|
+
}
|
|
4077
|
+
const utxoDetailPromises = selectedUtxos.map(async (utxo) => {
|
|
4078
|
+
try {
|
|
4079
|
+
const utxoDetail = await getTxDetail(utxo.txid);
|
|
4080
|
+
return { utxo, utxoDetail };
|
|
4081
|
+
} catch (error) {
|
|
4082
|
+
return { utxo, utxoDetail: null };
|
|
4083
|
+
}
|
|
4084
|
+
});
|
|
4085
|
+
const utxoResults = await Promise.all(utxoDetailPromises);
|
|
4086
|
+
const inputs = [];
|
|
4087
|
+
const usingUtxos = {};
|
|
4088
|
+
let addedAmount = 0;
|
|
4089
|
+
for (const { utxo, utxoDetail } of utxoResults) {
|
|
4090
|
+
if (addedAmount >= totalNeeded) break;
|
|
4091
|
+
const { txid, vout, outputValue, address = from } = utxo;
|
|
4092
|
+
if (utxoDetail?.hex && !usingUtxos[txid]) {
|
|
4093
|
+
inputs.push({
|
|
4094
|
+
txId: txid,
|
|
4095
|
+
vOut: vout,
|
|
4096
|
+
amount: Number(outputValue),
|
|
4097
|
+
nonWitnessUtxo: utxoDetail.hex,
|
|
4098
|
+
address
|
|
4099
|
+
});
|
|
4100
|
+
usingUtxos[txid] = 1;
|
|
4101
|
+
addedAmount += Number(outputValue);
|
|
4102
|
+
}
|
|
4103
|
+
}
|
|
4104
|
+
if (addedAmount < totalNeeded) {
|
|
4105
|
+
throw new Error("not enough funds to cover amount and fee");
|
|
4106
|
+
}
|
|
4107
|
+
const outputs = [
|
|
4108
|
+
{
|
|
4109
|
+
address: to,
|
|
4110
|
+
amount: sendAmount
|
|
4111
|
+
}
|
|
4112
|
+
];
|
|
4113
|
+
const changeAmount = addedAmount - sendAmount - sendCost;
|
|
4114
|
+
if (changeAmount > 0) {
|
|
4115
|
+
outputs.push({
|
|
4116
|
+
address: from,
|
|
4117
|
+
amount: changeAmount
|
|
4118
|
+
});
|
|
4119
|
+
}
|
|
4120
|
+
const params = {
|
|
4121
|
+
address: from,
|
|
4122
|
+
inputs,
|
|
4123
|
+
outputs
|
|
4124
|
+
};
|
|
4125
|
+
const psbtBase64 = DogecoinUtils.buildPsbtToBase64(params);
|
|
4126
|
+
return { psbtBase64, usingUtxos };
|
|
4127
|
+
}
|
|
4128
|
+
function decodePsbt(psbt, type = "hex") {
|
|
4129
|
+
try {
|
|
4130
|
+
if (type === "base64") {
|
|
4131
|
+
const psbtHex = toHex(fromBase64(psbt));
|
|
4132
|
+
return bitcoinjsLib.Psbt.fromHex(psbtHex, {
|
|
4133
|
+
network
|
|
4134
|
+
});
|
|
4135
|
+
}
|
|
4136
|
+
return bitcoinjsLib.Psbt.fromHex(psbt, {
|
|
4137
|
+
network
|
|
4138
|
+
});
|
|
4139
|
+
} catch (error) {
|
|
4140
|
+
console.error("Failed to decode PSBT:", error);
|
|
4141
|
+
throw error;
|
|
4142
|
+
}
|
|
4143
|
+
}
|
|
4144
|
+
var TransactionParser = class {
|
|
4145
|
+
rawTx;
|
|
4146
|
+
constructor(rawTx) {
|
|
4147
|
+
this.rawTx = rawTx;
|
|
4148
|
+
}
|
|
4149
|
+
hexToText(hex) {
|
|
4150
|
+
let str = "";
|
|
4151
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
4152
|
+
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
|
4153
|
+
}
|
|
4154
|
+
return str;
|
|
4155
|
+
}
|
|
4156
|
+
extractOPReturnData() {
|
|
4157
|
+
const ordIndex = this.rawTx.indexOf("6f7264");
|
|
4158
|
+
if (ordIndex === -1) return null;
|
|
4159
|
+
const dataHex = this.rawTx.substring(ordIndex);
|
|
4160
|
+
const dataText = this.hexToText(dataHex);
|
|
4161
|
+
const jsonMatch = dataText.match(/\{.*?\}/);
|
|
4162
|
+
return jsonMatch ? JSON.parse(jsonMatch[0]) : null;
|
|
4163
|
+
}
|
|
4164
|
+
parseScript() {
|
|
4165
|
+
return {
|
|
4166
|
+
version: this.rawTx.substring(0, 8),
|
|
4167
|
+
inputCount: parseInt(this.rawTx.substring(8, 10)),
|
|
4168
|
+
inputs: this.parseInputs(),
|
|
4169
|
+
opReturnData: this.extractOPReturnData()
|
|
4170
|
+
};
|
|
4171
|
+
}
|
|
4172
|
+
parseInputs() {
|
|
4173
|
+
const inputs = [];
|
|
4174
|
+
const position = 10;
|
|
4175
|
+
const firstInput = {
|
|
4176
|
+
txid: this.rawTx.substring(position, position + 64),
|
|
4177
|
+
vout: this.rawTx.substring(position + 64, position + 72),
|
|
4178
|
+
scriptData: this.extractOPReturnData()
|
|
4179
|
+
};
|
|
4180
|
+
inputs.push(firstInput);
|
|
4181
|
+
return inputs;
|
|
4182
|
+
}
|
|
4183
|
+
};
|
|
4184
|
+
|
|
4185
|
+
// src/dogecoin/rpc.ts
|
|
4186
|
+
var mydoge = axios__default.default.create({
|
|
4187
|
+
baseURL: MYDOGE_BASE_URL
|
|
4188
|
+
});
|
|
4189
|
+
var api = axios__default.default.create({
|
|
4190
|
+
baseURL: RPC_URL,
|
|
4191
|
+
timeout: RPC_TIMEOUT
|
|
4192
|
+
});
|
|
4193
|
+
async function getBalance(address) {
|
|
4194
|
+
if (!address) {
|
|
4195
|
+
return {
|
|
4196
|
+
address: "",
|
|
4197
|
+
balance: 0
|
|
4198
|
+
};
|
|
4199
|
+
}
|
|
4200
|
+
const path = `/address/${address}?page=1&pageSize=10`;
|
|
4201
|
+
const api2 = `${MYDOGE_BASE_URL}/wallet/info?route=` + encodeURIComponent(path);
|
|
4202
|
+
const res = await mydoge.get(api2);
|
|
4203
|
+
return res.data || {};
|
|
4204
|
+
}
|
|
4205
|
+
async function getTxDetail(txId) {
|
|
4206
|
+
if (!txId) {
|
|
4207
|
+
return {};
|
|
4208
|
+
}
|
|
4209
|
+
const path = `/tx/${txId}`;
|
|
4210
|
+
const api2 = `${MYDOGE_BASE_URL}/wallet/info?route=` + encodeURIComponent(path);
|
|
4211
|
+
const res = await mydoge.get(api2);
|
|
4212
|
+
return res.data || {};
|
|
4213
|
+
}
|
|
4214
|
+
async function getUtxos(address, cursor, result, filter, tx = null) {
|
|
4215
|
+
const query = (await mydoge.get(`${MYDOGE_BASE_URL}/utxos/${address}?filter=${filter}${cursor ? `&cursor=${cursor}` : ""}`)).data;
|
|
4216
|
+
let { utxos } = query;
|
|
4217
|
+
if (tx) {
|
|
4218
|
+
utxos = utxos.filter((utxo) => utxo.txid === tx?.txid && utxo.vout === tx?.vout);
|
|
4219
|
+
}
|
|
4220
|
+
result.push(
|
|
4221
|
+
...utxos.map((i) => ({
|
|
4222
|
+
txid: i.txid,
|
|
4223
|
+
vout: i.vout,
|
|
4224
|
+
outputValue: i.satoshis,
|
|
4225
|
+
script: i.script_pubkey,
|
|
4226
|
+
...filter === "inscriptions" && { inscriptions: i.inscriptions }
|
|
4227
|
+
}))
|
|
4228
|
+
);
|
|
4229
|
+
if (result.length && tx) {
|
|
4230
|
+
return;
|
|
4231
|
+
}
|
|
4232
|
+
result = result.sort((a, b) => toBitcoin(b.outputValue) - toBitcoin(a.outputValue));
|
|
4233
|
+
if (query.next_cursor) {
|
|
4234
|
+
return getUtxos(address, query.next_cursor, result, filter, tx);
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
async function getInscriptionsUtxos(address) {
|
|
4238
|
+
const inscriptions = [];
|
|
4239
|
+
await getUtxos(address, 0, inscriptions, "inscriptions");
|
|
4240
|
+
return inscriptions;
|
|
4241
|
+
}
|
|
4242
|
+
async function getSpendableUtxos(address) {
|
|
4243
|
+
const utxos = [];
|
|
4244
|
+
await getUtxos(address, 0, utxos, "spendable");
|
|
4245
|
+
return utxos;
|
|
4246
|
+
}
|
|
4247
|
+
async function getUnSpentUtxos(address) {
|
|
4248
|
+
try {
|
|
4249
|
+
const result = await api.get(`/address/${address}/?unspent=true&limit=${0}`);
|
|
4250
|
+
const unSpentUtxo = result?.data;
|
|
4251
|
+
if (unSpentUtxo?.length) return unSpentUtxo.filter((utxo) => !utxo.spentTxid);
|
|
4252
|
+
return [];
|
|
4253
|
+
} catch (e) {
|
|
4254
|
+
return [];
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4257
|
+
async function getInscriptionsUtxo(address, tx) {
|
|
4258
|
+
const inscriptions = [];
|
|
4259
|
+
await getUtxos(address, 0, inscriptions, "inscriptions", tx);
|
|
4260
|
+
return inscriptions[0];
|
|
4261
|
+
}
|
|
4262
|
+
async function sendTransaction({ signed, senderAddress }) {
|
|
4263
|
+
const jsonrpcReq = {
|
|
4264
|
+
jsonrpc: "2.0",
|
|
4265
|
+
id: `${senderAddress}_send_${Date.now()}`,
|
|
4266
|
+
method: "sendrawtransaction",
|
|
4267
|
+
params: [signed]
|
|
4268
|
+
};
|
|
4269
|
+
const jsonrpcRes = (await mydoge.post("/wallet/rpc", jsonrpcReq)).data;
|
|
4270
|
+
return jsonrpcRes;
|
|
4271
|
+
}
|
|
4272
|
+
async function estimateSmartFee({ senderAddress }) {
|
|
4273
|
+
const smartfeeReq = {
|
|
4274
|
+
jsonrpc: "2.0",
|
|
4275
|
+
id: `${senderAddress}_estimatesmartfee_${Date.now()}`,
|
|
4276
|
+
method: "estimatesmartfee",
|
|
4277
|
+
params: [BLOCK_CONFIRMATIONS]
|
|
4278
|
+
// confirm within x blocks
|
|
4279
|
+
};
|
|
4280
|
+
const feeData = (await mydoge.post("/wallet/rpc", smartfeeReq)).data;
|
|
4281
|
+
const feeRate = feeData?.result?.feerate || FEE_RATE_KB;
|
|
4282
|
+
const feePerKB = toSatoshi(feeRate * 2);
|
|
4283
|
+
return { feePerKB };
|
|
4284
|
+
}
|
|
4285
|
+
async function onCreateTransaction({ data, sendResponse }) {
|
|
4286
|
+
const amountSatoshi = toSatoshi(data.dogeAmount);
|
|
4287
|
+
const amount = toBitcoin(amountSatoshi);
|
|
4288
|
+
try {
|
|
4289
|
+
const response = await mydoge.post("/v3/tx/prepare", {
|
|
4290
|
+
sender: data.senderAddress,
|
|
4291
|
+
recipient: data.recipientAddress,
|
|
4292
|
+
amount
|
|
4293
|
+
});
|
|
4294
|
+
const { rawTx, fee, amount: resultAmount } = response.data;
|
|
4295
|
+
let amountMismatch = false;
|
|
4296
|
+
if (resultAmount < amount - fee) {
|
|
4297
|
+
amountMismatch = true;
|
|
4298
|
+
}
|
|
4299
|
+
sendResponse?.({
|
|
4300
|
+
rawTx,
|
|
4301
|
+
fee,
|
|
4302
|
+
amount: resultAmount,
|
|
4303
|
+
amountMismatch
|
|
4304
|
+
});
|
|
4305
|
+
} catch (err) {
|
|
4306
|
+
sendResponse?.(false);
|
|
4307
|
+
}
|
|
4308
|
+
}
|
|
4309
|
+
async function getTransactions(address, config) {
|
|
4310
|
+
const { pageSize = 10, pageNumber = 1 } = config || {};
|
|
4311
|
+
const size = Math.min(pageSize, TRANSACTION_PAGE_SIZE);
|
|
4312
|
+
let txIds = [];
|
|
4313
|
+
let totalPages;
|
|
4314
|
+
let page;
|
|
4315
|
+
try {
|
|
4316
|
+
const response = (await mydoge.get("/wallet/info", {
|
|
4317
|
+
params: {
|
|
4318
|
+
route: `/address/${address}?page=${pageNumber}&pageSize=${size}`
|
|
4319
|
+
}
|
|
4320
|
+
})).data;
|
|
4321
|
+
txIds = response.txids;
|
|
4322
|
+
totalPages = response.totalPages;
|
|
4323
|
+
page = response.page;
|
|
4324
|
+
const transactions = await Promise.all(
|
|
4325
|
+
txIds?.map(async (txId) => {
|
|
4326
|
+
const detail = await getTxDetail(txId);
|
|
4327
|
+
const tx = new TransactionParser(detail.hex);
|
|
4328
|
+
const parsedData = tx.parseScript();
|
|
4329
|
+
return {
|
|
4330
|
+
...detail,
|
|
4331
|
+
tick: parsedData?.opReturnData?.tick,
|
|
4332
|
+
tickAmount: parsedData?.opReturnData?.amt
|
|
4333
|
+
};
|
|
4334
|
+
}) || []
|
|
4335
|
+
);
|
|
4336
|
+
return { transactions, txIds, totalPages, page };
|
|
4337
|
+
} catch (err) {
|
|
4338
|
+
throw new Error("getTransactions failed");
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
var getDogeFeeByBlock = async (address, n = 22) => {
|
|
4342
|
+
const res = await api.get(`/fee/${n}`);
|
|
4343
|
+
return (res.data?.feerate || 0.01) * TX_SIZE;
|
|
4344
|
+
};
|
|
4345
|
+
var sendDogeTx = async (rawTx) => {
|
|
4346
|
+
try {
|
|
4347
|
+
const res = await api.post("/tx/send", { rawTx });
|
|
4348
|
+
return res.data;
|
|
4349
|
+
} catch (e) {
|
|
4350
|
+
if (typeof e?.response?.data === "string") return Promise.reject(e?.response?.data);
|
|
4351
|
+
else return Promise.reject(e.message);
|
|
4352
|
+
}
|
|
4353
|
+
};
|
|
4354
|
+
|
|
4355
|
+
// src/dogecoin/utils-doge.ts
|
|
4356
|
+
var DogecoinAddress = class {
|
|
4357
|
+
static network = network;
|
|
4358
|
+
static generatePath(addressIndex) {
|
|
4359
|
+
return `m/44'/3'/0'/0/${addressIndex || 0}`;
|
|
4360
|
+
}
|
|
4361
|
+
static verifyAddress(address) {
|
|
4362
|
+
try {
|
|
4363
|
+
const decoded = bitcoinjsLib.address.fromBase58Check(address);
|
|
4364
|
+
return decoded.version === network.pubKeyHash || decoded.version === network.scriptHash;
|
|
4365
|
+
} catch (error) {
|
|
4366
|
+
return false;
|
|
4367
|
+
}
|
|
4368
|
+
}
|
|
4369
|
+
};
|
|
4370
|
+
var DogecoinUtils = class {
|
|
4371
|
+
/**
|
|
4372
|
+
* Build the PSBT from the transaction
|
|
4373
|
+
* @param tx utxoTx
|
|
4374
|
+
* @param _maximumFeeRate number (optional, currently unused)
|
|
4375
|
+
* @returns base64
|
|
4376
|
+
*/
|
|
4377
|
+
static buildPsbtToBase64(tx, _maximumFeeRate) {
|
|
4378
|
+
const psbt = new bitcoinjsLib.Psbt({ network });
|
|
4379
|
+
for (const input of tx.inputs) {
|
|
4380
|
+
const inputOptions = {
|
|
4381
|
+
hash: input.txId,
|
|
4382
|
+
index: input.vOut
|
|
4383
|
+
};
|
|
4384
|
+
if (input.nonWitnessUtxo) {
|
|
4385
|
+
inputOptions.nonWitnessUtxo = Buffer.from(input.nonWitnessUtxo, "hex");
|
|
4386
|
+
}
|
|
4387
|
+
psbt.addInput(inputOptions);
|
|
4388
|
+
}
|
|
4389
|
+
for (const output of tx.outputs) {
|
|
4390
|
+
psbt.addOutput({
|
|
4391
|
+
value: BigInt(output?.amount || 0),
|
|
4392
|
+
address: output.address
|
|
4393
|
+
});
|
|
4394
|
+
}
|
|
4395
|
+
const psbtHex = psbt.toHex();
|
|
4396
|
+
return toBase64(fromHex(psbtHex));
|
|
4397
|
+
}
|
|
4398
|
+
/**
|
|
4399
|
+
* Extract the transaction from the signed PSBT
|
|
4400
|
+
* @param signedPsbt base64
|
|
4401
|
+
* @param _maximumFeeRate number (optional, currently unused)
|
|
4402
|
+
* @returns transaction hex
|
|
4403
|
+
*/
|
|
4404
|
+
static extractPsbtTransaction(signedPsbt, _maximumFeeRate) {
|
|
4405
|
+
const signedPsbtHex = toHex(fromBase64(signedPsbt));
|
|
4406
|
+
const psbt = bitcoinjsLib.Psbt.fromHex(signedPsbtHex, {
|
|
4407
|
+
network
|
|
4408
|
+
});
|
|
4409
|
+
const maximumFeeRate = _maximumFeeRate || 1e5;
|
|
4410
|
+
psbt.setMaximumFeeRate(maximumFeeRate);
|
|
4411
|
+
psbt.finalizeAllInputs();
|
|
4412
|
+
const transaction = psbt.extractTransaction();
|
|
4413
|
+
return transaction.toHex();
|
|
4414
|
+
}
|
|
4415
|
+
/**
|
|
4416
|
+
* Convert raw transaction hex to PSBT base64
|
|
4417
|
+
* This method converts an unsigned raw transaction to PSBT format.
|
|
4418
|
+
* Note: The rawTx should be an unsigned transaction, and the nonWitnessUtxo
|
|
4419
|
+
* for each input will need to be fetched separately from the blockchain.
|
|
4420
|
+
* @param rawTx hex string of the raw transaction
|
|
4421
|
+
* @returns base64 string of the PSBT
|
|
4422
|
+
*/
|
|
4423
|
+
static async rawTxToPsbtBase64(rawTx) {
|
|
4424
|
+
try {
|
|
4425
|
+
const cleanHex = rawTx.startsWith("0x") ? rawTx.slice(2) : rawTx;
|
|
4426
|
+
const transaction = bitcoinjsLib.Transaction.fromHex(cleanHex);
|
|
4427
|
+
const psbt = new bitcoinjsLib.Psbt({ network });
|
|
4428
|
+
for (let i = 0; i < transaction.ins.length; i++) {
|
|
4429
|
+
const input = transaction.ins[i];
|
|
4430
|
+
const hash = Buffer.from(input.hash).toString("hex");
|
|
4431
|
+
const index = input.index;
|
|
4432
|
+
const inputOptions = {
|
|
4433
|
+
hash,
|
|
4434
|
+
index
|
|
4435
|
+
};
|
|
4436
|
+
try {
|
|
4437
|
+
const prevTxDetail = await getTxDetail(hash);
|
|
4438
|
+
if (prevTxDetail?.hex) {
|
|
4439
|
+
inputOptions.nonWitnessUtxo = Buffer.from(prevTxDetail.hex, "hex");
|
|
4440
|
+
} else {
|
|
4441
|
+
throw new Error(`Previous transaction ${hash} has no hex data`);
|
|
4442
|
+
}
|
|
4443
|
+
} catch (error) {
|
|
4444
|
+
throw new Error(
|
|
4445
|
+
`Failed to fetch previous transaction ${hash} for input #${i}. This is required for PSBT creation. Error: ${error instanceof Error ? error.message : String(error)}`
|
|
4446
|
+
);
|
|
4447
|
+
}
|
|
4448
|
+
psbt.addInput(inputOptions);
|
|
4449
|
+
}
|
|
4450
|
+
for (const output of transaction.outs) {
|
|
4451
|
+
try {
|
|
4452
|
+
const address = bitcoinjsLib.address.fromOutputScript(output.script, network);
|
|
4453
|
+
psbt.addOutput({
|
|
4454
|
+
address,
|
|
4455
|
+
value: BigInt(output?.value || 0)
|
|
4456
|
+
});
|
|
4457
|
+
} catch (error) {
|
|
4458
|
+
psbt.addOutput({
|
|
4459
|
+
script: output.script,
|
|
4460
|
+
value: BigInt(output?.value || 0)
|
|
4461
|
+
});
|
|
4462
|
+
}
|
|
4463
|
+
}
|
|
4464
|
+
const psbtHex = psbt.toHex();
|
|
4465
|
+
return toBase64(fromHex(psbtHex));
|
|
4466
|
+
} catch (error) {
|
|
4467
|
+
console.warn("rawTxToPsbtBase64 failed:", error);
|
|
4468
|
+
throw new Error(
|
|
4469
|
+
`Failed to convert raw transaction to PSBT: ${error instanceof Error ? error.message : String(error)}`
|
|
4470
|
+
);
|
|
4471
|
+
}
|
|
4472
|
+
}
|
|
4473
|
+
};
|
|
4474
|
+
var DogecoinService = class _DogecoinService extends BaseService {
|
|
4475
|
+
static instance;
|
|
4476
|
+
chainType;
|
|
4477
|
+
rpcService;
|
|
4478
|
+
constructor(chainType, accountInfo, tomoAppInfo) {
|
|
4479
|
+
super(tomoAppInfo, accountInfo);
|
|
4480
|
+
this.chainType = chainType;
|
|
4481
|
+
this.rpcService = rpc_exports;
|
|
4482
|
+
}
|
|
4483
|
+
//singleton
|
|
4484
|
+
static getInstance(chainType, accountInfo, tomoAppInfo) {
|
|
4485
|
+
if (!_DogecoinService.instance) {
|
|
4486
|
+
_DogecoinService.instance = new _DogecoinService(chainType, accountInfo, tomoAppInfo);
|
|
4487
|
+
}
|
|
4488
|
+
return _DogecoinService.instance;
|
|
4489
|
+
}
|
|
4490
|
+
async requestAccounts() {
|
|
4491
|
+
const addresses = await this.accountInfo.getCurrent();
|
|
4492
|
+
const { publicKey, address } = addresses?.[0] || {};
|
|
4493
|
+
if (!address) {
|
|
4494
|
+
throw new Error("address is not set");
|
|
4495
|
+
}
|
|
4496
|
+
const { balance = 0 } = await getBalance(address);
|
|
4497
|
+
return {
|
|
4498
|
+
address,
|
|
4499
|
+
balance,
|
|
4500
|
+
approved: true,
|
|
4501
|
+
publicKey
|
|
4502
|
+
};
|
|
4503
|
+
}
|
|
4504
|
+
async getAccounts() {
|
|
4505
|
+
const accounts = await this.accountInfo.getCurrent();
|
|
4506
|
+
return accounts.map((account) => account.address);
|
|
4507
|
+
}
|
|
4508
|
+
async getConnectionStatus() {
|
|
4509
|
+
const addresses = await this.accountInfo.getCurrent();
|
|
4510
|
+
const { address } = addresses?.[0] || {};
|
|
4511
|
+
if (!address) {
|
|
4512
|
+
throw new Error("address is not set");
|
|
4513
|
+
}
|
|
4514
|
+
return {
|
|
4515
|
+
connected: true,
|
|
4516
|
+
address,
|
|
4517
|
+
selectedWalletAddress: address
|
|
4518
|
+
};
|
|
4519
|
+
}
|
|
4520
|
+
async getBalance() {
|
|
4521
|
+
const addresses = await this.accountInfo.getCurrent();
|
|
4522
|
+
const { address } = addresses?.[0] || {};
|
|
4523
|
+
if (!address) {
|
|
4524
|
+
throw new Error("address is not set");
|
|
4525
|
+
}
|
|
4526
|
+
const { balance = 0 } = await getBalance(address);
|
|
4527
|
+
return {
|
|
4528
|
+
address,
|
|
4529
|
+
balance
|
|
4530
|
+
};
|
|
4531
|
+
}
|
|
4532
|
+
async signMessage({ message, type }) {
|
|
4533
|
+
if (type) {
|
|
4534
|
+
throw new Error("bip322simple not support.");
|
|
4535
|
+
}
|
|
4536
|
+
const signature = await this.accountInfo.signMessage(message);
|
|
4537
|
+
return {
|
|
4538
|
+
signedMessage: signature
|
|
4539
|
+
};
|
|
4540
|
+
}
|
|
4541
|
+
async requestSignedMessage({
|
|
4542
|
+
message,
|
|
4543
|
+
type
|
|
4544
|
+
}) {
|
|
4545
|
+
return await this.signMessage({
|
|
4546
|
+
message,
|
|
4547
|
+
type
|
|
4548
|
+
});
|
|
4549
|
+
}
|
|
4550
|
+
async _queryGasInfo(txData) {
|
|
4551
|
+
const { chainId, amount = 0, decimals = 8 } = txData;
|
|
4552
|
+
const gasLimitParam = {
|
|
4553
|
+
from: txData.from,
|
|
4554
|
+
to: txData.to,
|
|
4555
|
+
value: viem.toHex(viem.parseUnits(amount.toString(), decimals))
|
|
4556
|
+
};
|
|
4557
|
+
const queryGasParams = {
|
|
4558
|
+
chainIndex: Number(chainId || BaseConfig.chainId),
|
|
4559
|
+
callData: "0x",
|
|
4560
|
+
gasLimitParam,
|
|
4561
|
+
addressList: [txData.from]
|
|
4562
|
+
};
|
|
4563
|
+
const {
|
|
4564
|
+
data: gasInfo,
|
|
4565
|
+
success,
|
|
4566
|
+
message
|
|
4567
|
+
} = await this.transactions.queryGasInfo({
|
|
4568
|
+
chainType: this.chainType,
|
|
4569
|
+
params: queryGasParams
|
|
4570
|
+
});
|
|
4571
|
+
if (!success) {
|
|
4572
|
+
console.error("queryGasInfo doge", success, txData, queryGasParams, gasInfo);
|
|
4573
|
+
const { gasFee } = BaseConfig;
|
|
4574
|
+
return {
|
|
4575
|
+
success: true,
|
|
4576
|
+
gasFee: gasFee.toString()
|
|
4577
|
+
};
|
|
4578
|
+
}
|
|
4579
|
+
const { baseFee = 1, gasLimit = 1 } = gasInfo;
|
|
4580
|
+
const calcFee = (feeLevel) => {
|
|
4581
|
+
const gasFee = new Bignumber.BigNumber(gasInfo[feeLevel] || baseFee).times(gasLimit);
|
|
4582
|
+
return toBitcoin(gasFee.toNumber());
|
|
4583
|
+
};
|
|
4584
|
+
const fees = {
|
|
4585
|
+
low: calcFee("priorityFeeLow"),
|
|
4586
|
+
medium: calcFee("priorityFeeMedium"),
|
|
4587
|
+
high: calcFee("priorityFeeHigh")
|
|
4588
|
+
};
|
|
4589
|
+
return {
|
|
4590
|
+
success: true,
|
|
4591
|
+
fees,
|
|
4592
|
+
gasFee: fees.high
|
|
4593
|
+
};
|
|
4594
|
+
}
|
|
4595
|
+
async requestPsbt({
|
|
4596
|
+
rawTx,
|
|
4597
|
+
signOnly
|
|
4598
|
+
}) {
|
|
4599
|
+
const psbtBase64 = await DogecoinUtils.rawTxToPsbtBase64(rawTx);
|
|
4600
|
+
const signedPsbt = await this.accountInfo.signTransaction(JSON.stringify({ psbtBase64 }));
|
|
4601
|
+
if (!signedPsbt) {
|
|
4602
|
+
return null;
|
|
4603
|
+
}
|
|
4604
|
+
const signedRawTx = DogecoinUtils.extractPsbtTransaction(signedPsbt, 1e5);
|
|
4605
|
+
if (signOnly) {
|
|
4606
|
+
return {
|
|
4607
|
+
signedRawTx
|
|
4608
|
+
};
|
|
4609
|
+
}
|
|
4610
|
+
const { txid = "" } = await sendDogeTx(signedRawTx);
|
|
4611
|
+
return {
|
|
4612
|
+
txId: txid,
|
|
4613
|
+
signedRawTx
|
|
4614
|
+
};
|
|
4615
|
+
}
|
|
4616
|
+
async requestTransaction(txData) {
|
|
4617
|
+
const spendableUtxos = txData?.spendableUtxos;
|
|
4618
|
+
if (txData.amountMismatch) {
|
|
4619
|
+
throw new Error("balance_insufficient");
|
|
4620
|
+
}
|
|
4621
|
+
if (!spendableUtxos || spendableUtxos?.length === 0) {
|
|
4622
|
+
txData.spendableUtxos = await getSpendableUtxos(txData.from);
|
|
4623
|
+
}
|
|
4624
|
+
const { psbtBase64, usingUtxos } = await createPsbt(txData);
|
|
4625
|
+
const signedPsbt = await this.accountInfo.signTransaction(JSON.stringify({ psbtBase64 }));
|
|
4626
|
+
const signedTx = DogecoinUtils.extractPsbtTransaction(signedPsbt, 1e5);
|
|
4627
|
+
if (signedTx === "") {
|
|
4628
|
+
throw new Error("Error: sign transaction err.");
|
|
4629
|
+
}
|
|
4630
|
+
try {
|
|
4631
|
+
const { txid } = await sendDogeTx(signedTx);
|
|
4632
|
+
addUsedUtxos(usingUtxos);
|
|
4633
|
+
return { txId: txid };
|
|
4634
|
+
} catch (err) {
|
|
4635
|
+
throw new Error("Error: send transaction err." + JSON.stringify(err));
|
|
4636
|
+
}
|
|
4637
|
+
}
|
|
4638
|
+
async getTransactionStatus({ txId }) {
|
|
4639
|
+
const transaction = await getTxDetail(txId);
|
|
4640
|
+
if (!transaction?.txid) {
|
|
4641
|
+
return null;
|
|
4642
|
+
}
|
|
4643
|
+
return {
|
|
4644
|
+
txId: transaction.txid,
|
|
4645
|
+
confirmations: transaction.confirmations,
|
|
4646
|
+
status: transaction.confirmations > 0 ? "confirmed" : "pending",
|
|
4647
|
+
dogeAmount: transaction.vout[0]?.value,
|
|
4648
|
+
blockTime: transaction.blockTime,
|
|
4649
|
+
address: transaction.vout[0]?.addresses[0]
|
|
4650
|
+
};
|
|
4651
|
+
}
|
|
4652
|
+
};
|
|
4653
|
+
function getRPCClient(network2) {
|
|
4654
|
+
const { chainId, name, rpcUrls, nativeCurrencyDecimals, nativeCurrencyName, nativeCurrencySymbol } = network2;
|
|
3909
4655
|
const myCustomChain = {
|
|
3910
4656
|
id: Number(chainId) || chainId,
|
|
3911
4657
|
name,
|
|
@@ -3960,8 +4706,8 @@ var TxTypes = /* @__PURE__ */ ((TxTypes2) => {
|
|
|
3960
4706
|
})(TxTypes || {});
|
|
3961
4707
|
|
|
3962
4708
|
// src/evm/utils.ts
|
|
3963
|
-
var isEvmChain = (
|
|
3964
|
-
return
|
|
4709
|
+
var isEvmChain = (network2) => {
|
|
4710
|
+
return network2 && network2?.platformType === "EVM";
|
|
3965
4711
|
};
|
|
3966
4712
|
var getAllTypeChainIds = ({ chainId, chainType }) => {
|
|
3967
4713
|
if (viem.isHex(chainId)) {
|
|
@@ -4053,7 +4799,7 @@ var EvmService = class _EvmService extends BaseService {
|
|
|
4053
4799
|
}
|
|
4054
4800
|
async personal_sign([message, address]) {
|
|
4055
4801
|
const accounts = await this.accountInfo.getCurrent();
|
|
4056
|
-
if (accounts[0].address
|
|
4802
|
+
if (!viem.isAddressEqual(accounts[0].address, address)) {
|
|
4057
4803
|
throw new Error("address is not the current account");
|
|
4058
4804
|
}
|
|
4059
4805
|
const signature = await this.accountInfo.signMessage(message);
|
|
@@ -4061,7 +4807,7 @@ var EvmService = class _EvmService extends BaseService {
|
|
|
4061
4807
|
}
|
|
4062
4808
|
async eth_signTypedData_v4([address, typedData]) {
|
|
4063
4809
|
const accounts = await this.accountInfo.getCurrent();
|
|
4064
|
-
if (accounts[0].address
|
|
4810
|
+
if (!viem.isAddressEqual(accounts[0].address, address)) {
|
|
4065
4811
|
throw new Error("address is not the current account");
|
|
4066
4812
|
}
|
|
4067
4813
|
const signature = await this.accountInfo.signTypedData(typedData);
|
|
@@ -4069,7 +4815,7 @@ var EvmService = class _EvmService extends BaseService {
|
|
|
4069
4815
|
}
|
|
4070
4816
|
async eth_getBalance([address, type]) {
|
|
4071
4817
|
const accounts = await this.accountInfo.getCurrent();
|
|
4072
|
-
if (accounts[0].address
|
|
4818
|
+
if (!viem.isAddressEqual(accounts[0].address, address)) {
|
|
4073
4819
|
throw new Error("address is not the current account");
|
|
4074
4820
|
}
|
|
4075
4821
|
if (type !== "latest") {
|
|
@@ -4113,8 +4859,8 @@ var EvmService = class _EvmService extends BaseService {
|
|
|
4113
4859
|
});
|
|
4114
4860
|
if (!success) {
|
|
4115
4861
|
console.error("queryGasInfo evm", txData, queryGasParams, message, gasInfo);
|
|
4116
|
-
const
|
|
4117
|
-
const { gasFee } =
|
|
4862
|
+
const BaseConfig3 = walletUtils.SupportedChainTypes[walletUtils.ChainTypes.EVM];
|
|
4863
|
+
const { gasFee } = BaseConfig3;
|
|
4118
4864
|
return {
|
|
4119
4865
|
success: true,
|
|
4120
4866
|
gasFee: gasFee.toString()
|
|
@@ -4146,51 +4892,6 @@ var EvmService = class _EvmService extends BaseService {
|
|
|
4146
4892
|
}
|
|
4147
4893
|
};
|
|
4148
4894
|
}
|
|
4149
|
-
async eth_estimateGas(txs) {
|
|
4150
|
-
const { from, to, value = "0x1" } = txs[0] || {};
|
|
4151
|
-
const accounts = await this.accountInfo.getCurrent();
|
|
4152
|
-
if (accounts[0].address !== from) {
|
|
4153
|
-
throw new Error("address is not the current account");
|
|
4154
|
-
}
|
|
4155
|
-
if (!to) {
|
|
4156
|
-
throw new Error("to is not set");
|
|
4157
|
-
}
|
|
4158
|
-
const chainId = txs[0]?.chainId || await this.eth_chainId();
|
|
4159
|
-
const queryGasParams = {
|
|
4160
|
-
chainIndex: Number(chainId),
|
|
4161
|
-
callData: "0x",
|
|
4162
|
-
gasLimitParam: {
|
|
4163
|
-
from,
|
|
4164
|
-
to,
|
|
4165
|
-
value
|
|
4166
|
-
},
|
|
4167
|
-
addressList: [from]
|
|
4168
|
-
};
|
|
4169
|
-
const chainType = this.chainType;
|
|
4170
|
-
const {
|
|
4171
|
-
data: gasInfo,
|
|
4172
|
-
success,
|
|
4173
|
-
message
|
|
4174
|
-
} = await this.transactions.queryGasInfo({
|
|
4175
|
-
chainType,
|
|
4176
|
-
params: queryGasParams
|
|
4177
|
-
});
|
|
4178
|
-
if (!success) {
|
|
4179
|
-
console.error("queryGasInfo evm", txs, message, gasInfo);
|
|
4180
|
-
const { gasFee } = walletUtils.SupportedChainTypes[chainType];
|
|
4181
|
-
return gasFee.toString();
|
|
4182
|
-
}
|
|
4183
|
-
const res = getAllTypeChainIds({ chainId, chainType });
|
|
4184
|
-
const { nativeCurrencyDecimals } = await this.networks.getNetworkByChainId(res.chainId);
|
|
4185
|
-
const { baseFee = 1, gasLimit = 0 } = gasInfo;
|
|
4186
|
-
const baseFeeBN = new Bignumber.BigNumber(baseFee);
|
|
4187
|
-
const calcFee = (feeLevel) => {
|
|
4188
|
-
const fee = baseFeeBN.plus(gasInfo[feeLevel] || 0);
|
|
4189
|
-
const gasFee = fee.times(gasLimit);
|
|
4190
|
-
return viem.toHex(BigInt(gasFee.toNumber()), nativeCurrencyDecimals);
|
|
4191
|
-
};
|
|
4192
|
-
return calcFee("priorityFeeMedium");
|
|
4193
|
-
}
|
|
4194
4895
|
async createPublicClient({ chainId, rpcUrl }) {
|
|
4195
4896
|
if (rpcUrl) {
|
|
4196
4897
|
return viem.createPublicClient({
|
|
@@ -4212,6 +4913,26 @@ var EvmService = class _EvmService extends BaseService {
|
|
|
4212
4913
|
transport: viem.http(rpcUrl)
|
|
4213
4914
|
});
|
|
4214
4915
|
}
|
|
4916
|
+
async eth_estimateGas(txs) {
|
|
4917
|
+
const { from, to, value = "0x1", chainId } = txs[0] || {};
|
|
4918
|
+
const accounts = await this.accountInfo.getCurrent();
|
|
4919
|
+
if (accounts[0].address !== from) {
|
|
4920
|
+
throw new Error("address is not the current account");
|
|
4921
|
+
}
|
|
4922
|
+
if (!to) {
|
|
4923
|
+
throw new Error("to is not set");
|
|
4924
|
+
}
|
|
4925
|
+
try {
|
|
4926
|
+
const rpcClient = await this.createPublicClient({ chainId: chainId?.toString() });
|
|
4927
|
+
const gas = await rpcClient.estimateGas({ account: from, to, value: viem.hexToBigInt(value) });
|
|
4928
|
+
return gas;
|
|
4929
|
+
} catch (error) {
|
|
4930
|
+
console.warn("Failed to estimate gas:", error);
|
|
4931
|
+
const BaseConfig3 = walletUtils.SupportedChainTypes[walletUtils.ChainTypes.EVM];
|
|
4932
|
+
const { gasFee } = BaseConfig3;
|
|
4933
|
+
return viem.numberToHex(viem.parseUnits(gasFee.toString(), 18));
|
|
4934
|
+
}
|
|
4935
|
+
}
|
|
4215
4936
|
// Get nonce for current account
|
|
4216
4937
|
async eth_getTransactionCount([address, type]) {
|
|
4217
4938
|
const accounts = await this.accountInfo.getCurrent();
|
|
@@ -4240,30 +4961,35 @@ var EvmService = class _EvmService extends BaseService {
|
|
|
4240
4961
|
nonce: "number",
|
|
4241
4962
|
maxPriorityFeePerGas: "bigint",
|
|
4242
4963
|
maxFeePerGas: "bigint",
|
|
4243
|
-
|
|
4964
|
+
gasPrice: "bigint",
|
|
4244
4965
|
gas: "bigint"
|
|
4245
4966
|
};
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
txData = { ...txData, gas, gasLimit: gas };
|
|
4967
|
+
const txData = txParams?.[0];
|
|
4968
|
+
txData.gas = txData?.gas || txData?.gasLimit;
|
|
4249
4969
|
txData.data = txData.data || "0x";
|
|
4970
|
+
txData.value = txData.value || "0x";
|
|
4971
|
+
txData.nonce = txData.nonce || "0x0";
|
|
4972
|
+
if (!txData?.gas || !txData?.to || !txData?.chainId) {
|
|
4973
|
+
throw new Error("gas or to or chainId is not set");
|
|
4974
|
+
}
|
|
4250
4975
|
const accounts = await this.accountInfo.getCurrent();
|
|
4251
4976
|
const address = accounts[0].address;
|
|
4252
|
-
if (txData?.from && txData?.from
|
|
4977
|
+
if (txData?.from && !viem.isAddressEqual(txData?.from, address)) {
|
|
4253
4978
|
console.error("eth_signTransaction error data: from is not the current account", txData);
|
|
4254
4979
|
throw new Error(`eth_signTransaction error data: from is not the current account`);
|
|
4255
4980
|
}
|
|
4256
4981
|
delete txData?.from;
|
|
4982
|
+
delete txData?.gasLimit;
|
|
4257
4983
|
const preparedTx = {
|
|
4258
|
-
|
|
4259
|
-
gas: txData?.gasLimit,
|
|
4260
|
-
account: address
|
|
4984
|
+
gas: txData?.gas
|
|
4261
4985
|
};
|
|
4262
4986
|
for (const key in preparedTxPropsType) {
|
|
4263
|
-
if (
|
|
4264
|
-
|
|
4987
|
+
if (txData?.[key] && viem.isHex(txData?.[key])) {
|
|
4988
|
+
preparedTx[key] = preparedTxPropsType[key] === "number" ? viem.fromHex(txData[key], "number") : txData[key];
|
|
4265
4989
|
}
|
|
4266
|
-
|
|
4990
|
+
}
|
|
4991
|
+
if (txData?.type !== "legacy") {
|
|
4992
|
+
delete preparedTx.gasPrice;
|
|
4267
4993
|
}
|
|
4268
4994
|
try {
|
|
4269
4995
|
const serializedTransaction = await this.accountInfo.signTransaction(
|
|
@@ -4309,7 +5035,7 @@ var EvmService = class _EvmService extends BaseService {
|
|
|
4309
5035
|
}
|
|
4310
5036
|
}
|
|
4311
5037
|
};
|
|
4312
|
-
var
|
|
5038
|
+
var BaseConfig2 = walletUtils.SupportedChainTypes[walletUtils.ChainTypes.SOL];
|
|
4313
5039
|
var TOKEN_METADATA_PROGRAM_ID = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s";
|
|
4314
5040
|
var MSG_PREFIX = "\xFFsolana offchain";
|
|
4315
5041
|
|
|
@@ -4384,13 +5110,6 @@ async function createTokenLegacyTransaction2({
|
|
|
4384
5110
|
throw error;
|
|
4385
5111
|
}
|
|
4386
5112
|
}
|
|
4387
|
-
|
|
4388
|
-
// src/dogecoin/base.ts
|
|
4389
|
-
function toBase58(data) {
|
|
4390
|
-
throw new Error("toBase58 requires bs58 package. Install it: pnpm add bs58");
|
|
4391
|
-
}
|
|
4392
|
-
|
|
4393
|
-
// src/solana/service.ts
|
|
4394
5113
|
var SolanaService = class _SolanaService extends BaseService {
|
|
4395
5114
|
static instance;
|
|
4396
5115
|
chainType;
|
|
@@ -4422,11 +5141,11 @@ var SolanaService = class _SolanaService extends BaseService {
|
|
|
4422
5141
|
return await this.accountInfo.getCurrent();
|
|
4423
5142
|
}
|
|
4424
5143
|
async getAccount() {
|
|
4425
|
-
const { currentAddress, publicKey } = await this.accountInfo.
|
|
5144
|
+
const { address: currentAddress, publicKey } = await this.accountInfo.getCurrent();
|
|
4426
5145
|
return { publicKey: publicKey || currentAddress, address: currentAddress };
|
|
4427
5146
|
}
|
|
4428
5147
|
async signMessage(params) {
|
|
4429
|
-
const { currentAddress, publicKey } = await this.accountInfo.
|
|
5148
|
+
const { address: currentAddress, publicKey } = await this.accountInfo.getCurrent();
|
|
4430
5149
|
const { message } = params;
|
|
4431
5150
|
const signature = await this.accountInfo.signMessage(message);
|
|
4432
5151
|
return {
|
|
@@ -4436,7 +5155,7 @@ var SolanaService = class _SolanaService extends BaseService {
|
|
|
4436
5155
|
};
|
|
4437
5156
|
}
|
|
4438
5157
|
async signIn(params) {
|
|
4439
|
-
const { currentAddress, publicKey } = await this.accountInfo.
|
|
5158
|
+
const { address: currentAddress, publicKey } = await this.accountInfo.getCurrent();
|
|
4440
5159
|
const { signature = "" } = await this.signMessage(params);
|
|
4441
5160
|
return {
|
|
4442
5161
|
address: currentAddress,
|
|
@@ -4483,7 +5202,7 @@ var SolanaService = class _SolanaService extends BaseService {
|
|
|
4483
5202
|
});
|
|
4484
5203
|
if (!success) {
|
|
4485
5204
|
console.error("queryGasInfo solana", txData, message, gasInfo);
|
|
4486
|
-
const { gasFee } =
|
|
5205
|
+
const { gasFee } = BaseConfig2;
|
|
4487
5206
|
return {
|
|
4488
5207
|
success: true,
|
|
4489
5208
|
gasFee: gasFee.toString()
|
|
@@ -4646,8 +5365,8 @@ var TomoWallet = class _TomoWallet extends BaseService {
|
|
|
4646
5365
|
}
|
|
4647
5366
|
async getChainInfo(chainType, chainId) {
|
|
4648
5367
|
this.networks.setChainType(chainType);
|
|
4649
|
-
const
|
|
4650
|
-
return
|
|
5368
|
+
const network2 = await this.networks.getNetworkByChainId(chainId);
|
|
5369
|
+
return network2;
|
|
4651
5370
|
}
|
|
4652
5371
|
//evm chains
|
|
4653
5372
|
async isChainSupported(chainType, chainId) {
|
|
@@ -4714,13 +5433,24 @@ var TomoWallet = class _TomoWallet extends BaseService {
|
|
|
4714
5433
|
// src/index.ts
|
|
4715
5434
|
var ChainTypeServices = {
|
|
4716
5435
|
[walletUtils.ChainTypes.EVM]: EvmService,
|
|
4717
|
-
[walletUtils.ChainTypes.SOL]: SolanaService
|
|
4718
|
-
|
|
5436
|
+
[walletUtils.ChainTypes.SOL]: SolanaService,
|
|
5437
|
+
[walletUtils.ChainTypes.DOGE]: DogecoinService
|
|
4719
5438
|
};
|
|
4720
5439
|
|
|
4721
5440
|
exports.AccountType = AccountType;
|
|
4722
5441
|
exports.ChainTypeServices = ChainTypeServices;
|
|
5442
|
+
exports.DogecoinAPI = rpc_exports;
|
|
5443
|
+
exports.DogecoinAddress = DogecoinAddress;
|
|
5444
|
+
exports.DogecoinService = DogecoinService;
|
|
5445
|
+
exports.DogecoinUtils = DogecoinUtils;
|
|
4723
5446
|
exports.EvmService = EvmService;
|
|
4724
5447
|
exports.SolanaService = SolanaService;
|
|
4725
5448
|
exports.TomoWallet = TomoWallet;
|
|
5449
|
+
exports.TransactionParser = TransactionParser;
|
|
4726
5450
|
exports.TxTypes = TxTypes;
|
|
5451
|
+
exports.addUsedUtxos = addUsedUtxos;
|
|
5452
|
+
exports.createPsbt = createPsbt;
|
|
5453
|
+
exports.decodePsbt = decodePsbt;
|
|
5454
|
+
exports.getUsedUtxos = getUsedUtxos;
|
|
5455
|
+
exports.toBitcoin = toBitcoin;
|
|
5456
|
+
exports.toSatoshi = toSatoshi;
|