wietsewind's notebooks

  • Calc XRPL Check ID - /wietsewind/calc-xrpl-check-id
    Last edited 20 days ago
    const crypto = require('crypto') const ra = require('ripple-address-codec') const a = Buffer.from('0043', 'hex') const b = ra.decodeAccountID('rtaBqey87MpBcbrbv3qjtNCUchwag2vMv') const c = Buffer.alloc(4) c.writeUInt32BE(225) // Create Sequence const all = Buffer.concat([a, b, c]) console.log(all) const sha = crypto.createHash('sha512').update(all) const result = sha.digest('hex') console.log(result.toUpperCase().slice(0, 64))
  • Monitor XRPL Testnet Servers - /wietsewind/monitor-xrpl-testnet-servers
    Last edited a month ago
    const WebSocket = require('websocket').client const ServersToTest = [ 'testnet.xrpl-labs.com', 's.altnet.rippletest.net:51233' ] exports.endpoint = (request, response) => { Promise.all(ServersToTest.map(Server => { return new Promise((resolve, reject) => { let WsInstance = new WebSocket() WsInstance.connect('wss://' + Server) WsInstance.on('connectFailed', error => { console.log('Connect Error ' + Server, error.toString()) resolve({ server: Server, status: 'ConnectError', data: null, errorData: error.toString() }) }) WsInstance.on('connect', c => { // console.log('Connected ' + Server, c) c.on('message', m => { let data = JSON.parse(m.utf8Data) // console.log('Message ' + Server, data) resolve({ server: Server, status: 'Response', data: data, errorData: null }) c.close() }) c.on('close', () => { // console.log('Closed ' + Server) }) c.on('error', e => { console.log('Error ' + Server, e.toString()) resolve({ server: Server, status: 'MsgError', data: null, errorData: e.toString() }) }) c.send(JSON.stringify({ command: 'server_info' })) setTimeout(() => { c.close() resolve({ server: Server, status: 'Timeout', data: null, errorData: null }) }, 5000) }) }) })).then(Results => { // Running in the browser, respond let highestLedger = Math.max.apply(Math, Results.filter(r => { return r.status === 'Response' && r.data !== null && r.data.result.info.complete_ledgers.match(/[0-9]/) }).map(r => { return parseInt(r.data.result.info.complete_ledgers.split(',').reverse()[0].split('-').reverse()[0]) }).filter(r => { return !isNaN(r) })) let OutputData = { highestLedger: highestLedger, responses: Object.assign({}, ...Results.map(r => { let lastLedger = 0 if (r.data !== null) { lastLedger = parseInt(r.data.result.info.complete_ledgers.split(',').reverse()[0].split('-').reverse()[0]) if (isNaN(lastLedger)) lastLedger = 0 } return { [r.server.replace(/[^a-z0-9]/g, '')]: Object.assign(r, { lastLedger: lastLedger, ledgerOffset: highestLedger - lastLedger }) } })) } if (response !== null) { response.end(JSON.stringify(OutputData)) } else { // Running in the console. Log. console.log('Done', OutputData) } }).catch(Error => { }) } // When in the browser... exports.endpoint(null, null)
  • Test rippled instance (Endpoint) - /wietsewind/test-rippled-instance-endpoint
    Last edited a month ago
    const WebSocket = require('websocket').client const ServersToTest = [ 'rippled-dev.xrpayments.co', 'rippled.xrptipbot.com', 's1.ripple.com' ] exports.endpoint = (request, response) => { Promise.all(ServersToTest.map(Server => { return new Promise((resolve, reject) => { let WsInstance = new WebSocket() WsInstance.connect('wss://' + Server) WsInstance.on('connectFailed', error => { console.log('Connect Error ' + Server, error.toString()) resolve({ server: Server, status: 'ConnectError', data: null, errorData: error.toString() }) }) WsInstance.on('connect', c => { // console.log('Connected ' + Server, c) c.on('message', m => { let data = JSON.parse(m.utf8Data) // console.log('Message ' + Server, data) resolve({ server: Server, status: 'Response', data: data, errorData: null }) c.close() }) c.on('close', () => { // console.log('Closed ' + Server) }) c.on('error', e => { console.log('Error ' + Server, e.toString()) resolve({ server: Server, status: 'MsgError', data: null, errorData: e.toString() }) }) c.send(JSON.stringify({ command: 'server_info' })) setTimeout(() => { c.close() resolve({ server: Server, status: 'Timeout', data: null, errorData: null }) }, 5000) }) }) })).then(Results => { // Running in the browser, respond let highestLedger = Math.max.apply(Math, Results.filter(r => { return r.status === 'Response' && r.data !== null && r.data.result.info.complete_ledgers.match(/[0-9]/) }).map(r => { return parseInt(r.data.result.info.complete_ledgers.split(',').reverse()[0].split('-').reverse()[0]) }).filter(r => { return !isNaN(r) })) let OutputData = { highestLedger: highestLedger, responses: Object.assign({}, ...Results.map(r => { let lastLedger = 0 if (r.data !== null) { lastLedger = parseInt(r.data.result.info.complete_ledgers.split(',').reverse()[0].split('-').reverse()[0]) if (isNaN(lastLedger)) lastLedger = 0 } return { [r.server.replace(/[^a-z0-9]/g, '')]: Object.assign(r, { lastLedger: lastLedger, ledgerOffset: highestLedger - lastLedger }) } })) } if (response !== null) { response.end(JSON.stringify(OutputData)) } else { // Running in the console. Log. console.log('Done', OutputData) } }).catch(Error => { }) } // When in the browser... exports.endpoint(null, null)
  • Mnemonic with ripple-keypairs, w/o ripplelib - /wietsewind/mnemonic-with-ripple-keypairs-w-o-ripplelib
    Last edited a month ago
    const bip39 = require("bip39"); const bip32 = require("ripple-bip32"); const ripple = require('ripple-keypairs') var mnemonic = 'novel matter final only nice cheese address cradle civil crash great flame struggle consider crowd surface purpose saddle mango endless mixed trial tape wrap' // Or generate: // mnemonic = bip39.generateMnemonic() console.log('mnemonic: ' + mnemonic) const seed = bip39.mnemonicToSeed(mnemonic) // add second argument for 25th word encrypted // console.log('seed: ', seed) const m = bip32.fromSeedBuffer(seed) // console.log('m: ', m) const keyPair = m.derivePath("m/44'/144'/0'/0/0").keyPair.getKeyPairs() const address = ripple.deriveAddress(keyPair.publicKey) console.log('privateKey: ' + keyPair.privateKey) console.log('publicKey: ' + keyPair.publicKey) console.log('address: ' + address)
  • HEX Private key to address with ripple-lib - /wietsewind/hex-private-key-to-address-with-ripple-lib
    Last edited a month ago
    const keypairs = require('ripple-keypairs') const elliptic = require('elliptic') const secp256k1 = elliptic.ec('secp256k1') const ed25519 = elliptic.eddsa('ed25519') function bytesToHex(a) { return a.map(function(byteValue) { const hex = byteValue.toString(16).toUpperCase() return hex.length > 1 ? hex : '0' + hex }).join('') } /* secp256k1 */ let secp256k1_privateKey = '00' + '0762EED5BA4F378FFA60621C6DEF72F4A0A579112ADA5F5D6B2A35EC27E893A5' let secp256k1_keypair = { privateKey: secp256k1_privateKey, publicKey: bytesToHex(secp256k1.keyFromPrivate(secp256k1_privateKey.slice(2)).getPublic().encodeCompressed()), } console.log('secp256k1 Keypair, Address ', secp256k1_keypair, keypairs.deriveAddress(secp256k1_keypair.publicKey)) /* ed25519 */ let ed25519_privateKey = 'ED' + '3AD7B2EC2CFD134C500867164E4E257FD703C2CF4915E93A8CFC0CC7C2DBA46B' let ed25519_keypair = { privateKey: ed25519_privateKey, publicKey: 'ED' + bytesToHex(ed25519.keyFromSecret(ed25519_privateKey.slice(2)).pubBytes()), } console.log('ed25519 Keypair, Address ', ed25519_keypair, keypairs.deriveAddress(ed25519_keypair.publicKey))
  • Get GH XRPL Tx Types - /wietsewind/get-gh-xrpl-tx-types
    Last edited 2 months ago
    const Fetch = require('node-fetch') const getTransactionTypes = async () => { const dirList = await Fetch('https://api.github.com/repos/ripple/xrpl-dev-portal/contents/content/references/rippled-api/transaction-formats/transaction-types').then(r => r.json()) const relevantFiles = dirList.filter(r => r.name.match(/^[a-zA-Z]+\.md$/)) return Promise.all(relevantFiles.map(async f => { const source = await Fetch(f.download_url).then(r => r.text()) return { transactionType: source.match(/^# ([a-zA-Z]+)/gm)[0].slice(2), docLink: 'https://xrpl.org/' + f.name.split('.')[0] + '.html', codeSamples: source.split(`\n`).join(' ').match(/```.+?```/gm) .map(s => s.split('```')[1].trim().replace(/^json[\n]*/gm, '')) .map(s => s.replace(/,[ \t\n\\t\\n]*}$/, '}')) .map(s => { try { return JSON.parse(s) } catch (e) { return s } }) } })) } const transactionTypes = await getTransactionTypes() console.log(transactionTypes)
  • Finishable XRPL Escrows - /wietsewind/finishable-xrpl-escrows
    Last edited 2 months ago
    const Fetch = require('node-fetch') const Client = require('rippled-ws-client') const Sign = require('rippled-ws-client-sign') const Seed = process.argv[2] || '' new Client('wss://xrpl.ws').then(Connection => { Fetch('https://ledger.exposed/api/escrowlist').then(r => r.json()).then(Escrows => { const ToFinish = Escrows.filter(Escrow => { return Escrow.FinishAfter <= Math.round((new Date()) / 1000) - 946684800 && Escrow.Condition === undefined }).slice(0, 1) ToFinish.forEach(Escrow => { Connection.send({ command: 'account_objects', account: Escrow.Account, limit: 400 }).then(AccountObjects => { const Escrows = AccountObjects.account_objects.filter(Obj => Obj.LedgerEntryType === 'Escrow') Escrows.forEach(Escrow => { Connection.send({ command: 'tx', transaction: Escrow.PreviousTxnID }).then(CreateTx => { const FinishJson = { Account: 'rPEPPER7kfTD9w2To4CQk6UCfuHM9c6GDY', TransactionType: 'EscrowFinish', Owner: Escrow.Account, OfferSequence: CreateTx.Sequence } new Sign(FinishJson, Seed, Connection) .then(TransactionSuccess => { console.log('TransactionSuccess', TransactionSuccess) }).catch(SignError => { console.log('SignError', SignError.details) }) }) }) }) }) }) })
  • XRPL Buffer to Seed to Account - /wietsewind/xrpl-buffer-to-seed-to-account
    Last edited 2 months ago
    const kp = require('ripple-keypairs') const hex = '0123456789ABCDEF0123456789ABCDEF' const entropy = Buffer.from(hex, 'hex') console.log(entropy) const secret = kp.generateSeed({entropy}) const pair = kp.deriveKeypair(secret) const wallet = kp.deriveAddress(pair.publicKey) console.log('Secret', secret) console.log('Address', wallet)
  • Sign XRP TX using HEX privateKey - /wietsewind/sign-xrp-tx-using-hex-privatekey
    Last edited 2 months ago
    const ripple = require('ripplelib') const sign = require('ripple-sign-keypairs') // NOTE! ripplelib isn't working in Safari 10.1 (wrong public key generated from private key) - use // ripple-keypairs, as displayed in: // > https://runkit.com/wietsewind/hex-private-key-to-address-with-ripple-lib // > https://runkit.com/wietsewind/mnemonic-with-ripple-keypairs-w-o-ripplelib var privateKey = '0762EED5BA4F378FFA60621C6DEF72F4A0A579112ADA5F5D6B2A35EC27E893A5' const key = ripple.KeyPair.from_json(privateKey) const keyPair = { privateKey: '00' + key.to_hex_pri(), publicKey: key.to_hex_pub() } console.log('privateKey: ' + keyPair.privateKey) console.log('privateKeyWif: ' + key.to_pri_string()) // to_wif console.log('publicKey: ' + keyPair.publicKey) console.log('address: ' + key.to_address_string()) // // Now sign a transaction... // var tx = { // TransactionType: 'Payment', // Account: key.to_address_string(), // Fee : (0.000012 * 1000 * 1000) + '', // Destination: 'rPEPPER7kfTD9w2To4CQk6UCfuHM9c6GDY', // DestinationTag : 2, // Amount: (1 * 1000 * 1000) + '', // Sequence: 0 // } // var txJSON = JSON.stringify(tx) // var txSign = sign(txJSON, keyPair) // console.log(txSign) // return txSign
  • Reserved - /wietsewind/reserved
    Last edited 3 months ago
    const Client = require('rippled-ws-client') const account = 'rPyFs5kpbiiawSdP9JGdaYM33zfUUah1TY' // const account = 'rPdvC6ccq8hCdPKSPJkPmyZ4Mi1oG2FFkT' const c = new Client('wss://xrpl.link').then(Connection => { Connection.send({ command: 'account_tx', account: account }).then(txs => { console.log('Got', txs.transactions.length) if (typeof txs.transactions !== 'undefined' && txs.transactions && txs.transactions.length > 0) { const incomingTxs = txs.transactions.filter(tx => { return tx.tx.Destination === account }) const incomingTxCountWithTag = incomingTxs.filter(tx => { return typeof tx.tx.TransactionType === 'string' && typeof tx.tx.DestinationTag !== 'undefined' }).length const senders = txs.transactions.map(tx => { return tx.tx.Account || '' }) const uniqueSenders = senders.filter((elem, pos) => { return senders.indexOf(elem) === pos }).length const percentageTag = Math.round(incomingTxCountWithTag / incomingTxs.length * 100) console.log('Unique senders: ' + uniqueSenders) console.log('With tag: ' + incomingTxCountWithTag) console.log('Percentage: ' + percentageTag) if (uniqueSenders >= 10 && percentageTag > 50) { console.log('This is most likely an exchange or custodian, tag required') } else { console.log('Tag is probably not required...') } } Connection.close() }).catch(e => console.log(e.message)) })