update testnet node address because it moved
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
import { Instructions, LedgerClosedEvent, RippleAPI } from 'ripple-lib'
|
||||
import { Memo, Wallet } from '../util/types'
|
||||
import { MIN_XRP_FEE, MIN_XRP_TX_VALUE } from '../util/protocol.constants';
|
||||
import * as zlib from 'zlib'
|
||||
import * as util from 'util'
|
||||
import { Payment } from 'ripple-lib/dist/npm/transaction/payment';
|
||||
|
||||
const chunkString = (str: string, length: number) => str.match(new RegExp('.{1,' + length + '}', 'gs'));
|
||||
const PAYLOAD_SIZE = 925
|
||||
const debug = false
|
||||
|
||||
const cloneApi = async (api: RippleAPI): Promise<RippleAPI> => {
|
||||
const subApi = new RippleAPI({ server: api.connection['_url'] })
|
||||
await subApi.connect()
|
||||
return subApi
|
||||
}
|
||||
|
||||
export const getLatestSequence = async (api: RippleAPI, accountAddress: string): Promise<number> => {
|
||||
if(debug) console.log("Getting acc info for", accountAddress)
|
||||
const accountInfo = await api.getAccountInfo(accountAddress, {})
|
||||
return Number(accountInfo.sequence-1)
|
||||
}
|
||||
|
||||
const compressB64 = async (data: string) => (await util.promisify(zlib.deflate)(Buffer.from(data, 'utf-8'))).toString('base64')
|
||||
const decompressB64 = async (data: string) => (await util.promisify(zlib.inflate)(Buffer.from(data, 'base64'))).toString('utf-8')
|
||||
|
||||
const sendReliably = (api: RippleAPI, signed: any, preparedPayment,): Promise<any> => new Promise((res, rej) => {
|
||||
const ledgerClosedCallback = async (event: LedgerClosedEvent) => {
|
||||
let status
|
||||
try {
|
||||
status = await api.getTransaction(signed.id, {
|
||||
minLedgerVersion: 20368096
|
||||
})
|
||||
} catch (e) {
|
||||
|
||||
// Typical error when the tx hasn't been validated yet:
|
||||
if ((e as Error).name !== 'MissingLedgerHistoryError') {
|
||||
//console.log(e)
|
||||
}
|
||||
|
||||
if (event.ledger_index > preparedPayment.instructions.maxLedgerVersion + 3) {
|
||||
// Assumptions:
|
||||
// - We are still connected to the same rippled server
|
||||
// - No ledger gaps occurred
|
||||
// - All ledgers between the time we submitted the tx and now have been checked for the tx
|
||||
status = {
|
||||
finalResult: 'Transaction was not, and never will be, included in a validated ledger'
|
||||
}
|
||||
rej(status);
|
||||
|
||||
} else {
|
||||
// Check again later:
|
||||
api.connection.once('ledgerClosed', ledgerClosedCallback)
|
||||
return
|
||||
}
|
||||
}
|
||||
res(status)
|
||||
}
|
||||
api.connection.once('ledgerClosed', ledgerClosedCallback)
|
||||
})
|
||||
|
||||
export const sendPayment = async (api: RippleAPI, data: Memo[], from: string, to: string, secret: string, sequence: number) => {
|
||||
if(debug) console.log("Sending payment with seq", sequence)
|
||||
const options: Instructions = {
|
||||
maxLedgerVersionOffset: 5,
|
||||
fee: MIN_XRP_FEE,
|
||||
sequence: sequence,
|
||||
};
|
||||
const payment: Payment = {
|
||||
source: {
|
||||
address: from,
|
||||
maxAmount: {
|
||||
value: MIN_XRP_TX_VALUE,
|
||||
currency: 'XRP'
|
||||
},
|
||||
},
|
||||
destination: {
|
||||
address: to,
|
||||
amount: {
|
||||
value: MIN_XRP_TX_VALUE,
|
||||
currency: 'XRP'
|
||||
},
|
||||
},
|
||||
memos: data,
|
||||
};
|
||||
try {
|
||||
const _api = await cloneApi(api)
|
||||
const prepared = await _api.preparePayment(from, payment, options)
|
||||
const signed = _api.sign(prepared.txJSON, secret);
|
||||
const txHash = await _api.submit(signed.signedTransaction)
|
||||
if(debug) console.log("Transaction submitted", txHash)
|
||||
await sendReliably(_api, signed, prepared)
|
||||
_api.disconnect()
|
||||
|
||||
return txHash
|
||||
} catch (error) {
|
||||
//console.log("SENDPAYMENT ERROR", error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export const getTransactions = async (api: RippleAPI, address: string, minLedgerVersion: number = 19832467): Promise<any[]> => {
|
||||
const txs = await api.getTransactions(address, {
|
||||
minLedgerVersion: minLedgerVersion,
|
||||
earliestFirst: true,
|
||||
excludeFailures: true,
|
||||
})
|
||||
return txs
|
||||
}
|
||||
|
||||
export const writeRaw = async (api: RippleAPI, data: Memo, from: string, to: string, secret: string, sequence?: number): Promise<string> => {
|
||||
//if (memoSize(data) > 1000) throw new Error("data length exceeds capacity")
|
||||
try {
|
||||
if (!sequence) {
|
||||
const accountInfo = await getLatestSequence(api, from)
|
||||
sequence = accountInfo + 1
|
||||
}
|
||||
|
||||
const resp = await sendPayment(api, [data], from, to, secret, sequence)
|
||||
return resp['tx_json'].hash
|
||||
} catch (error) {
|
||||
console.log("WRITERAW ERR", error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const readRaw = async (api: RippleAPI, hash: string): Promise<Memo> => {
|
||||
const tx = await api.getTransaction(hash, {
|
||||
minLedgerVersion: 16392480
|
||||
})
|
||||
if (!tx || !tx.specification || !tx.specification['memos'] || !tx.specification['memos'][0]) {
|
||||
throw new Error('Invalid Transaction ' + hash)
|
||||
}
|
||||
|
||||
return tx.specification['memos'][0]
|
||||
}
|
||||
|
||||
export const subscribe = async (api: RippleAPI, address: string, callback: (tx) => any) => {
|
||||
api.connection.on('transaction', (tx) => callback(tx))
|
||||
await api.connection.request({
|
||||
command: 'subscribe',
|
||||
accounts: [address],
|
||||
})
|
||||
}
|
||||
|
||||
export const treeWrite = async (api: RippleAPI, data: string, wallet: Wallet, to: string, format: 'L'|'N' = 'L'): Promise<string> => {
|
||||
data = await compressB64(data)
|
||||
const chunks = chunkString(data, PAYLOAD_SIZE)
|
||||
const latestSequence = await getLatestSequence(api, wallet.address)
|
||||
const hashes = await Promise.all(Object.entries(chunks).map(([i, chunk]) => writeRaw(api, { data: chunk, format: format }, wallet.address, to, wallet.secret, latestSequence + Number(i) + 1)))
|
||||
|
||||
if (hashes.length === 1) {
|
||||
return hashes[0]
|
||||
}
|
||||
|
||||
return await treeWrite(api, JSON.stringify(hashes), wallet, to, 'N')
|
||||
}
|
||||
|
||||
export const treeRead = async (api: RippleAPI, hashes: string[]): Promise<string> => {
|
||||
const memos = await Promise.all(hashes.map(hash => readRaw(api, hash)))
|
||||
const payload: string = await decompressB64(memos.map(memo => memo.data).join(''))
|
||||
|
||||
if (memos.some(memo => memo.format === 'N')) {
|
||||
return await treeRead(api, JSON.parse(payload))
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
Reference in New Issue
Block a user