@tomo-inc/chains-service 0.0.2
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 +3 -0
- package/README.md +15 -0
- package/package.json +38 -0
- package/project.json +59 -0
- package/src/api/__tests__/config.ts +21 -0
- package/src/api/__tests__/token.test.ts +120 -0
- package/src/api/__tests__/transaction.test.ts +86 -0
- package/src/api/__tests__/user.test.ts +105 -0
- package/src/api/__tests__/wallet.test.ts +73 -0
- package/src/api/base.ts +52 -0
- package/src/api/index.ts +24 -0
- package/src/api/network-data.ts +572 -0
- package/src/api/network.ts +81 -0
- package/src/api/token.ts +182 -0
- package/src/api/transaction.ts +59 -0
- package/src/api/types/common.ts +35 -0
- package/src/api/types/index.ts +13 -0
- package/src/api/types/type.ts +283 -0
- package/src/api/user.ts +83 -0
- package/src/api/utils/index.ts +34 -0
- package/src/api/utils/signature.ts +60 -0
- package/src/api/wallet.ts +57 -0
- package/src/base/network.ts +55 -0
- package/src/base/service.ts +33 -0
- package/src/base/token.ts +43 -0
- package/src/base/transaction.ts +58 -0
- package/src/config.ts +21 -0
- package/src/dogecoin/base.ts +39 -0
- package/src/dogecoin/config.ts +43 -0
- package/src/dogecoin/rpc.ts +449 -0
- package/src/dogecoin/service.ts +451 -0
- package/src/dogecoin/type.ts +29 -0
- package/src/dogecoin/utils-doge.ts +105 -0
- package/src/dogecoin/utils.ts +601 -0
- package/src/evm/rpc.ts +68 -0
- package/src/evm/service.ts +403 -0
- package/src/evm/utils.ts +92 -0
- package/src/index.ts +28 -0
- package/src/solana/config.ts +5 -0
- package/src/solana/service.ts +312 -0
- package/src/solana/types.ts +91 -0
- package/src/solana/utils.ts +635 -0
- package/src/types/account.ts +58 -0
- package/src/types/dapp.ts +7 -0
- package/src/types/gas.ts +53 -0
- package/src/types/index.ts +81 -0
- package/src/types/network.ts +66 -0
- package/src/types/tx.ts +181 -0
- package/src/types/wallet.ts +49 -0
- package/src/wallet.ts +96 -0
- package/tsconfig.json +14 -0
- package/tsup.config.ts +18 -0
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
|
|
3
|
+
import { TRANSACTION_PAGE_SIZE, BLOCK_CONFIRMATIONS, FEE_RATE_KB } from "./config";
|
|
4
|
+
import { RPC_URL, MYDOGE_BASE_URL, RPC_TIMEOUT, TX_SIZE } from "./config";
|
|
5
|
+
import { TransactionParser, toSatoshi, toBitcoin } from "./utils";
|
|
6
|
+
import { cache } from "@tomo-inc/wallet-utils";
|
|
7
|
+
import { DogeSpendableUtxos, DunesTransactionParams } from "./type";
|
|
8
|
+
|
|
9
|
+
export const mydoge = axios.create({
|
|
10
|
+
baseURL: MYDOGE_BASE_URL,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const api = axios.create({
|
|
14
|
+
baseURL: RPC_URL,
|
|
15
|
+
timeout: RPC_TIMEOUT,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export async function getBalance(address?: string) {
|
|
19
|
+
if (!address) {
|
|
20
|
+
return {
|
|
21
|
+
address: "",
|
|
22
|
+
balance: 0,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const path = `/address/${address}?page=1&pageSize=10`;
|
|
26
|
+
const api = `${MYDOGE_BASE_URL}/wallet/info?route=` + encodeURIComponent(path);
|
|
27
|
+
|
|
28
|
+
const res: any = await mydoge.get(api);
|
|
29
|
+
return res.data || {};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type Drc20Transaction = {
|
|
33
|
+
blockHash: string;
|
|
34
|
+
blockHeight: number;
|
|
35
|
+
blockTime: number;
|
|
36
|
+
confirmations: number;
|
|
37
|
+
fees: string;
|
|
38
|
+
hex: string;
|
|
39
|
+
size: number;
|
|
40
|
+
txid: string;
|
|
41
|
+
value: string;
|
|
42
|
+
valueIn: string;
|
|
43
|
+
version: number;
|
|
44
|
+
vin: {
|
|
45
|
+
addresses: string[];
|
|
46
|
+
hex: string;
|
|
47
|
+
isAddress: boolean;
|
|
48
|
+
n: number;
|
|
49
|
+
sequence: number;
|
|
50
|
+
txid: string;
|
|
51
|
+
value: string;
|
|
52
|
+
}[];
|
|
53
|
+
vout: {
|
|
54
|
+
addresses: string[];
|
|
55
|
+
value: string;
|
|
56
|
+
n: number;
|
|
57
|
+
hex: string;
|
|
58
|
+
isAddress: boolean;
|
|
59
|
+
}[];
|
|
60
|
+
tick?: string;
|
|
61
|
+
tickAmount?: number;
|
|
62
|
+
drc20Detail?: Drc20Detail;
|
|
63
|
+
};
|
|
64
|
+
export async function getTxDetail(txId: string): Promise<Drc20Transaction> {
|
|
65
|
+
if (!txId) {
|
|
66
|
+
return {} as Drc20Transaction;
|
|
67
|
+
}
|
|
68
|
+
const path = `/tx/${txId}`;
|
|
69
|
+
const api = `${MYDOGE_BASE_URL}/wallet/info?route=` + encodeURIComponent(path);
|
|
70
|
+
|
|
71
|
+
const res = await mydoge.get(api);
|
|
72
|
+
|
|
73
|
+
return res.data || {};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export async function getAccountDrc20List(address: string, config?: any) {
|
|
77
|
+
const api = `/drc20/${address}`;
|
|
78
|
+
const res: any = await mydoge.get(api);
|
|
79
|
+
return res.data || {};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const Drc20DetailsCacheKey = "Drc20Details";
|
|
83
|
+
const Drc20DetailsCache = cache.get(Drc20DetailsCacheKey) || {};
|
|
84
|
+
function isCacheAvailable(time: number) {
|
|
85
|
+
const cacheTime = 20 * 60 * 1000; // 30 minutes
|
|
86
|
+
return Date.now() - time <= cacheTime;
|
|
87
|
+
}
|
|
88
|
+
export type Drc20Detail = {
|
|
89
|
+
changePercent: string;
|
|
90
|
+
currentSupply: number;
|
|
91
|
+
floorPrice: number;
|
|
92
|
+
holders: number;
|
|
93
|
+
lastPrice: number;
|
|
94
|
+
maxSupply: number;
|
|
95
|
+
pic: string;
|
|
96
|
+
sales: number;
|
|
97
|
+
tick: string;
|
|
98
|
+
twentyFourHourVolume: string;
|
|
99
|
+
volume: string;
|
|
100
|
+
};
|
|
101
|
+
export async function getDrc20Detail(ticker: string): Promise<Drc20Detail> {
|
|
102
|
+
const drc20Detail = Drc20DetailsCache?.[ticker];
|
|
103
|
+
if (drc20Detail?.cacheTime && isCacheAvailable(drc20Detail?.cacheTime)) {
|
|
104
|
+
return drc20Detail;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const api = `/drc20/data/${ticker}`;
|
|
108
|
+
const res: any = await mydoge.get(api);
|
|
109
|
+
const detail = res.data || {};
|
|
110
|
+
if (detail.pic) {
|
|
111
|
+
Drc20DetailsCache[ticker] = { ...detail, cacheTime: Date.now() };
|
|
112
|
+
cache.set(Drc20DetailsCacheKey, Drc20DetailsCache, false);
|
|
113
|
+
}
|
|
114
|
+
return detail;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function getDRC20Inscriptions(address: string, ticker: string) {
|
|
118
|
+
const api = `${MYDOGE_BASE_URL}/inscriptions/${address}?filter=drc20&ticker=${encodeURIComponent(ticker)}`;
|
|
119
|
+
const query = (await mydoge.get(api)).data;
|
|
120
|
+
return query;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export async function getDRC20Balance(address: string, ticker: string) {
|
|
124
|
+
const api = `${MYDOGE_BASE_URL}/drc20/${address}?ticker=${ticker}`;
|
|
125
|
+
const res = (await mydoge.get(api))?.data || {};
|
|
126
|
+
return res;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function getUtxos(
|
|
130
|
+
address: string,
|
|
131
|
+
cursor: number,
|
|
132
|
+
result: any,
|
|
133
|
+
filter: string,
|
|
134
|
+
tx: { txid: string; vout: number } | null = null,
|
|
135
|
+
): Promise<DogeSpendableUtxos[] | undefined> {
|
|
136
|
+
const query = (
|
|
137
|
+
await mydoge.get(`${MYDOGE_BASE_URL}/utxos/${address}?filter=${filter}${cursor ? `&cursor=${cursor}` : ""}`)
|
|
138
|
+
).data;
|
|
139
|
+
|
|
140
|
+
let { utxos } = query;
|
|
141
|
+
|
|
142
|
+
if (tx) {
|
|
143
|
+
utxos = utxos.filter((utxo: any) => utxo.txid === tx?.txid && utxo.vout === tx?.vout);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
result.push(
|
|
147
|
+
...utxos.map((i: any) => ({
|
|
148
|
+
txid: i.txid,
|
|
149
|
+
vout: i.vout,
|
|
150
|
+
outputValue: i.satoshis,
|
|
151
|
+
script: i.script_pubkey,
|
|
152
|
+
...(filter === "inscriptions" && { inscriptions: i.inscriptions }),
|
|
153
|
+
})),
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
if (result.length && tx) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
result = result.sort((a: any, b: any) => toBitcoin(b.outputValue) - toBitcoin(a.outputValue));
|
|
161
|
+
|
|
162
|
+
if (query.next_cursor) {
|
|
163
|
+
return getUtxos(address, query.next_cursor, result, filter, tx);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export async function getInscriptionsUtxos(address: string) {
|
|
168
|
+
const inscriptions: any[] = [];
|
|
169
|
+
await getUtxos(address, 0, inscriptions, "inscriptions");
|
|
170
|
+
|
|
171
|
+
return inscriptions;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export async function getSpendableUtxos(address: string) {
|
|
175
|
+
const utxos: any[] = [];
|
|
176
|
+
await getUtxos(address, 0, utxos, "spendable");
|
|
177
|
+
|
|
178
|
+
return utxos;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export async function getUnSpentUtxos(address: string) {
|
|
182
|
+
try {
|
|
183
|
+
const result = await api.get(`/address/${address}/?unspent=true&limit=${0}`);
|
|
184
|
+
const unSpentUtxo = result?.data;
|
|
185
|
+
if (unSpentUtxo?.length) return unSpentUtxo.filter((utxo: any) => !utxo.spentTxid);
|
|
186
|
+
return [];
|
|
187
|
+
} catch (e) {
|
|
188
|
+
return [];
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export async function getInscriptionsUtxo(address: string, tx: any) {
|
|
193
|
+
const inscriptions: any[] = [];
|
|
194
|
+
await getUtxos(address, 0, inscriptions, "inscriptions", tx);
|
|
195
|
+
|
|
196
|
+
return inscriptions[0];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export async function sendTransaction({ signed, senderAddress }: any) {
|
|
200
|
+
// const signed = signRawTx(
|
|
201
|
+
// data.rawTx,
|
|
202
|
+
// decryptedWallet.children[selectedAddressIndex],
|
|
203
|
+
// );
|
|
204
|
+
|
|
205
|
+
const jsonrpcReq = {
|
|
206
|
+
jsonrpc: "2.0",
|
|
207
|
+
id: `${senderAddress}_send_${Date.now()}`,
|
|
208
|
+
method: "sendrawtransaction",
|
|
209
|
+
params: [signed],
|
|
210
|
+
};
|
|
211
|
+
const jsonrpcRes = (await mydoge.post("/wallet/rpc", jsonrpcReq)).data;
|
|
212
|
+
return jsonrpcRes;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
//nft
|
|
216
|
+
export async function getNFTs(address?: string): Promise<{ list: any[]; total: number }> {
|
|
217
|
+
if (!address) {
|
|
218
|
+
throw new Error("address is required");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const res: any = await mydoge.get(`/inscriptions/${address}`);
|
|
222
|
+
const { list = [], total = 0 } = res?.data || {};
|
|
223
|
+
return { list, total };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export async function createNFTTransaction(params: {
|
|
227
|
+
senderAddress: string;
|
|
228
|
+
recipientAddress: string;
|
|
229
|
+
location: string;
|
|
230
|
+
inscriptionId: string;
|
|
231
|
+
}) {
|
|
232
|
+
const { senderAddress, recipientAddress, location, inscriptionId } = params;
|
|
233
|
+
try {
|
|
234
|
+
const res: any = await mydoge.post("/tx/prepare/inscription", {
|
|
235
|
+
sender: senderAddress,
|
|
236
|
+
recipient: recipientAddress,
|
|
237
|
+
location: location,
|
|
238
|
+
inscriptionId: inscriptionId,
|
|
239
|
+
});
|
|
240
|
+
const { rawTx, fee, amount } = res?.data || {};
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
rawTx,
|
|
244
|
+
fee,
|
|
245
|
+
amount,
|
|
246
|
+
};
|
|
247
|
+
} catch (err) {
|
|
248
|
+
console.error("createNFTTransaction", err);
|
|
249
|
+
return {};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
//dunes
|
|
254
|
+
export async function getDunesBalance(address: string, ticker?: string) {
|
|
255
|
+
const api = `/dunes/${address}${ticker ? `?ticker=${ticker}` : ""}`;
|
|
256
|
+
const res = (await mydoge.get(api))?.data || {};
|
|
257
|
+
return res;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const DuneDetailsCacheKey = "DuneDetails";
|
|
261
|
+
const DuneDetailsCache = cache.get(DuneDetailsCacheKey) || {};
|
|
262
|
+
export async function getDuneDetail(ticker: string): Promise<Drc20Detail> {
|
|
263
|
+
const duneDetail = DuneDetailsCache?.[ticker];
|
|
264
|
+
if (duneDetail?.cacheTime && isCacheAvailable(duneDetail?.cacheTime)) {
|
|
265
|
+
return duneDetail;
|
|
266
|
+
}
|
|
267
|
+
try {
|
|
268
|
+
const api = `/dunes/data/${ticker}`;
|
|
269
|
+
const res: any = await mydoge.get(api);
|
|
270
|
+
const detail = res.data || {};
|
|
271
|
+
if (detail.pic) {
|
|
272
|
+
DuneDetailsCache[ticker] = { ...detail, cacheTime: Date.now() };
|
|
273
|
+
cache.set(DuneDetailsCacheKey, DuneDetailsCache, false);
|
|
274
|
+
}
|
|
275
|
+
return detail;
|
|
276
|
+
} catch (err) {
|
|
277
|
+
throw new Error("dune detail not found");
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export async function createDunesTransaction(params: DunesTransactionParams) {
|
|
282
|
+
try {
|
|
283
|
+
const { senderAddress = "", recipientAddress = "", amount = 0, ticker = "" } = params;
|
|
284
|
+
const { balances = [] } = await getDunesBalance(senderAddress, ticker);
|
|
285
|
+
const { duneId } = balances[0] || {};
|
|
286
|
+
if (!duneId) {
|
|
287
|
+
throw new Error("duneId not found");
|
|
288
|
+
}
|
|
289
|
+
const response = await mydoge.post("/tx/prepare/dune", {
|
|
290
|
+
sender: senderAddress,
|
|
291
|
+
recipient: recipientAddress,
|
|
292
|
+
amount,
|
|
293
|
+
duneId,
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
const { rawTx, fee, inputs } = response.data;
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
rawTx,
|
|
300
|
+
fee,
|
|
301
|
+
inputs, // usingUtxos
|
|
302
|
+
};
|
|
303
|
+
} catch (err) {
|
|
304
|
+
console.error("createDunesTransaction", err);
|
|
305
|
+
return {};
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export async function estimateSmartFee({ senderAddress }: { senderAddress: string }) {
|
|
310
|
+
const smartfeeReq = {
|
|
311
|
+
jsonrpc: "2.0",
|
|
312
|
+
id: `${senderAddress}_estimatesmartfee_${Date.now()}`,
|
|
313
|
+
method: "estimatesmartfee",
|
|
314
|
+
params: [BLOCK_CONFIRMATIONS], // confirm within x blocks
|
|
315
|
+
};
|
|
316
|
+
const feeData = (await mydoge.post("/wallet/rpc", smartfeeReq)).data;
|
|
317
|
+
const feeRate = feeData?.result?.feerate || FEE_RATE_KB;
|
|
318
|
+
const feePerKB = toSatoshi(feeRate * 2);
|
|
319
|
+
|
|
320
|
+
return { feePerKB };
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Build a raw transaction and determine fee
|
|
324
|
+
export async function onCreateTransaction({ data, sendResponse }: { data: any; sendResponse: any }) {
|
|
325
|
+
const amountSatoshi = toSatoshi(data.dogeAmount);
|
|
326
|
+
const amount = toBitcoin(amountSatoshi);
|
|
327
|
+
|
|
328
|
+
try {
|
|
329
|
+
const response = await mydoge.post("/v3/tx/prepare", {
|
|
330
|
+
sender: data.senderAddress,
|
|
331
|
+
recipient: data.recipientAddress,
|
|
332
|
+
amount,
|
|
333
|
+
});
|
|
334
|
+
const { rawTx, fee, amount: resultAmount } = response.data;
|
|
335
|
+
let amountMismatch = false;
|
|
336
|
+
|
|
337
|
+
if (resultAmount < amount - fee) {
|
|
338
|
+
amountMismatch = true;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
sendResponse?.({
|
|
342
|
+
rawTx,
|
|
343
|
+
fee,
|
|
344
|
+
amount: resultAmount,
|
|
345
|
+
amountMismatch,
|
|
346
|
+
});
|
|
347
|
+
} catch (err) {
|
|
348
|
+
sendResponse?.(false);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export type Drc20TransactionResponse = {
|
|
353
|
+
transactions: Drc20Transaction[];
|
|
354
|
+
txIds: string[];
|
|
355
|
+
totalPages: number;
|
|
356
|
+
page: number;
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
export async function getTransactions(
|
|
360
|
+
address: string,
|
|
361
|
+
config?: {
|
|
362
|
+
pageSize: number;
|
|
363
|
+
pageNumber: number;
|
|
364
|
+
},
|
|
365
|
+
): Promise<Drc20TransactionResponse> {
|
|
366
|
+
const { pageSize = 10, pageNumber = 1 } = config || {};
|
|
367
|
+
const size = Math.min(pageSize, TRANSACTION_PAGE_SIZE);
|
|
368
|
+
// Get txids
|
|
369
|
+
let txIds = [];
|
|
370
|
+
let totalPages;
|
|
371
|
+
let page;
|
|
372
|
+
|
|
373
|
+
try {
|
|
374
|
+
const response = (
|
|
375
|
+
await mydoge.get("/wallet/info", {
|
|
376
|
+
params: {
|
|
377
|
+
route: `/address/${address}?page=${pageNumber}&pageSize=${size}`,
|
|
378
|
+
},
|
|
379
|
+
})
|
|
380
|
+
).data;
|
|
381
|
+
|
|
382
|
+
txIds = response.txids;
|
|
383
|
+
totalPages = response.totalPages;
|
|
384
|
+
page = response.page;
|
|
385
|
+
|
|
386
|
+
const res = await Promise.all(
|
|
387
|
+
txIds?.map(async (txId: string) => {
|
|
388
|
+
const detail = await getTxDetail(txId);
|
|
389
|
+
const tx = new TransactionParser(detail.hex);
|
|
390
|
+
const parsedData: any = tx.parseScript();
|
|
391
|
+
return {
|
|
392
|
+
...detail,
|
|
393
|
+
tick: parsedData?.opReturnData?.tick,
|
|
394
|
+
tickAmount: parsedData?.opReturnData?.amt,
|
|
395
|
+
};
|
|
396
|
+
}) || [],
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
const filterTickList = [...new Set(res.map((item) => item.tick).filter((i) => i))];
|
|
400
|
+
const tickList = [];
|
|
401
|
+
for (const item of filterTickList) {
|
|
402
|
+
try {
|
|
403
|
+
const detail = await getDrc20Detail(item);
|
|
404
|
+
tickList.push(detail);
|
|
405
|
+
} catch (err) {
|
|
406
|
+
console.error(`Failed to fetch detail for ${item}`, err);
|
|
407
|
+
tickList.push({ tick: item });
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
// const tickList = await throttledMap(
|
|
411
|
+
// filterTickList,
|
|
412
|
+
// async (item) => {
|
|
413
|
+
// try {
|
|
414
|
+
// return await getDrc20Detail(item);
|
|
415
|
+
// } catch (err) {
|
|
416
|
+
// console.error(`Failed to fetch detail for ${item}`, err);
|
|
417
|
+
// return { tick: item };
|
|
418
|
+
// }
|
|
419
|
+
// },
|
|
420
|
+
// 1,
|
|
421
|
+
// );
|
|
422
|
+
const tickMap = tickList.reduce((acc, cur) => {
|
|
423
|
+
acc[cur.tick] = cur;
|
|
424
|
+
return acc;
|
|
425
|
+
}, {} as any);
|
|
426
|
+
res.forEach((item) => {
|
|
427
|
+
item.drc20Detail = tickMap[item.tick];
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
return { transactions: res || [], txIds, totalPages, page };
|
|
431
|
+
} catch (err) {
|
|
432
|
+
throw new Error("getTransactions failed");
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export const getDogeFeeByBlock = async (address?: string, n = 22) => {
|
|
437
|
+
const res = await api.get(`/fee/${n}`);
|
|
438
|
+
return (res.data?.feerate || 0.01) * TX_SIZE;
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
export const sendDogeTx = async (rawTx: string) => {
|
|
442
|
+
try {
|
|
443
|
+
const res = await api.post("/tx/send", { rawTx });
|
|
444
|
+
return res.data;
|
|
445
|
+
} catch (e: any) {
|
|
446
|
+
if (typeof e?.response?.data === "string") return Promise.reject(e?.response?.data);
|
|
447
|
+
else return Promise.reject(e.message);
|
|
448
|
+
}
|
|
449
|
+
};
|