ton-watcher
Advanced tools
Comparing version
@@ -14,2 +14,3 @@ export * from './modules/txs/tonTxWatcher'; | ||
import { checkTonAuth } from './utils/checkTonAuth'; | ||
import { TransferQueue } from './modules/txs/TransferQueu'; | ||
declare const _default: { | ||
@@ -29,3 +30,4 @@ parse_tx: (tx: import("@ton/ton").Transaction, is_testnet?: boolean) => any; | ||
Address: typeof Address; | ||
TransferQueue: typeof TransferQueue; | ||
}; | ||
export default _default; |
@@ -32,2 +32,3 @@ "use strict"; | ||
const checkTonAuth_1 = require("./utils/checkTonAuth"); | ||
const TransferQueu_1 = require("./modules/txs/TransferQueu"); | ||
exports.default = { | ||
@@ -43,3 +44,4 @@ parse_tx: Transaction_1.parse_tx, | ||
Address: ton_1.Address, | ||
TransferQueue: TransferQueu_1.TransferQueue | ||
}; | ||
//# sourceMappingURL=index.js.map |
@@ -9,2 +9,3 @@ import { STATUS } from "../../modules/txs/sendTx"; | ||
req_id: number; | ||
priority: number; | ||
}; | ||
@@ -28,2 +29,3 @@ resSendJetton: { | ||
req_id: number; | ||
priority: number; | ||
}; | ||
@@ -88,4 +90,5 @@ resSendTon: { | ||
}>; | ||
rps: number; | ||
}; | ||
export declare function runWatcher(init: InitData): Promise<unknown>; | ||
export {}; |
@@ -15,2 +15,3 @@ "use strict"; | ||
const CoreV4_1 = require("../../modules/wallet/CoreV4"); | ||
const TransferQueu_1 = require("../../modules/txs/TransferQueu"); | ||
async function runWatcher(init) { | ||
@@ -20,2 +21,3 @@ if (!init) { | ||
} | ||
init.rps = init.rps || 2; | ||
try { | ||
@@ -26,3 +28,3 @@ const isTestnet = init.network !== 'mainnet'; | ||
const address = wallet.address; | ||
axios_request_throttle_1.default.use(axios_1.default, { requestsPerSecond: isTestnet ? 2 : 5 }); | ||
axios_request_throttle_1.default.use(axios_1.default, { requestsPerSecond: init.rps }); | ||
// const endpoint = isTestnet ? 'https://testnet.toncenter.com/api/v2/jsonRPC' : await getHttpEndpoint({ network: init.network }); | ||
@@ -37,2 +39,5 @@ const endpoint = await (0, ton_access_1.getHttpV4Endpoint)({ network: init.network }); | ||
}); | ||
const txs = new TransferQueu_1.TransferQueue(core, (msg) => { | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)({ data: { level: 'debug', data: msg }, event: 'logger' })); | ||
}); | ||
const client4 = new ton_1.TonClient4({ | ||
@@ -51,3 +56,3 @@ endpoint: endpoint4, | ||
process.send && process.send(`{ "event": "address", "data": { "address" : "${address.toString()}" }}`); | ||
process.on('message', (data) => executeCommand(core, data)); | ||
process.on('message', (data) => executeCommand(core, txs, data)); | ||
} | ||
@@ -61,3 +66,3 @@ catch (e) { | ||
} | ||
function executeCommand(ton, data) { | ||
function executeCommand(ton, txs, data) { | ||
try { | ||
@@ -71,5 +76,5 @@ const event = JSON.parse(data); | ||
case 'reqSendJetton': | ||
return sendJetton(event, ton); | ||
return sendJetton(event, txs); | ||
case 'reqSendTon': | ||
return sendTon(event, ton); | ||
return sendTon(event, txs); | ||
} | ||
@@ -82,37 +87,10 @@ } | ||
async function sendTon(event, ton) { | ||
const { amount, destination, message, req_id } = event.data; | ||
const { amount, destination, message, req_id, priority = 1 } = event.data; | ||
try { | ||
if (!ton.isValidAddress(destination)) { | ||
const event = { | ||
data: { error: 'Recipient Address is invalid', req_id }, | ||
event: "resSendTon" | ||
}; | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)(event)); | ||
return; | ||
} | ||
const amount_bigint = parseToBigInt(Number(amount) * 10 ** 9); | ||
if (amount_bigint == null) { | ||
const event = { | ||
data: { error: `Amount is invalid ${Number(amount) * 10 ** 9}`, req_id }, | ||
event: "resSendTon" | ||
}; | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)(event)); | ||
return; | ||
} | ||
const transfer = await ton.transferTonMessage(destination, amount_bigint, message); | ||
try { | ||
const res = await ton.sendTx(transfer.message); | ||
const event = { | ||
data: { req_id, hash: null, lt: null, msgHash: res.messageHash, status: 'ok', reason: null, seqno: transfer.seqno }, | ||
event: "resSendTon" | ||
}; | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)(event)); | ||
} | ||
catch (e) { | ||
const event = { | ||
data: { req_id, hash: null, lt: null, msgHash: transfer.messageHash, status: 'ok', reason: null, seqno: transfer.seqno }, | ||
event: "resSendTon" | ||
}; | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)(event)); | ||
} | ||
const res = await ton.transfer(priority, destination, amount, 'TON', message); | ||
const event = { | ||
data: { req_id, hash: res.hash, lt: res.lt, msgHash: res.msgHash, status: 'ok', reason: null, seqno: res.seqno }, | ||
event: "resSendTon" | ||
}; | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)(event)); | ||
} | ||
@@ -128,47 +106,10 @@ catch (e) { | ||
async function sendJetton(event, ton) { | ||
const { amount, destination, message, req_id, name } = event.data; | ||
const { amount, destination, message, req_id, name, priority = 1 } = event.data; | ||
try { | ||
if (!ton.isValidAddress(destination)) { | ||
const event = { | ||
data: { error: 'Recipient Address is invalid', req_id }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)(event)); | ||
return; | ||
} | ||
const jettons = await ton.getJettonsInfo(); | ||
const jetton_settings = jettons[name]; | ||
if (!jetton_settings) { | ||
const event = { | ||
data: { error: 'Jetton not found', req_id }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)(event)); | ||
return; | ||
} | ||
const amount_bigint = parseToBigInt(Number(amount) * 10 ** jetton_settings.decimals); | ||
if (amount_bigint == null) { | ||
const event = { | ||
data: { error: `Amount is invalid ${Number(amount) * 10 ** jetton_settings.decimals}`, req_id }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)(event)); | ||
return; | ||
} | ||
const transfer = await ton.transferJettonMessage(destination, jetton_settings.jettonMasterAddress.toString(), amount_bigint, message); | ||
try { | ||
const res = await ton.sendTx(transfer.message); | ||
const event = { | ||
data: { req_id, hash: null, lt: null, msgHash: res.messageHash, status: 'ok', reason: null, seqno: transfer.seqno }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)(event)); | ||
} | ||
catch (e) { | ||
const event = { | ||
data: { req_id, hash: null, lt: null, msgHash: transfer.messageHash, status: 'ok', reason: null, seqno: transfer.seqno }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)(event)); | ||
} | ||
const res = await ton.transfer(priority, destination, amount, name, message); | ||
const event = { | ||
data: { req_id, hash: null, lt: null, msgHash: res.msgHash, status: 'ok', reason: null, seqno: res.seqno }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)(event)); | ||
} | ||
@@ -245,10 +186,2 @@ catch (e) { | ||
} | ||
function parseToBigInt(value) { | ||
try { | ||
return BigInt(value); | ||
} | ||
catch (e) { | ||
return null; | ||
} | ||
} | ||
//# sourceMappingURL=runProcess.js.map |
@@ -7,3 +7,4 @@ export type Func<T> = () => Promise<T>; | ||
add<T>(func: Func<T>): Promise<T>; | ||
getNext(): null | (() => Promise<void>); | ||
isBusy(): boolean; | ||
getNext(): (null | (() => Promise<void>)); | ||
private start; | ||
@@ -13,9 +14,10 @@ } | ||
private tmr; | ||
private requests; | ||
private request_time; | ||
private limit_per_sec; | ||
private queues; | ||
private in_progress; | ||
constructor(prority_number?: number, limit_per_sec?: number); | ||
size(): number[]; | ||
size(): number; | ||
run(): Promise<void>; | ||
add<T>(cb: Func<T>, priority: number): Promise<T>; | ||
} |
@@ -22,4 +22,7 @@ "use strict"; | ||
} | ||
isBusy() { | ||
return !!this.executed_promise; | ||
} | ||
getNext() { | ||
if (this.executed_promise) { | ||
if (this.isBusy()) { | ||
return null; | ||
@@ -52,13 +55,15 @@ } | ||
tmr; | ||
requests = []; | ||
request_time = 0; | ||
limit_per_sec; | ||
queues; | ||
in_progress = false; | ||
constructor(prority_number = 4, limit_per_sec = 10) { | ||
this.limit_per_sec = limit_per_sec; | ||
this.queues = Array | ||
.from(new Uint16Array(prority_number)) | ||
.from(new Uint8Array(prority_number)) | ||
.map(() => new Queue()); | ||
} | ||
size() { | ||
return this.queues.map(q => q.size()); | ||
return this.queues.map(q => q.size()) | ||
.reduce((acc, count) => acc + count, 0); | ||
} | ||
@@ -68,15 +73,23 @@ async run() { | ||
const now = Date.now(); | ||
this.requests = this.requests.filter(time => (now - time) < 1000); | ||
if (this.requests.length >= (this.limit_per_sec - 1)) { | ||
const is_inprogress = this.in_progress; | ||
if (is_inprogress || (this.request_time + 1000 / this.limit_per_sec) > now) { | ||
this.tmr = setTimeout(() => this.run(), 1000 / this.limit_per_sec); | ||
return; | ||
} | ||
const items = this.queues.map(q => q.getNext()); | ||
const item = items.filter(item => item != null)[0]; | ||
if (item != null) { | ||
this.requests.push(now); | ||
this.in_progress = true; | ||
const queue = this.queues.find(q => q.size()); | ||
const item = queue?.getNext(); | ||
if (item) { | ||
this.request_time = now; | ||
item() | ||
.then(() => this.run()); | ||
this.run(); | ||
.catch(() => { | ||
}) | ||
.then(() => { | ||
this.in_progress = false; | ||
this.run(); | ||
}); | ||
} | ||
else { | ||
this.tmr = setTimeout(() => this.run(), 1000 / this.limit_per_sec); | ||
} | ||
} | ||
@@ -83,0 +96,0 @@ add(cb, priority) { |
@@ -54,2 +54,133 @@ import { TonClient4, Address, Cell } from "@ton/ton"; | ||
}[]>; | ||
getParsedTransactions(address: Address | string, params?: { | ||
lt: string; | ||
hash: string; | ||
}): Promise<{ | ||
lt: string; | ||
hash: string; | ||
fees: string; | ||
address: string; | ||
prevTransaction: { | ||
lt: string; | ||
hash: string; | ||
}; | ||
time: number; | ||
outMessagesCount: number; | ||
oldStatus: "active" | "uninitialized" | "frozen" | "non-existing"; | ||
newStatus: "active" | "uninitialized" | "frozen" | "non-existing"; | ||
update: { | ||
oldHash: string; | ||
newHash: string; | ||
}; | ||
inMessage: { | ||
body: string; | ||
init: { | ||
data: string | null; | ||
code: string | null; | ||
splitDepth: number | null; | ||
special: { | ||
tick: boolean; | ||
tock: boolean; | ||
} | null; | ||
} | null; | ||
info: { | ||
value: string; | ||
type: "internal"; | ||
dest: string; | ||
src: string; | ||
bounced: boolean; | ||
bounce: boolean; | ||
ihrDisabled: boolean; | ||
createdAt: number; | ||
createdLt: string; | ||
fwdFee: string; | ||
ihrFee: string; | ||
} | { | ||
type: "external-in"; | ||
dest: string; | ||
src: { | ||
data: string; | ||
bits: number; | ||
} | null; | ||
importFee: string; | ||
} | { | ||
type: "external-out"; | ||
dest: { | ||
data: string; | ||
bits: number; | ||
} | null; | ||
}; | ||
} | null; | ||
outMessages: { | ||
body: string; | ||
init: { | ||
data: string | null; | ||
code: string | null; | ||
splitDepth: number | null; | ||
special: { | ||
tick: boolean; | ||
tock: boolean; | ||
} | null; | ||
} | null; | ||
info: { | ||
value: string; | ||
type: "internal"; | ||
dest: string; | ||
src: string; | ||
bounced: boolean; | ||
bounce: boolean; | ||
ihrDisabled: boolean; | ||
createdAt: number; | ||
createdLt: string; | ||
fwdFee: string; | ||
ihrFee: string; | ||
} | { | ||
type: "external-in"; | ||
dest: string; | ||
src: { | ||
data: string; | ||
bits: number; | ||
} | null; | ||
importFee: string; | ||
} | { | ||
type: "external-out"; | ||
dest: { | ||
data: string; | ||
bits: number; | ||
} | null; | ||
}; | ||
}[]; | ||
parsed: { | ||
status: "success" | "failed" | "pending"; | ||
seqno: number | null; | ||
body: { | ||
type: "comment"; | ||
comment: string; | ||
} | { | ||
type: "payload"; | ||
cell: string; | ||
} | null; | ||
dest: string | null; | ||
bounced: boolean; | ||
kind: "out" | "in"; | ||
amount: string; | ||
resolvedAddress: string; | ||
mentioned: string[]; | ||
}; | ||
operation: { | ||
items: ({ | ||
kind: "ton"; | ||
amount: string; | ||
} | { | ||
kind: "token"; | ||
amount: string; | ||
})[]; | ||
address: string; | ||
comment?: string | undefined; | ||
op?: { | ||
type: "jetton::excesses" | "jetton::transfer" | "jetton::transfer_notification" | "deposit" | "deposit::ok" | "withdraw" | "withdraw::all" | "withdraw::delayed" | "withdraw::ok" | "airdrop"; | ||
options?: Record<string, string> | undefined; | ||
} | undefined; | ||
}; | ||
}[]>; | ||
getAddressBalance(address: string): Promise<BigInt>; | ||
@@ -56,0 +187,0 @@ getJetonUserAddress(jetonMasterAddress: string | Address, userAddress: string | Address): Promise<Address | null>; |
@@ -122,2 +122,3 @@ "use strict"; | ||
const transfer = contract.createTransfer({ | ||
queryId: BigInt(seqno), | ||
secretKey: key_pair.secretKey, | ||
@@ -167,3 +168,3 @@ sendMode: ton_1.SendMode.PAY_GAS_SEPARATELY, | ||
.storeUint(0xf8a7ea5, 32) // opcode for jetton transfer | ||
.storeUint(0, 64) // query id | ||
.storeUint(seqno, 64) // query id | ||
.storeCoins(amount) // jetton amount, amount * 10^decimals | ||
@@ -219,4 +220,28 @@ .storeAddress(parsed_address) // destination:MsgAddress | ||
const client = this.ton_client; | ||
return client.getAccountTransactions(user_address, BigInt(params.lt), Buffer.from(params.hash, 'hex')); | ||
return client.getAccountTransactions(user_address, BigInt(params.lt), Buffer.from(params.hash, 'base64')); | ||
} | ||
async getParsedTransactions(address, params) { | ||
if (!this.ton_client) { | ||
return Promise.reject('No client'); | ||
} | ||
if (!this.contract || !this.key_pair) { | ||
throw new Error('Contract not inited'); | ||
} | ||
if (!params) { | ||
const latestBlock = await this.ton_client.getLastBlock(); | ||
const latestBlockNumber = latestBlock.last.seqno; | ||
const { account } = await this.ton_client.getAccount(latestBlockNumber, this.contract.address); | ||
const { last: lastTransaction } = account; | ||
if (!lastTransaction) { | ||
return []; | ||
} | ||
params = lastTransaction; | ||
} | ||
const user_address = this.isValidAddress(address); | ||
if (!user_address) { | ||
return Promise.reject('Invalid user address'); | ||
} | ||
const client = this.ton_client; | ||
return (await client.getAccountTransactionsParsed(user_address, BigInt(params.lt), Buffer.from(params.hash, 'hex'))).transactions; | ||
} | ||
async getAddressBalance(address) { | ||
@@ -223,0 +248,0 @@ if (!this.contract || !this.key_pair) { |
@@ -7,2 +7,3 @@ import { TonTxWatcher } from './modules/txs/tonTxWatcher'; | ||
import { Address } from '@ton/core'; | ||
import { TransferQueue } from './modules/txs/TransferQueu'; | ||
export * from '@ton/core'; | ||
@@ -30,3 +31,4 @@ export * from './utils/safeJson'; | ||
Address: typeof Address; | ||
TransferQueue: typeof TransferQueue; | ||
}; | ||
export default _default; |
@@ -25,2 +25,3 @@ "use strict"; | ||
const core_1 = require("@ton/core"); | ||
const TransferQueu_1 = require("./modules/txs/TransferQueu"); | ||
__exportStar(require("@ton/core"), exports); | ||
@@ -43,4 +44,5 @@ __exportStar(require("./utils/safeJson"), exports); | ||
checkTonAuth: checkTonAuth_1.checkTonAuth, | ||
Address: core_1.Address | ||
Address: core_1.Address, | ||
TransferQueue: TransferQueu_1.TransferQueue | ||
}; | ||
//# sourceMappingURL=ton-watcher.js.map |
{ | ||
"name": "ton-watcher", | ||
"version": "1.2.10", | ||
"version": "1.2.11", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "build/index.js", |
@@ -17,2 +17,3 @@ export * from './modules/txs/tonTxWatcher'; | ||
import { checkTonAuth } from './utils/checkTonAuth'; | ||
import { TransferQueue } from './modules/txs/TransferQueu'; | ||
@@ -30,3 +31,4 @@ | ||
Address, | ||
TransferQueue | ||
}; | ||
import { getHttpV4Endpoint } from "@orbs-network/ton-access"; | ||
import { Address, TonClient4, WalletContractV5R1 } from "@ton/ton"; | ||
import { TonClient4, WalletContractV5R1 } from "@ton/ton"; | ||
import { keyPairFromSecretKey } from "@ton/crypto"; | ||
@@ -10,8 +10,9 @@ import { safeJSONStringify } from "../../utils/safeJson"; | ||
import { TonInteractionV4 } from "../../modules/wallet/CoreV4"; | ||
import { TransferQueue } from "../../modules/txs/TransferQueu"; | ||
type Events = { | ||
reqSendJetton: { destination: string, name: string, amount: string, message: string, req_id: number }; | ||
reqSendJetton: { destination: string, name: string, amount: string, message: string, req_id: number, priority: number }; | ||
resSendJetton: { hash: string | null, lt: string | null, msgHash: string | null, status: typeof STATUS[keyof typeof STATUS], reason: string | null, req_id: number, seqno: number } | { error: string, req_id: number }; | ||
reqSendTon: { destination: string, amount: string, message: string, req_id: number }; | ||
reqSendTon: { destination: string, amount: string, message: string, req_id: number, priority: number }; | ||
resSendTon: { hash: string | null, lt: string | null, msgHash: string | null, status: typeof STATUS[keyof typeof STATUS], reason: string | null, req_id: number, seqno: number } | { error: string, req_id: number }; | ||
@@ -38,2 +39,3 @@ | ||
jettons_config?: Record<string, { decimals: number; address: string }>; | ||
rps: number | ||
}; | ||
@@ -46,2 +48,4 @@ | ||
init.rps = init.rps || 2; | ||
try { | ||
@@ -53,3 +57,3 @@ const isTestnet = init.network !== 'mainnet'; | ||
axiosThrottle.use(axios, { requestsPerSecond: isTestnet ? 2 : 5 }); | ||
axiosThrottle.use(axios, { requestsPerSecond: init.rps }); | ||
// const endpoint = isTestnet ? 'https://testnet.toncenter.com/api/v2/jsonRPC' : await getHttpEndpoint({ network: init.network }); | ||
@@ -67,2 +71,6 @@ const endpoint = await getHttpV4Endpoint({ network: init.network }); | ||
const txs = new TransferQueue(core, (msg: string) => { | ||
process.send && process.send(safeJSONStringify({data: { level: 'debug', data: msg }, event: 'logger'})); | ||
}); | ||
const client4 = new TonClient4({ | ||
@@ -83,3 +91,3 @@ endpoint: endpoint4, | ||
process.send && process.send(`{ "event": "address", "data": { "address" : "${address.toString()}" }}`); | ||
process.on('message', (data: string) => executeCommand(core, data)); | ||
process.on('message', (data: string) => executeCommand(core, txs, data)); | ||
} catch(e) { | ||
@@ -94,3 +102,3 @@ process.send && process.send(safeJSONStringify({ event: 'error', data: e })); | ||
function executeCommand(ton: TonInteractionV4, data: string) { | ||
function executeCommand(ton: TonInteractionV4, txs: TransferQueue, data: string) { | ||
try { | ||
@@ -104,5 +112,5 @@ const event: TonProcessEvents = JSON.parse(data); | ||
case 'reqSendJetton': | ||
return sendJetton(event, ton); | ||
return sendJetton(event, txs); | ||
case 'reqSendTon': | ||
return sendTon(event, ton); | ||
return sendTon(event, txs); | ||
@@ -116,43 +124,13 @@ } | ||
async function sendTon(event: TonProcessEvents<'reqSendTon'>, ton: TonInteractionV4) { | ||
const { amount, destination, message, req_id } = event.data; | ||
async function sendTon(event: TonProcessEvents<'reqSendTon'>, ton: TransferQueue) { | ||
const { amount, destination, message, req_id, priority = 1 } = event.data; | ||
try { | ||
if (!ton.isValidAddress(destination)) { | ||
const event: TonProcessEvents<'resSendTon'> = { | ||
data: { error: 'Recipient Address is invalid', req_id }, | ||
event: "resSendTon" | ||
}; | ||
process.send && process.send(safeJSONStringify(event)); | ||
return; | ||
} | ||
const amount_bigint = parseToBigInt(Number(amount) * 10 ** 9) | ||
if (amount_bigint == null) { | ||
const event: TonProcessEvents<'resSendTon'> = { | ||
data: { error: `Amount is invalid ${Number(amount) * 10 ** 9}`, req_id }, | ||
event: "resSendTon" | ||
}; | ||
process.send && process.send(safeJSONStringify(event)); | ||
return; | ||
} | ||
const transfer = await ton.transferTonMessage(destination, amount_bigint, message); | ||
try { | ||
const res = await ton.sendTx(transfer.message); | ||
const event: TonProcessEvents<'resSendTon'> = { | ||
data: { req_id, hash: null, lt: null, msgHash: res.messageHash, status: 'ok', reason: null, seqno: transfer.seqno }, | ||
event: "resSendTon" | ||
}; | ||
process.send && process.send(safeJSONStringify(event)); | ||
} catch (e) { | ||
const event: TonProcessEvents<'resSendTon'> = { | ||
data: { req_id, hash: null, lt: null, msgHash: transfer.messageHash, status: 'ok', reason: null, seqno: transfer.seqno }, | ||
event: "resSendTon" | ||
}; | ||
process.send && process.send(safeJSONStringify(event)); | ||
} | ||
} catch (e) { | ||
const res = await ton.transfer(priority, destination, amount, 'TON', message); | ||
const event: TonProcessEvents<'resSendTon'> = { | ||
data: { req_id, hash: res.hash, lt: res.lt, msgHash: res.msgHash, status: 'ok', reason: null, seqno: res.seqno }, | ||
event: "resSendTon" | ||
}; | ||
process.send && process.send(safeJSONStringify(event)); | ||
} catch(e) { | ||
const event: TonProcessEvents<'resSendTon'> = { | ||
data: { error: safeJSONStringify(e), req_id }, | ||
@@ -165,60 +143,19 @@ event: "resSendTon" | ||
async function sendJetton(event: TonProcessEvents<'reqSendJetton'>, ton: TonInteractionV4) { | ||
const { amount, destination, message, req_id, name } = event.data; | ||
async function sendJetton(event: TonProcessEvents<'reqSendJetton'>, ton: TransferQueue) { | ||
const { amount, destination, message, req_id, name, priority = 1 } = event.data; | ||
try { | ||
if (!ton.isValidAddress(destination)) { | ||
const event: TonProcessEvents<'resSendJetton'> = { | ||
data: { error: 'Recipient Address is invalid', req_id }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send(safeJSONStringify(event)); | ||
return; | ||
} | ||
const jettons = await ton.getJettonsInfo(); | ||
const jetton_settings = jettons[name]; | ||
if (!jetton_settings) { | ||
const event: TonProcessEvents<'resSendJetton'> = { | ||
data: { error: 'Jetton not found', req_id }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send(safeJSONStringify(event)); | ||
return; | ||
} | ||
const amount_bigint = parseToBigInt(Number(amount) * 10 ** jetton_settings.decimals) | ||
if (amount_bigint == null) { | ||
const event: TonProcessEvents<'resSendJetton'> = { | ||
data: { error: `Amount is invalid ${Number(amount) * 10 ** jetton_settings.decimals}`, req_id }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send(safeJSONStringify(event)); | ||
return; | ||
} | ||
const transfer = await ton.transferJettonMessage(destination, jetton_settings.jettonMasterAddress.toString(), amount_bigint, message); | ||
try { | ||
const res = await ton.sendTx(transfer.message); | ||
const event: TonProcessEvents<'resSendJetton'> = { | ||
data: { req_id, hash: null, lt: null, msgHash: res.messageHash, status: 'ok', reason: null, seqno: transfer.seqno }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send(safeJSONStringify(event)); | ||
} catch (e) { | ||
const event: TonProcessEvents<'resSendJetton'> = { | ||
data: { req_id, hash: null, lt: null, msgHash: transfer.messageHash, status: 'ok', reason: null, seqno: transfer.seqno }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send(safeJSONStringify(event)); | ||
} | ||
} catch (e) { | ||
const event: TonProcessEvents<'resSendJetton'> = { | ||
data: { error: safeJSONStringify(e), req_id }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send(safeJSONStringify(event)); | ||
} | ||
const res = await ton.transfer(priority, destination, amount, name, message); | ||
const event: TonProcessEvents<'resSendJetton'> = { | ||
data: { req_id, hash: null, lt: null, msgHash: res.msgHash, status: 'ok', reason: null, seqno: res.seqno }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send(safeJSONStringify(event)); | ||
} catch(e) { | ||
const event: TonProcessEvents<'resSendJetton'> = { | ||
data: { error: safeJSONStringify(e), req_id }, | ||
event: "resSendJetton" | ||
}; | ||
process.send && process.send(safeJSONStringify(event)); | ||
} | ||
} | ||
@@ -292,9 +229,1 @@ | ||
} | ||
function parseToBigInt(value: any) : bigint | null { | ||
try { | ||
return BigInt(value); | ||
} catch (e) { | ||
return null; | ||
} | ||
} |
@@ -30,4 +30,8 @@ | ||
public getNext(): null | (() => Promise<void>) { | ||
if (this.executed_promise) { | ||
public isBusy(): boolean { | ||
return !!this.executed_promise; | ||
} | ||
public getNext(): (null | (() => Promise<void>)) { | ||
if (this.isBusy()) { | ||
return null; | ||
@@ -69,5 +73,6 @@ } | ||
private tmr: NodeJS.Timeout | undefined; | ||
private requests: Array<number> = []; | ||
private request_time: number = 0; | ||
private limit_per_sec: number; | ||
private queues: Array<Queue>; | ||
private in_progress = false; | ||
@@ -77,3 +82,3 @@ constructor(prority_number = 4, limit_per_sec = 10) { | ||
this.queues = Array | ||
.from(new Uint16Array(prority_number)) | ||
.from(new Uint8Array(prority_number)) | ||
.map(() => new Queue()); | ||
@@ -84,3 +89,4 @@ } | ||
public size() { | ||
return this.queues.map(q => q.size()); | ||
return this.queues.map(q => q.size()) | ||
.reduce((acc, count) => acc + count, 0); | ||
} | ||
@@ -93,6 +99,6 @@ | ||
const now = Date.now(); | ||
const is_inprogress = this.in_progress; | ||
this.requests = this.requests.filter(time => (now - time) < 1000); | ||
if (this.requests.length >= (this.limit_per_sec - 1)) { | ||
if (is_inprogress || (this.request_time + 1000 / this.limit_per_sec) > now) { | ||
this.tmr = setTimeout(() => this.run(), 1000 / this.limit_per_sec); | ||
@@ -102,11 +108,19 @@ return; | ||
const items = this.queues.map(q => q.getNext()); | ||
const item = items.filter(item => item != null)[0]; | ||
this.in_progress = true; | ||
if (item != null) { | ||
this.requests.push(now); | ||
const queue = this.queues.find(q => q.size()); | ||
const item = queue?.getNext(); | ||
if (item) { | ||
this.request_time = now; | ||
item() | ||
.then(() => this.run()); | ||
this.run(); | ||
.catch(() => { | ||
}) | ||
.then(() => { | ||
this.in_progress = false; | ||
this.run(); | ||
}); | ||
} else { | ||
this.tmr = setTimeout(() => this.run(), 1000 / this.limit_per_sec); | ||
} | ||
@@ -113,0 +127,0 @@ } |
@@ -145,2 +145,3 @@ import { TonClient4, WalletContractV5R1, internal, SendMode, OpenedContract, Address, JettonMaster, JettonWallet, beginCell, toNano, external, Cell, storeMessage } from "@ton/ton"; | ||
const transfer = contract.createTransfer({ | ||
queryId: BigInt(seqno), | ||
secretKey: key_pair.secretKey, | ||
@@ -207,3 +208,3 @@ sendMode: SendMode.PAY_GAS_SEPARATELY, | ||
.storeUint(0xf8a7ea5, 32) // opcode for jetton transfer | ||
.storeUint(0, 64) // query id | ||
.storeUint(seqno, 64) // query id | ||
.storeCoins(amount) // jetton amount, amount * 10^decimals | ||
@@ -271,5 +272,36 @@ .storeAddress(parsed_address) // destination:MsgAddress | ||
return client.getAccountTransactions(user_address, BigInt(params.lt), Buffer.from(params.hash, 'hex')); | ||
return client.getAccountTransactions(user_address, BigInt(params.lt), Buffer.from(params.hash, 'base64')); | ||
} | ||
public async getParsedTransactions(address: Address | string, params?: { lt: string, hash: string }) { | ||
if (!this.ton_client) { | ||
return Promise.reject('No client'); | ||
} | ||
if (!this.contract || !this.key_pair) { | ||
throw new Error('Contract not inited'); | ||
} | ||
if (!params) { | ||
const latestBlock = await this.ton_client.getLastBlock(); | ||
const latestBlockNumber = latestBlock.last.seqno; | ||
const { account } = await this.ton_client.getAccount(latestBlockNumber, this.contract.address); | ||
const { last: lastTransaction } = account; | ||
if (!lastTransaction) { | ||
return []; | ||
} | ||
params = lastTransaction; | ||
} | ||
const user_address = this.isValidAddress(address); | ||
if (!user_address) { | ||
return Promise.reject('Invalid user address'); | ||
} | ||
const client = this.ton_client; | ||
return (await client.getAccountTransactionsParsed(user_address, BigInt(params.lt), Buffer.from(params.hash, 'hex'))).transactions; | ||
} | ||
public async getAddressBalance(address: string): Promise<BigInt> { | ||
@@ -276,0 +308,0 @@ |
@@ -9,2 +9,3 @@ import { parse_tx } from './modules/txs/Transaction'; | ||
import { Address } from '@ton/core'; | ||
import { TransferQueue } from './modules/txs/TransferQueu'; | ||
@@ -29,3 +30,4 @@ export * from '@ton/core'; | ||
checkTonAuth, | ||
Address | ||
Address, | ||
TransferQueue | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
357116
6.45%101
7.45%5952
7.15%