ton-watcher
Advanced tools
Comparing version 1.2.11 to 1.3.0
@@ -15,4 +15,5 @@ export * from './modules/txs/tonTxWatcher'; | ||
import { TransferQueue } from './modules/txs/TransferQueu'; | ||
import { TrackTxBySeqNo } from './modules/txs/TrackTxBySeqno'; | ||
declare const _default: { | ||
parse_tx: (tx: import("@ton/ton").Transaction, is_testnet?: boolean) => any; | ||
parse_tx: (tx: import("@ton/ton").Transaction, is_testnet?: boolean) => import("./modules/txs/Transaction").ParsedTx; | ||
TonTxWatcher: typeof TonTxWatcher; | ||
@@ -31,3 +32,4 @@ getJettonInfo: typeof getJettonInfo; | ||
TransferQueue: typeof TransferQueue; | ||
TrackTxBySeqNo: typeof TrackTxBySeqNo; | ||
}; | ||
export default _default; |
@@ -33,2 +33,3 @@ "use strict"; | ||
const TransferQueu_1 = require("./modules/txs/TransferQueu"); | ||
const TrackTxBySeqno_1 = require("./modules/txs/TrackTxBySeqno"); | ||
exports.default = { | ||
@@ -44,4 +45,5 @@ parse_tx: Transaction_1.parse_tx, | ||
Address: ton_1.Address, | ||
TransferQueue: TransferQueu_1.TransferQueue | ||
TransferQueue: TransferQueu_1.TransferQueue, | ||
TrackTxBySeqNo: TrackTxBySeqno_1.TrackTxBySeqNo | ||
}; | ||
//# sourceMappingURL=index.js.map |
@@ -11,5 +11,5 @@ export interface Persistent<T> { | ||
to: string; | ||
fee: number; | ||
fee?: string; | ||
time: number; | ||
msg: string; | ||
msg?: string | null; | ||
token: string; | ||
@@ -16,0 +16,0 @@ amount: string; |
@@ -12,4 +12,2 @@ import { STATUS } from "../../modules/txs/sendTx"; | ||
resSendJetton: { | ||
hash: string | null; | ||
lt: string | null; | ||
msgHash: string | null; | ||
@@ -32,4 +30,2 @@ status: typeof STATUS[keyof typeof STATUS]; | ||
resSendTon: { | ||
hash: string | null; | ||
lt: string | null; | ||
msgHash: string | null; | ||
@@ -70,2 +66,18 @@ status: typeof STATUS[keyof typeof STATUS]; | ||
}; | ||
reqTxStatus: { | ||
req_id: number; | ||
msgHash: string; | ||
seqno: number; | ||
}; | ||
resTxStatus: { | ||
req_id: number; | ||
msgHash: string; | ||
seqno: number; | ||
hash: string; | ||
lt: string; | ||
status: 'ok' | 'pending' | 'noExist' | 'fail'; | ||
} | { | ||
error: string; | ||
req_id: number; | ||
}; | ||
lastState: { | ||
@@ -72,0 +84,0 @@ lt: string; |
@@ -16,2 +16,3 @@ "use strict"; | ||
const TransferQueu_1 = require("../../modules/txs/TransferQueu"); | ||
const TrackTxBySeqno_1 = require("../../modules/txs/TrackTxBySeqno"); | ||
async function runWatcher(init) { | ||
@@ -37,2 +38,3 @@ if (!init) { | ||
}); | ||
const tx_finder = new TrackTxBySeqno_1.TrackTxBySeqNo(core); | ||
const txs = new TransferQueu_1.TransferQueue(core, (msg) => { | ||
@@ -54,3 +56,3 @@ process.send && process.send((0, safeJson_1.safeJSONStringify)({ data: { level: 'debug', data: msg }, event: 'logger' })); | ||
process.send && process.send(`{ "event": "address", "data": { "address" : "${address.toString()}" }}`); | ||
process.on('message', (data) => executeCommand(core, txs, data)); | ||
process.on('message', (data) => executeCommand(core, txs, tx_finder, data)); | ||
} | ||
@@ -64,3 +66,3 @@ catch (e) { | ||
} | ||
function executeCommand(ton, txs, data) { | ||
function executeCommand(ton, txs, tx_finder, data) { | ||
try { | ||
@@ -77,2 +79,4 @@ const event = JSON.parse(data); | ||
return sendTon(event, txs); | ||
case 'reqTxStatus': | ||
return txStatus(event, tx_finder); | ||
} | ||
@@ -84,2 +88,20 @@ } | ||
} | ||
async function txStatus(event, tx_finder) { | ||
const { msgHash, req_id, seqno } = event.data; | ||
try { | ||
const res = await tx_finder.searchTx(seqno, msgHash); | ||
const resp = { | ||
data: { req_id, ...res }, | ||
event: "resTxStatus" | ||
}; | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)(resp)); | ||
} | ||
catch (e) { | ||
const resp = { | ||
data: { error: (0, safeJson_1.safeJSONStringify)(e), req_id }, | ||
event: "resTxStatus" | ||
}; | ||
process.send && process.send((0, safeJson_1.safeJSONStringify)(resp)); | ||
} | ||
} | ||
async function sendTon(event, ton) { | ||
@@ -90,3 +112,3 @@ const { amount, destination, message, req_id, priority = 1 } = event.data; | ||
const event = { | ||
data: { req_id, hash: res.hash, lt: res.lt, msgHash: res.msgHash, status: 'ok', reason: null, seqno: res.seqno }, | ||
data: { req_id, msgHash: res.msgHash, status: 'ok', reason: null, seqno: res.seqno }, | ||
event: "resSendTon" | ||
@@ -109,3 +131,3 @@ }; | ||
const event = { | ||
data: { req_id, hash: null, lt: null, msgHash: res.msgHash, status: 'ok', reason: null, seqno: res.seqno }, | ||
data: { req_id, msgHash: res.msgHash, status: 'ok', reason: null, seqno: res.seqno }, | ||
event: "resSendJetton" | ||
@@ -112,0 +134,0 @@ }; |
@@ -92,3 +92,3 @@ "use strict"; | ||
const parsed = (0, Transaction_1.parse_tx)(data.tx); | ||
data.status = parsed.status !== 'fail' ? exports.STATUS.OK : exports.STATUS.FAIL; | ||
data.status = parsed.status !== 'failed' ? exports.STATUS.OK : exports.STATUS.FAIL; | ||
} | ||
@@ -95,0 +95,0 @@ else { |
@@ -22,3 +22,3 @@ import { TonClient, Transaction } from "@ton/ton"; | ||
name: string; | ||
message: string; | ||
message?: string | null; | ||
decimals: number; | ||
@@ -25,0 +25,0 @@ lt: string; |
@@ -136,3 +136,3 @@ "use strict"; | ||
} | ||
else if (parsed_tx.inMessage.type === 'external-in' || parsed_tx.inMessage.recipient === this.address.toString()) { | ||
else if (parsed_tx.inMessage.recipient === this.address.toString()) { | ||
this.processing_out_tx(parsed_tx); | ||
@@ -139,0 +139,0 @@ } |
@@ -205,3 +205,3 @@ "use strict"; | ||
decimals, | ||
message: msg, | ||
message: msg || '', | ||
name: token, | ||
@@ -208,0 +208,0 @@ hash, |
@@ -1,2 +0,63 @@ | ||
import { Transaction } from "@ton/ton"; | ||
export declare const parse_tx: (tx: Transaction, is_testnet?: boolean) => any; | ||
import { AccountStatus, Address, Transaction } from "@ton/ton"; | ||
export declare const parse_tx: (tx: Transaction, is_testnet?: boolean) => ParsedTx; | ||
export type ParsedTx = { | ||
originalTx: Transaction; | ||
accStatus: AccountStatus; | ||
hash: string; | ||
now: number; | ||
totalFees: undefined | bigint; | ||
lt: bigint; | ||
oldStatus: AccountStatus; | ||
prevTxHash: string; | ||
prevLt: bigint; | ||
address: bigint; | ||
is_testnet: boolean; | ||
wallet_id: number; | ||
status?: 'succeeded' | 'failed'; | ||
reason?: string; | ||
is_aborted: boolean; | ||
is_destroyed: boolean; | ||
type: string; | ||
success: boolean; | ||
totalFeesFromdesc?: bigint; | ||
inMessage: IncomingMessage; | ||
outMessages: Array<any>; | ||
}; | ||
export type IncomingMessage = { | ||
msgType: 'external-in' | 'internal'; | ||
hash: string; | ||
sender?: string; | ||
recipient?: string; | ||
message?: string | null; | ||
tx_type: 'unknown' | 'jetton_notification' | 'jetton_request' | 'excess_ton' | 'nft_request'; | ||
jetton_notify?: { | ||
jettonAmount: bigint; | ||
jettonSender: Address; | ||
message: string | null; | ||
}; | ||
jetton_req?: { | ||
jettonAmount: bigint; | ||
jettonSender: Address; | ||
message: string | null; | ||
}; | ||
} & (IncomingMessageInternal | IncomingMessageExternalIn); | ||
export type IncomingMessageInternal = { | ||
msgType: 'internal'; | ||
value: bigint; | ||
ihrFee: bigint; | ||
forwardFee: bigint; | ||
bounce: boolean; | ||
bounced: boolean; | ||
createdAt: bigint; | ||
createdLt: bigint; | ||
ihrDisabled: boolean; | ||
}; | ||
export type IncomingMessageExternalIn = { | ||
msgType: 'external-in'; | ||
importFee: bigint; | ||
opcode: string; | ||
timeout: number; | ||
seqno: number; | ||
query_id: number; | ||
wallet_id: number; | ||
}; |
@@ -22,3 +22,3 @@ "use strict"; | ||
accStatus: tx.endStatus, | ||
hash: tx.hash().toString('hex'), | ||
hash: tx.hash().toString('base64'), | ||
now: tx.now, | ||
@@ -56,2 +56,3 @@ totalFees: tx.totalFees.coins, | ||
return { | ||
wallet_id, | ||
...result | ||
@@ -65,4 +66,4 @@ }; | ||
const success = tx.description.actionPhase?.success; | ||
const totalFees = tx.description.actionPhase?.totalActionFees; | ||
return { is_aborted, is_destroyed, type, success, totalFees }; | ||
const totalFeesFromdesc = tx.description.actionPhase?.totalActionFees; | ||
return { is_aborted, is_destroyed, type, success, totalFeesFromdesc }; | ||
} | ||
@@ -102,5 +103,27 @@ function parseOutMessage(out_message, is_testnet = false) { | ||
function parseExternalInNessage(in_message) { | ||
return { | ||
importFee: in_message.info.importFee | ||
const res = { | ||
importFee: in_message.info.importFee, | ||
opcode: '', | ||
timeout: -1, | ||
seqno: -1, | ||
query_id: -1, | ||
wallet_id: -1 | ||
}; | ||
try { | ||
const slice = in_message.body.beginParse().clone(); | ||
if (!slice.remainingBits) { | ||
return res; | ||
} | ||
res.opcode = '0x' + slice.loadUint(32).toString(16); | ||
switch (res.opcode) { | ||
case '0x7369676e': | ||
res.wallet_id = slice.loadUint(32); | ||
res.timeout = slice.loadUint(32); | ||
res.seqno = slice.loadUint(32); | ||
break; | ||
} | ||
} | ||
catch (e) { | ||
} | ||
return res; | ||
} | ||
@@ -126,2 +149,3 @@ function parseInternalMessage(in_message) { | ||
const op_code = slice.loadUint(32); | ||
//const query_id = slice.loadUint(64); | ||
const remainings = slice.remainingBits; | ||
@@ -171,3 +195,3 @@ let message = ''; | ||
const op = body.loadUint(32); | ||
body.skip(64); // skip query_id | ||
const query_id = body.loadUint(64); | ||
const jettonAmount = body.loadCoins(); | ||
@@ -184,3 +208,3 @@ const jettonSender = body.loadAddressAny(); | ||
const message = forwardPayload.loadStringTail(); | ||
return { jettonSender, jettonAmount, message }; | ||
return { jettonSender, jettonAmount, message, queryId: query_id, op }; | ||
} | ||
@@ -190,3 +214,3 @@ else { | ||
// you may parse it manually if you know other opcodes or just print it as hex | ||
return { jettonSender, jettonAmount, message: null }; | ||
return { jettonSender, jettonAmount, message: null, queryId: query_id, op }; | ||
} | ||
@@ -193,0 +217,0 @@ } |
@@ -8,8 +8,7 @@ import { TonInteractionV4 } from "../../modules/wallet/CoreV4"; | ||
private logger; | ||
private currentSeqNo; | ||
constructor(ton: TonInteractionV4, logger?: (msg: string) => void); | ||
transfer(priority: number, address: string, amount: string, name: Tokens, message?: string): Promise<{ | ||
hash: string; | ||
msgHash: string; | ||
seqno: number; | ||
lt: string; | ||
}>; | ||
@@ -16,0 +15,0 @@ private _transfer; |
@@ -11,2 +11,3 @@ "use strict"; | ||
logger; | ||
currentSeqNo = -1; | ||
constructor(ton, logger) { | ||
@@ -33,2 +34,5 @@ this.queue = new Queue_1.PriorityQueue(5, 1); | ||
const bigIntAmount = (0, stringNumber_1.strToBigInt)(amount, 9); | ||
if (this.currentSeqNo !== -1) { | ||
await this.waitNewSeqNo(this.currentSeqNo); | ||
} | ||
const { message, messageHash, seqno } = await this.ton.transferTonMessage(address, bigIntAmount, msg, true); | ||
@@ -38,5 +42,5 @@ this.logger(`TON transfer ready to send ${amount} to ${address} seqno ${seqno} msghash ${messageHash}`); | ||
this.logger(`TON transfer sent ${amount} to ${address} seqno ${seqno} msghash ${messageHash}`); | ||
const data = await this.waitMsgHash(messageHash); | ||
this.logger(`TON transfer done ${amount} to ${address} seqno ${seqno} msghash ${messageHash} txhash is ${data.hash}`); | ||
return { ...data, seqno }; | ||
// const data = await this.waitMsgHash(messageHash); | ||
this.logger(`TON transfer done ${amount} to ${address} seqno ${seqno} msghash ${messageHash}`); | ||
return { msgHash: messageHash, seqno }; | ||
} | ||
@@ -48,2 +52,5 @@ async transferJetton(address, amount, name, msg = '') { | ||
} | ||
if (this.currentSeqNo !== -1) { | ||
await this.waitNewSeqNo(this.currentSeqNo); | ||
} | ||
const bigIntAmount = (0, stringNumber_1.strToBigInt)(amount, jettons[name].decimals); | ||
@@ -58,11 +65,12 @@ const balance = await this.ton.fetchJettonWalletBalance(jettons[name].jettonMasterAddress.toRawString(), address); | ||
this.logger(`Jetton ${name} transfer sent ${amount} to ${address} seqno ${seqno} msghash ${messageHash}`); | ||
const data = await this.waitMsgHash(messageHash); | ||
this.logger(`Jetton ${name} transfer done ${amount} to ${address} seqno ${seqno} msghash ${messageHash} txhash is ${data.hash}`); | ||
return { ...data, seqno }; | ||
// const data = await this.waitMsgHash(messageHash); | ||
this.logger(`Jetton ${name} transfer done ${amount} to ${address} seqno ${seqno} msghash ${messageHash}`); | ||
return { msgHash: messageHash, seqno }; | ||
} | ||
async sendMsg(msg, seqNo) { | ||
const newSeqNo = await this.ton.getSeqNo(); | ||
if (newSeqNo > seqNo) { | ||
if (newSeqNo !== seqNo) { | ||
throw new Error('Invalid message Seqno is expired'); | ||
} | ||
this.currentSeqNo = newSeqNo; | ||
try { | ||
@@ -73,3 +81,2 @@ await this.ton.sendTx(msg); | ||
} | ||
await this.waitNewSeqNo(seqNo); | ||
} | ||
@@ -76,0 +83,0 @@ async waitNewSeqNo(seqNo, delay = 5000, maxTryes = 20) { |
@@ -13,2 +13,3 @@ import { TonClient4, Address, Cell } from "@ton/ton"; | ||
private is_testnet; | ||
private txTimeDelay; | ||
private constructor(); | ||
@@ -15,0 +16,0 @@ getSeqNo(): Promise<number>; |
@@ -8,3 +8,2 @@ "use strict"; | ||
const checkProof_1 = require("./utils/checkProof"); | ||
const common_helpers_1 = require("../../modules/helpers/common_helpers"); | ||
class TonInteractionV4 { | ||
@@ -18,2 +17,3 @@ address; | ||
is_testnet = false; | ||
txTimeDelay = 30; | ||
constructor(client, key_pair, contract, jetton_settings, is_testnet) { | ||
@@ -77,3 +77,3 @@ if (!client) { | ||
const { message, seqno, messageHash } = await this.transferJettonMessage(ton_address, jetton_master_address, amount, msg); | ||
this.contract.send(message); | ||
await this.contract.send(message); | ||
return { | ||
@@ -143,3 +143,3 @@ messageHash, | ||
const sq = res.last.seqno; | ||
const is_deploed = await this.ton_client.isContractDeployed(sq, parsed_address); | ||
const is_deploed = true || (await this.ton_client.isContractDeployed(sq, parsed_address)); | ||
if (!is_deploed) { | ||
@@ -156,10 +156,10 @@ throw new Error('Address is not active'); | ||
const { jettonUserWalletAddress, jettonUserWalletContract } = jetton_info; | ||
const jetton_balance = await jettonUserWalletContract.getBalance(); | ||
if (jetton_balance < amount) { | ||
return Promise.reject(`Balance less than amount to transfer balance is ${jetton_balance} amount is ${amount}`); | ||
} | ||
const ton_balance = await this.contract.getBalance(); | ||
if (ton_balance < BigInt(10 ** 8)) { | ||
return Promise.reject(`Ton Balance less than fee to balance is ${ton_balance} min balance is 0.1 TON`); | ||
} | ||
// const jetton_balance = await jettonUserWalletContract.getBalance(); | ||
// if (jetton_balance < amount) { | ||
// return Promise.reject(`Balance less than amount to transfer balance is ${jetton_balance} amount is ${amount}`); | ||
// } | ||
// const ton_balance = await this.contract.getBalance(); | ||
// if (ton_balance < BigInt(10 ** 8)) { | ||
// return Promise.reject(`Ton Balance less than fee to balance is ${ton_balance} min balance is 0.1 TON`); | ||
// } | ||
const seqno = await this.contract.getSeqno(); | ||
@@ -205,4 +205,5 @@ const forwardPayload = (0, ton_1.beginCell)() | ||
} | ||
if (!this.contract || !this.key_pair) { | ||
throw new Error('Contract not inited'); | ||
const parsed = this.isValidAddress(address); | ||
if (!parsed) { | ||
throw new Error('Address is not valid'); | ||
} | ||
@@ -212,3 +213,3 @@ if (!params) { | ||
const latestBlockNumber = latestBlock.last.seqno; | ||
const { account } = await this.ton_client.getAccount(latestBlockNumber, this.contract.address); | ||
const { account } = await this.ton_client.getAccount(latestBlockNumber, parsed); | ||
const { last: lastTransaction } = account; | ||
@@ -249,3 +250,3 @@ if (!lastTransaction) { | ||
const client = this.ton_client; | ||
return (await client.getAccountTransactionsParsed(user_address, BigInt(params.lt), Buffer.from(params.hash, 'hex'))).transactions; | ||
return (await client.getAccountTransactionsParsed(user_address, BigInt(params.lt), Buffer.from(params.hash, 'base64'))).transactions; | ||
} | ||
@@ -361,2 +362,3 @@ async getAddressBalance(address) { | ||
const transfer = this.contract.createTransfer({ | ||
timeout: Math.floor(Date.now() / 1e3) + this.txTimeDelay, | ||
secretKey: this.key_pair.secretKey, | ||
@@ -385,4 +387,2 @@ sendMode: ton_1.SendMode.PAY_GAS_SEPARATELY, | ||
} | ||
let tryes = 0; | ||
const seqno = await this.getSeqNo(); | ||
const messageHash = message.hash().toString('hex'); | ||
@@ -399,14 +399,2 @@ const ext = (0, ton_1.external)({ | ||
const finalHash = finall_cell.hash().toString('hex'); | ||
await (0, common_helpers_1.wait)(10000); | ||
while (true) { | ||
const seqno2 = await this.getSeqNo(); | ||
if (seqno2 > seqno) { | ||
break; | ||
} | ||
tryes++; | ||
if (tryes > 20) { | ||
throw new Error('Seqno is not changed in 2 min'); | ||
} | ||
await (0, common_helpers_1.wait)(5000); | ||
} | ||
return { | ||
@@ -413,0 +401,0 @@ messageHash, |
@@ -8,2 +8,3 @@ import { TonTxWatcher } from './modules/txs/tonTxWatcher'; | ||
import { TransferQueue } from './modules/txs/TransferQueu'; | ||
import { TrackTxBySeqNo } from './modules/txs/TrackTxBySeqno'; | ||
export * from '@ton/core'; | ||
@@ -18,3 +19,3 @@ export * from './utils/safeJson'; | ||
declare const _default: { | ||
parse_tx: (tx: import("@ton/core").Transaction, is_testnet?: boolean) => any; | ||
parse_tx: (tx: import("@ton/core").Transaction, is_testnet?: boolean) => import("./modules/txs/Transaction").ParsedTx; | ||
TonTxWatcher: typeof TonTxWatcher; | ||
@@ -33,3 +34,4 @@ getJettonInfo: typeof getJettonInfo; | ||
TransferQueue: typeof TransferQueue; | ||
TrackTxBySeqNo: typeof TrackTxBySeqNo; | ||
}; | ||
export default _default; |
@@ -26,2 +26,3 @@ "use strict"; | ||
const TransferQueu_1 = require("./modules/txs/TransferQueu"); | ||
const TrackTxBySeqno_1 = require("./modules/txs/TrackTxBySeqno"); | ||
__exportStar(require("@ton/core"), exports); | ||
@@ -45,4 +46,5 @@ __exportStar(require("./utils/safeJson"), exports); | ||
Address: core_1.Address, | ||
TransferQueue: TransferQueu_1.TransferQueue | ||
TransferQueue: TransferQueu_1.TransferQueue, | ||
TrackTxBySeqNo: TrackTxBySeqno_1.TrackTxBySeqNo | ||
}; | ||
//# sourceMappingURL=ton-watcher.js.map |
{ | ||
"name": "ton-watcher", | ||
"version": "1.2.11", | ||
"version": "1.3.0", | ||
"description": "", | ||
@@ -15,3 +15,3 @@ "main": "build/index.js", | ||
"@orbs-network/ton-access": "^2.3.3", | ||
"@ton/core": "^0.58.1", | ||
"@ton/core": "^0.59.0", | ||
"@ton/ton": "^15.0.0", | ||
@@ -18,0 +18,0 @@ "axios-request-throttle": "^1.0.0", |
@@ -18,2 +18,3 @@ export * from './modules/txs/tonTxWatcher'; | ||
import { TransferQueue } from './modules/txs/TransferQueu'; | ||
import { TrackTxBySeqNo } from './modules/txs/TrackTxBySeqno'; | ||
@@ -31,4 +32,5 @@ | ||
Address, | ||
TransferQueue | ||
TransferQueue, | ||
TrackTxBySeqNo | ||
}; | ||
@@ -9,3 +9,3 @@ | ||
export type StoredTx = { hash: string, from: string, to: string, fee: number, time: number, msg: string, token: string, amount: string, status: string, decimals: number, lt: string, success: boolean, inMessageHash: string }; | ||
export type StoredTx = { hash: string, from: string, to: string, fee?: string, time: number, msg?: string | null, token: string, amount: string, status: string, decimals: number, lt: string, success: boolean, inMessageHash: string }; | ||
@@ -12,0 +12,0 @@ export type Store = { |
@@ -11,9 +11,10 @@ import { getHttpV4Endpoint } from "@orbs-network/ton-access"; | ||
import { TransferQueue } from "../../modules/txs/TransferQueu"; | ||
import { TrackTxBySeqNo } from "../../modules/txs/TrackTxBySeqno"; | ||
type Events = { | ||
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 }; | ||
resSendJetton: { 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, 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 }; | ||
resSendTon: { msgHash: string | null, status: typeof STATUS[keyof typeof STATUS], reason: string | null, req_id: number, seqno: number } | { error: string, req_id: number }; | ||
@@ -26,2 +27,5 @@ reqTonBalance: { req_id: number; address?: string; }; | ||
reqTxStatus: { req_id: number; msgHash: string; seqno: number }; | ||
resTxStatus: { req_id: number; msgHash: string; seqno: number, hash: string, lt: string, status: 'ok' | 'pending' | 'noExist' | 'fail' } | { error: string, req_id: number }; | ||
lastState: { lt: string, hash: string }; | ||
@@ -69,2 +73,4 @@ }; | ||
const tx_finder = new TrackTxBySeqNo(core); | ||
const txs = new TransferQueue(core, (msg: string) => { | ||
@@ -89,3 +95,3 @@ process.send && process.send(safeJSONStringify({data: { level: 'debug', data: msg }, event: 'logger'})); | ||
process.send && process.send(`{ "event": "address", "data": { "address" : "${address.toString()}" }}`); | ||
process.on('message', (data: string) => executeCommand(core, txs, data)); | ||
process.on('message', (data: string) => executeCommand(core, txs, tx_finder, data)); | ||
} catch(e) { | ||
@@ -100,3 +106,3 @@ process.send && process.send(safeJSONStringify({ event: 'error', data: e })); | ||
function executeCommand(ton: TonInteractionV4, txs: TransferQueue, data: string) { | ||
function executeCommand(ton: TonInteractionV4, txs: TransferQueue, tx_finder: TrackTxBySeqNo, data: string) { | ||
try { | ||
@@ -113,2 +119,4 @@ const event: TonProcessEvents = JSON.parse(data); | ||
return sendTon(event, txs); | ||
case 'reqTxStatus': | ||
return txStatus(event, tx_finder); | ||
@@ -122,2 +130,21 @@ } | ||
async function txStatus(event: TonProcessEvents<'reqTxStatus'>, tx_finder: TrackTxBySeqNo) { | ||
const { msgHash, req_id, seqno } = event.data; | ||
try { | ||
const res = await tx_finder.searchTx(seqno, msgHash); | ||
const resp: TonProcessEvents<'resTxStatus'> = { | ||
data: { req_id, ...res }, | ||
event: "resTxStatus" | ||
}; | ||
process.send && process.send(safeJSONStringify(resp)); | ||
} catch (e) { | ||
const resp: TonProcessEvents<'resTxStatus'> = { | ||
data: { error: safeJSONStringify(e), req_id }, | ||
event: "resTxStatus" | ||
}; | ||
process.send && process.send(safeJSONStringify(resp)); | ||
} | ||
} | ||
async function sendTon(event: TonProcessEvents<'reqSendTon'>, ton: TransferQueue) { | ||
@@ -128,3 +155,3 @@ const { amount, destination, message, req_id, priority = 1 } = event.data; | ||
const event: TonProcessEvents<'resSendTon'> = { | ||
data: { req_id, hash: res.hash, lt: res.lt, msgHash: res.msgHash, status: 'ok', reason: null, seqno: res.seqno }, | ||
data: { req_id, msgHash: res.msgHash, status: 'ok', reason: null, seqno: res.seqno }, | ||
event: "resSendTon" | ||
@@ -148,3 +175,3 @@ }; | ||
const event: TonProcessEvents<'resSendJetton'> = { | ||
data: { req_id, hash: null, lt: null, msgHash: res.msgHash, status: 'ok', reason: null, seqno: res.seqno }, | ||
data: { req_id, msgHash: res.msgHash, status: 'ok', reason: null, seqno: res.seqno }, | ||
event: "resSendJetton" | ||
@@ -151,0 +178,0 @@ }; |
@@ -121,3 +121,3 @@ import { Cell, Transaction } from '@ton/core'; | ||
const parsed = parse_tx(data.tx) | ||
data.status = parsed.status !== 'fail' ? STATUS.OK : STATUS.FAIL; | ||
data.status = parsed.status !== 'failed' ? STATUS.OK : STATUS.FAIL; | ||
} else { | ||
@@ -124,0 +124,0 @@ data.status = STATUS.UNKNOWN; |
@@ -10,3 +10,3 @@ import { Address, TonClient, Transaction } from "@ton/ton"; | ||
jettonBalance?: (data: { address: string, amount: string, name: string, decimals: number }) => void | Promise<void>; | ||
jettonDeposit?: (data: { from: string, to: string, hash: string, amount: string, name: string, message: string, decimals: number, lt: string, success: boolean, inMessageHash: string }) => void | Promise<void>; | ||
jettonDeposit?: (data: { from: string, to: string, hash: string, amount: string, name: string, message?: string | null, decimals: number, lt: string, success: boolean, inMessageHash: string }) => void | Promise<void>; | ||
tonDeposit?: (data: { address: string, amount: string, message: string, decimals: number, hash: string }) => void | Promise<void>; | ||
@@ -171,3 +171,3 @@ transferTx?: (data?: any) => void | Promise<void>; | ||
}; | ||
} else if (parsed_tx.inMessage.type === 'external-in' || parsed_tx.inMessage.recipient === this.address.toString()) { | ||
} else if (parsed_tx.inMessage.recipient === this.address.toString()) { | ||
this.processing_out_tx(parsed_tx); | ||
@@ -174,0 +174,0 @@ } else { |
@@ -258,3 +258,3 @@ import { Address, TonClient4, Transaction, WalletContractV5R1 } from "@ton/ton"; | ||
decimals, | ||
message: msg, | ||
message: msg || '', | ||
name: token, | ||
@@ -261,0 +261,0 @@ hash, |
@@ -1,4 +0,5 @@ | ||
import { Cell, CommonMessageInfoExternalIn, CommonMessageInfoInternal, Dictionary, Message, Transaction, TransactionDescriptionGeneric } from "@ton/ton"; | ||
import { AccountStatus, Address, Cell, CommonMessageInfoExternalIn, CommonMessageInfoInternal, Dictionary, Message, Transaction, TransactionDescriptionGeneric } from "@ton/ton"; | ||
export const parse_tx = (tx: Transaction, is_testnet = false): any => { | ||
export const parse_tx = (tx: Transaction, is_testnet = false): ParsedTx => { | ||
const result = Object.create(null); | ||
@@ -22,3 +23,3 @@ result.originalTx = tx; | ||
accStatus: tx.endStatus, | ||
hash: tx.hash().toString('hex'), | ||
hash: tx.hash().toString('base64'), | ||
now: tx.now, | ||
@@ -57,2 +58,3 @@ totalFees: tx.totalFees.coins, | ||
return { | ||
wallet_id, | ||
...result | ||
@@ -67,4 +69,4 @@ } | ||
const success = tx.description.actionPhase?.success; | ||
const totalFees = tx.description.actionPhase?.totalActionFees; | ||
return { is_aborted, is_destroyed, type, success, totalFees }; | ||
const totalFeesFromdesc = tx.description.actionPhase?.totalActionFees; | ||
return { is_aborted, is_destroyed, type, success, totalFeesFromdesc }; | ||
} | ||
@@ -90,3 +92,3 @@ | ||
} | ||
Object.assign(result, parseInMessageBody(in_message.body)); | ||
@@ -115,6 +117,32 @@ | ||
function parseExternalInNessage(in_message: ExternalInMessage) { | ||
return { | ||
importFee: in_message.info.importFee | ||
const res = { | ||
importFee: in_message.info.importFee, | ||
opcode: '', | ||
timeout: -1, | ||
seqno: -1, | ||
query_id: -1, | ||
wallet_id: -1 | ||
}; | ||
try { | ||
const slice = in_message.body.beginParse().clone(); | ||
if (!slice.remainingBits) { | ||
return res; | ||
} | ||
res.opcode = '0x' + slice.loadUint(32).toString(16); | ||
switch (res.opcode) { | ||
case '0x7369676e': | ||
res.wallet_id = slice.loadUint(32); | ||
res.timeout = slice.loadUint(32); | ||
res.seqno = slice.loadUint(32); | ||
break; | ||
} | ||
} catch (e) { | ||
} | ||
return res; | ||
} | ||
@@ -143,2 +171,3 @@ | ||
const op_code = slice.loadUint(32); | ||
//const query_id = slice.loadUint(64); | ||
const remainings = slice.remainingBits; | ||
@@ -186,3 +215,3 @@ let message = ''; | ||
body.skip(64); // skip query_id | ||
const query_id = body.loadUint(64); | ||
const jettonAmount = body.loadCoins(); | ||
@@ -199,7 +228,7 @@ const jettonSender = body.loadAddressAny(); | ||
const message = forwardPayload.loadStringTail(); | ||
return { jettonSender, jettonAmount, message }; | ||
return { jettonSender, jettonAmount, message, queryId: query_id, op }; | ||
} else { | ||
// if forward payload opcode is something else: it's some message with arbitrary structure | ||
// you may parse it manually if you know other opcodes or just print it as hex | ||
return { jettonSender, jettonAmount, message: null }; | ||
return { jettonSender, jettonAmount, message: null, queryId: query_id, op }; | ||
} | ||
@@ -212,2 +241,68 @@ } | ||
type InternalInMessage = Message & { info: CommonMessageInfoInternal }; | ||
type ExternalInMessage = Message & { info: CommonMessageInfoExternalIn }; | ||
type ExternalInMessage = Message & { info: CommonMessageInfoExternalIn }; | ||
export type ParsedTx = { | ||
originalTx: Transaction, | ||
accStatus: AccountStatus, | ||
hash: string, | ||
now: number, | ||
totalFees: undefined | bigint, | ||
lt: bigint, | ||
oldStatus: AccountStatus, | ||
prevTxHash: string, | ||
prevLt: bigint, | ||
address: bigint, | ||
is_testnet: boolean, | ||
wallet_id: number, | ||
status?: 'succeeded' | 'failed', | ||
reason?: string, | ||
is_aborted: boolean, | ||
is_destroyed: boolean, | ||
type: string, | ||
success: boolean, | ||
totalFeesFromdesc?: bigint | ||
inMessage: IncomingMessage, | ||
outMessages: Array<any>; | ||
}; | ||
export type IncomingMessage = { | ||
msgType: 'external-in' | 'internal'; | ||
hash: string, | ||
sender?: string, | ||
recipient?: string, | ||
message?: string | null, | ||
tx_type: 'unknown' | 'jetton_notification' | 'jetton_request' | 'excess_ton' | 'nft_request'; | ||
jetton_notify?: { | ||
jettonAmount: bigint, | ||
jettonSender: Address, | ||
message: string | null | ||
}, | ||
jetton_req?: { | ||
jettonAmount: bigint, | ||
jettonSender: Address, | ||
message: string | null, | ||
}, | ||
} & (IncomingMessageInternal | IncomingMessageExternalIn); | ||
export type IncomingMessageInternal = { | ||
msgType: 'internal'; | ||
value: bigint, | ||
ihrFee: bigint, | ||
forwardFee: bigint, | ||
bounce: boolean, | ||
bounced: boolean, | ||
createdAt: bigint, | ||
createdLt: bigint, | ||
ihrDisabled: boolean, | ||
}; | ||
export type IncomingMessageExternalIn = { | ||
msgType: 'external-in'; | ||
importFee: bigint, | ||
opcode: string, | ||
timeout: number, | ||
seqno: number, | ||
query_id: number, | ||
wallet_id: number, | ||
} |
@@ -14,2 +14,3 @@ import { Cell } from "@ton/core"; | ||
private logger: (msg: string) => void; | ||
private currentSeqNo = -1; | ||
@@ -22,3 +23,3 @@ constructor(ton: TonInteractionV4, logger?: (msg: string) => void) { | ||
public transfer(priority: number, address: string, amount: string, name: Tokens, message?: string): Promise<{ hash: string, msgHash: string, seqno: number, lt: string }> { | ||
public transfer(priority: number, address: string, amount: string, name: Tokens, message?: string): Promise<{ msgHash: string, seqno: number }> { | ||
return this.queue.add(async () => { | ||
@@ -29,3 +30,3 @@ return this._transfer(address, amount, name, message); | ||
private _transfer(address: string, amount: string, name: Tokens, message?: string): Promise<{ hash: string, msgHash: string, seqno: number, lt: string }> { | ||
private _transfer(address: string, amount: string, name: Tokens, message?: string): Promise<{ msgHash: string, seqno: number }> { | ||
if (!this.ton.isValidAddress(address)) { | ||
@@ -41,4 +42,9 @@ return Promise.reject(`Ton transfer Fail. Address ${address} is not valid`); | ||
private async transferTon(address: string, amount: string, msg: string = ''): Promise<{ hash: string, msgHash: string, seqno: number, lt: string }> { | ||
private async transferTon(address: string, amount: string, msg: string = ''): Promise<{ msgHash: string, seqno: number }> { | ||
const bigIntAmount = strToBigInt(amount, 9); | ||
if (this.currentSeqNo !== -1) { | ||
await this.waitNewSeqNo(this.currentSeqNo); | ||
} | ||
const { message, messageHash, seqno } = await this.ton.transferTonMessage(address, bigIntAmount, msg, true); | ||
@@ -48,8 +54,8 @@ this.logger(`TON transfer ready to send ${amount} to ${address} seqno ${seqno} msghash ${messageHash}`); | ||
this.logger(`TON transfer sent ${amount} to ${address} seqno ${seqno} msghash ${messageHash}`); | ||
const data = await this.waitMsgHash(messageHash); | ||
this.logger(`TON transfer done ${amount} to ${address} seqno ${seqno} msghash ${messageHash} txhash is ${data.hash}`); | ||
return { ...data, seqno }; | ||
// const data = await this.waitMsgHash(messageHash); | ||
this.logger(`TON transfer done ${amount} to ${address} seqno ${seqno} msghash ${messageHash}`); | ||
return { msgHash: messageHash, seqno }; | ||
} | ||
private async transferJetton(address: string, amount: string, name: string, msg: string = ''): Promise<{ hash: string, msgHash: string, seqno: number, lt: string }> { | ||
private async transferJetton(address: string, amount: string, name: string, msg: string = ''): Promise<{ msgHash: string, seqno: number }> { | ||
const jettons = await this.ton.getJettonsInfo(); | ||
@@ -60,2 +66,6 @@ if (!jettons[name]) { | ||
if (this.currentSeqNo !== -1) { | ||
await this.waitNewSeqNo(this.currentSeqNo); | ||
} | ||
const bigIntAmount = strToBigInt(amount, jettons[name].decimals); | ||
@@ -73,5 +83,5 @@ const balance = await this.ton.fetchJettonWalletBalance(jettons[name].jettonMasterAddress.toRawString(), address); | ||
const data = await this.waitMsgHash(messageHash); | ||
this.logger(`Jetton ${name} transfer done ${amount} to ${address} seqno ${seqno} msghash ${messageHash} txhash is ${data.hash}`); | ||
return { ...data, seqno }; | ||
// const data = await this.waitMsgHash(messageHash); | ||
this.logger(`Jetton ${name} transfer done ${amount} to ${address} seqno ${seqno} msghash ${messageHash}`); | ||
return { msgHash: messageHash, seqno }; | ||
} | ||
@@ -81,6 +91,8 @@ | ||
const newSeqNo = await this.ton.getSeqNo(); | ||
if (newSeqNo > seqNo) { | ||
if (newSeqNo !== seqNo) { | ||
throw new Error('Invalid message Seqno is expired'); | ||
} | ||
this.currentSeqNo = newSeqNo; | ||
try { | ||
@@ -91,4 +103,2 @@ await this.ton.sendTx(msg); | ||
} | ||
await this.waitNewSeqNo(seqNo); | ||
} | ||
@@ -95,0 +105,0 @@ |
@@ -17,2 +17,3 @@ import { TonClient4, WalletContractV5R1, internal, SendMode, OpenedContract, Address, JettonMaster, JettonWallet, beginCell, toNano, external, Cell, storeMessage } from "@ton/ton"; | ||
private is_testnet = false; | ||
private txTimeDelay = 30; | ||
@@ -86,3 +87,3 @@ private constructor(client: TonClient4, key_pair: KeyPair | null, contract: OpenedContract<WalletContractV5R1> | null, jetton_settings?: Record<string, JetonSettings>, is_testnet?: boolean) { | ||
const { message, seqno, messageHash } = await this.transferJettonMessage(ton_address, jetton_master_address, amount, msg); | ||
this.contract.send(message); | ||
await this.contract.send(message); | ||
return { | ||
@@ -170,3 +171,3 @@ messageHash, | ||
const sq = res.last.seqno; | ||
const is_deploed = await this.ton_client.isContractDeployed(sq, parsed_address); | ||
const is_deploed = true || (await this.ton_client.isContractDeployed(sq, parsed_address as Address)); | ||
@@ -189,13 +190,13 @@ if (!is_deploed) { | ||
const jetton_balance = await jettonUserWalletContract.getBalance(); | ||
// const jetton_balance = await jettonUserWalletContract.getBalance(); | ||
if (jetton_balance < amount) { | ||
return Promise.reject(`Balance less than amount to transfer balance is ${jetton_balance} amount is ${amount}`); | ||
} | ||
// if (jetton_balance < amount) { | ||
// return Promise.reject(`Balance less than amount to transfer balance is ${jetton_balance} amount is ${amount}`); | ||
// } | ||
const ton_balance = await this.contract.getBalance(); | ||
// const ton_balance = await this.contract.getBalance(); | ||
if (ton_balance < BigInt(10 ** 8)) { | ||
return Promise.reject(`Ton Balance less than fee to balance is ${ton_balance} min balance is 0.1 TON`); | ||
} | ||
// if (ton_balance < BigInt(10 ** 8)) { | ||
// return Promise.reject(`Ton Balance less than fee to balance is ${ton_balance} min balance is 0.1 TON`); | ||
// } | ||
@@ -251,4 +252,6 @@ const seqno = await this.contract.getSeqno(); | ||
if (!this.contract || !this.key_pair) { | ||
throw new Error('Contract not inited'); | ||
const parsed = this.isValidAddress(address); | ||
if (!parsed) { | ||
throw new Error('Address is not valid'); | ||
} | ||
@@ -259,3 +262,3 @@ | ||
const latestBlockNumber = latestBlock.last.seqno; | ||
const { account } = await this.ton_client.getAccount(latestBlockNumber, this.contract.address); | ||
const { account } = await this.ton_client.getAccount(latestBlockNumber, parsed); | ||
const { last: lastTransaction } = account; | ||
@@ -307,3 +310,3 @@ if (!lastTransaction) { | ||
return (await client.getAccountTransactionsParsed(user_address, BigInt(params.lt), Buffer.from(params.hash, 'hex'))).transactions; | ||
return (await client.getAccountTransactionsParsed(user_address, BigInt(params.lt), Buffer.from(params.hash, 'base64'))).transactions; | ||
} | ||
@@ -474,2 +477,3 @@ | ||
const transfer = this.contract.createTransfer({ | ||
timeout: Math.floor(Date.now() / 1e3) + this.txTimeDelay, | ||
secretKey: this.key_pair.secretKey, | ||
@@ -506,4 +510,2 @@ sendMode: SendMode.PAY_GAS_SEPARATELY, | ||
} | ||
let tryes = 0; | ||
const seqno = await this.getSeqNo(); | ||
@@ -522,16 +524,2 @@ const messageHash = message.hash().toString('hex'); | ||
await wait(10000); | ||
while(true) { | ||
const seqno2 = await this.getSeqNo(); | ||
if (seqno2 > seqno) { | ||
break; | ||
} | ||
tryes++; | ||
if (tryes > 20) { | ||
throw new Error('Seqno is not changed in 2 min'); | ||
} | ||
await wait(5000); | ||
} | ||
return { | ||
@@ -538,0 +526,0 @@ messageHash, |
@@ -10,2 +10,3 @@ import { parse_tx } from './modules/txs/Transaction'; | ||
import { TransferQueue } from './modules/txs/TransferQueu'; | ||
import { TrackTxBySeqNo } from './modules/txs/TrackTxBySeqno'; | ||
@@ -31,3 +32,4 @@ export * from '@ton/core'; | ||
Address, | ||
TransferQueue | ||
TransferQueue, | ||
TrackTxBySeqNo | ||
}; |
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
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
377565
105
6368
- Removed@ton/core@0.58.1(transitive)
Updated@ton/core@^0.59.0