wietsewind's notebooks

  • Safe Char number encoding / decoding - /wietsewind/safe-char-number-encoding-decoding
    Last edited 3 months ago
    const chars = 'abcdehlkmrtwxyz3469'.toUpperCase() // const i = 19880108151231 const i = 1002558 console.log(i) const to = (decimal) => { let out = '' while (true) { let remainder = (decimal - 1) % chars.length out = chars[remainder] + out; decimal = Math.floor((decimal - 1) / chars.length); if (decimal === 0) break } return out; } let t = to(i) console.log(i + ' (' + to(i % 13) + ') ' + t) console.log('eg. \'' + i + '.' + to(i % 13) + t + '\'') const from = (alpha) => { const crs = chars.split('') const letters = alpha.split('') let out = 0 for (let i = 0; i < letters.length; i++) { let indexPos = crs.indexOf(letters[letters.length - 1 - i]) out += (indexPos + 1) * Math.pow(crs.length, i) } return out } let f = from(t) console.log(t + ' = ' + f + ' (' + to(f % 13) + ')')
  • XRP Ledger Orderbook map/reduce - /wietsewind/xrp-ledger-orderbook-map-reduce
    Last edited 4 months ago
    const XRPLClient = require('rippled-ws-client') // Added: respect "owner_funds", offer may be > funds // (only the highest-ranked offer includes this field, so: keep per-account balance looping // through the offers) // Same: taker_gets_funded / taker_pays_funded const precision = 4 const currency = { // issuer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B', // Bitstamp USD issuer: 'rhub8VRN55s94qWKDv6jmDy1pUykJzF3wq', // Gatehub USD currency: 'EUR' } new XRPLClient('wss://rippled.xrptipbot.com').then(connection => { console.log(`Connected. Fetching orderbook for ${currency.currency}.${currency.issuer}\n - Precision: ${precision}\n`) Promise.all([ 'Gets', 'Pays' ].map(book => { return new Promise((resolve, reject) => { connection.send({ command: 'book_offers', limit: 1000, [ 'taker_' + book.toLowerCase() ]: { currency: 'XRP' }, [ 'taker_' + (book === 'Gets' ? 'pays' : 'gets') ]: currency }).then(result => { let offers = result.offers.map(r => { let xrp = parseInt(r[ 'taker_' + book.toLowerCase() + '_funded' ] || r[ 'Taker' + book ]) / 1000000 let currField = typeof r[ 'taker_' + (book === 'Gets' ? 'pays' : 'gets') + '_funded' ] !== 'undefined' ? r[ 'taker_' + (book === 'Gets' ? 'pays' : 'gets') + '_funded' ] : r[ 'Taker' + (book === 'Gets' ? 'Pays' : 'Gets') ] let curr = parseFloat(currField.value) if (typeof r.owner_funds !== 'undefined') { let ownerFunds = parseFloat(r.owner_funds) if (book === 'Gets') { // XRP ownerFunds = ownerFunds / 1000000 // console.log(`${book} xrp ${xrp} ${ownerFunds}`) xrp = Math.min(xrp, ownerFunds) } else { // console.log(`${book} curr ${curr} ${ownerFunds}`) curr = Math.min(curr, ownerFunds) } } let rate = curr / xrp return { book: book, rate: rate, roundedRate: Math.round(rate * 10 ** precision) / 10 ** precision, value: { currency: curr, xrp: xrp } } }) resolve({ [book.toLowerCase()]: { offers: offers, offerCount: offers.length, startRate: offers[0].roundedRate, book: offers.reduce((a, b) => { let existingAtRate = a.filter(match => { return match.rate === b.roundedRate }) if (existingAtRate.length > 0) { // Increase existing book value a[a.indexOf(existingAtRate[0])].amountXrp += b.value.xrp } else { // New rate a.push({ rate: b.roundedRate, amountXrp: b.value.xrp }) } return a }, []) } }) }).catch(reject) }) })).then(results => { results = results.reduce((a, b) => { return Object.assign(a, { ...b }) }, {}) console.log(`Taker GETS # offers: ${results.gets.offerCount}, starting at: ${results.gets.startRate} ${currency.currency} / XRP\n`, results.gets.book.slice(0, 15)) console.log(`Taker PAYS # offers: ${results.pays.offerCount}, starting at: ${results.pays.startRate} ${currency.currency} / XRP\n`, results.pays.book.slice(0, 15)) connection.close().then(() => { console.log('Closed connection.') }) }) }).catch(console.error)
  • Ripple-lib valid addr. (promise) - /wietsewind/ripple-lib-valid-addr-promise
    Last edited 4 months ago
    const RippleAPI = require('ripple-lib').RippleAPI const RippleAddressCodec = require('ripple-address-codec') const api = new RippleAPI({ server: 'wss://s2.ripple.com:443' }) /** * Note: isValidAddress will probably be exposed in a future ripple-lib release at api level. */ api.connect().then(() => { return new Promise((resolve, reject) => { if (RippleAddressCodec.isValidAddress("rBwdSqfFMBYUazUsv9pV1ZpHTG2nZcaNJv")) { resolve(true) } else { reject(new Error('Invalid XRPL account')) } }) }).then(r => { console.log('Valid?', r) }).then(() => { console.log('Disconnect') api.disconnect() }) .catch(e => console.log("Caught error", e))
  • Test rippled instance (Endpoint) - /wietsewind/test-rippled-instance-endpoint
    Last edited 4 months 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)
  • Get Account Transactions with ripple-lib - /wietsewind/get-account-transactions-with-ripple-lib
    Last edited 5 months ago
    const RippleAPI = require('ripple-lib').RippleAPI const api = new RippleAPI({ server: 'wss://rippled.xrptipbot.com' }) api.connect().then(() => { api.getServerInfo().then(server => { console.log('Connected', server) api.getTransactions('rf8kg7r5Fc8cCszGdD2jeUZt2FrgQd76BS', { limit: 10, earliestFirst: true }).then(transactions => { console.log(transactions) api.disconnect() }).catch(console.error) }) }).catch(console.error)
  • Ripple Mnemonic wallet generator - /wietsewind/ripple-mnemonic-wallet-generator
    Last edited 7 months ago
    const bip39 = require("bip39"); const bip32 = require("ripple-bip32"); 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 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) const m = bip32.fromSeedBuffer(seed) const keyPair = m.derivePath("m/44'/144'/0'/0/0").keyPair.getKeyPairs() const key = ripple.KeyPair.from_json(keyPair.privateKey.substring(2)) 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) return txSign
  • Decode Signed XRP TX - /wietsewind/decode-signed-xrp-tx
    Last edited 7 months ago
    const codec = require('ripple-binary-codec') const hashes = require('ripple-hashes') const tx = '1200032280000000240000003241833237B8665D2F4E00135E8DE646589F68400000000000000C732103709723A5967EAAED571B71DB511D87FA44CC7CDDF827A37F457A25E14D862BCD74473045022100C6A6999BD33153C6A236D78438D1BFEEEC810CFE05D0E41339B577560C9143CA022074F07881F559F56593FF680049C12FC3BCBB0B73CE02338651522891D95886F981146078086881F39B191D63B528D914FEA7F8CA2293F9EA7C06636C69656E747D15426974686F6D7020746F6F6C20762E20302E302E337E0A706C61696E2F74657874E1F1' let transactionId = hashes.computeBinaryTransactionHash(tx) let transaction = codec.decode(tx) console.log('Transaction ID', transactionId) console.log('Transaction', transaction) // console.log('Transaction (JSON)', JSON.stringify(transaction))
  • Mnemonic with ripple-keypairs, w/o ripplelib - /wietsewind/mnemonic-with-ripple-keypairs-w-o-ripplelib
    Last edited 7 months 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)
  • Ripple Wallet Generator (raw) - /wietsewind/ripple-wallet-generator-raw
    Last edited 7 months ago
    const crypto = require('crypto') const rippleSecretCodec = require('ripple-secret-codec') const rippleKeypairs = require('ripple-keypairs') const ripple = require('ripple-lib').RippleAPI const rippleApi = new ripple() var passphrase = 'masterpassphrase' // Create a SHA512 hash from the `passphrase` var hash = crypto.createHash('sha512').update(passphrase).digest('hex').toUpperCase() // Get the first 32 chars var hexSeed = hash.substring(0,32) // Encode in base58 with Ripple-aphabet. Here's our secret console.log('hexSeed: ' + hexSeed) var secret = rippleSecretCodec.encodeHex(hexSeed).secret_b58 console.log('Secret: ' + secret) // Generate keypair with secret var keypair = rippleKeypairs.deriveKeypair(secret) // Retrieve the wallet address var address = rippleKeypairs.deriveAddress(keypair.publicKey) // Create object with secret & wallet address var wallet = { address: address, secret: secret } console.log('Passphrase: ' + passphrase) console.log('Address: ' + address) // Now sign a transaction... var tx = { TransactionType: 'Payment', Account: address, Fee : (0.000012 * 1000 * 1000) + '', Destination: 'rPEPPER7kfTD9w2To4CQk6UCfuHM9c6GDY', DestinationTag : 2, Amount: (1 * 1000 * 1000) + '', Sequence: 0 } var txJSON = JSON.stringify(tx) var txSign = rippleApi.sign(txJSON, secret) return txSign
  • Generate Ripple Wallet - /wietsewind/generate-ripple-wallet
    Last edited 7 months ago
    const keypairs = require('ripple-keypairs') const secret = keypairs.generateSeed() const keypair = keypairs.deriveKeypair(secret) const address = keypairs.deriveAddress(keypair.publicKey) console.log(secret, keypair, address)