wietsewind's notebooks

  • XRPL Memo PoW tryout - /wietsewind/xrpl-memo-pow-tryout
    Last edited 3 months ago
    /* Based on hashcash */ const crypto = require("crypto") const alphabet = `0123456789_;:. ?!@#$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ` const next = array => { for (i = array.length - 1; i >= 0; i--) { if (array[i] < alphabet.length - 1) { array[i] += 1 return true } else { array[i] = 0 } } return false } const toSuffix = array => { return array.map(v => { return alphabet[v] }).join('') } const hash = data => { const alg = crypto.createHash('sha1') alg.update(data) return alg.digest('hex') } const findHash = obj => { const data = JSON.stringify(obj) const zeroes = Math.min(Math.ceil(data.length / 28), 10) console.log(`Looking for ${zeroes} zeroes...`) for (let l = 0; l < 25; l++) { let array = Array(l) for (let i = 0; i < l; i++) array[i] = 0 do { const appended = toSuffix(array) const challenge = data + appended const cash = hash(challenge) if (cash.match(`^0{${zeroes}}`)) { return { hash: cash, appended } } } while (next(array)) } } const hashFound = findHash({ some: 'data', more: 'things', andOther: 'stuff', for: 'XRP ledger', because: ['Safe', 'Secure', 'Cool'] }) console.log(hashFound)
  • Check XRP account address validity - /wietsewind/check-xrp-account-address-validity
    Last edited 3 months ago
    const xcodec = require('xrpl-tagged-address-codec') const rcodec = require('ripple-address-codec') const assert = require('assert') const xrplClient = require('rippled-ws-client') /* Locally, check account checksum */ const addressValid = address => { assert(typeof address === 'string', 'Invalid account address, should be string') const accountAddress = address.trim() if (accountAddress.match(/^X/)) { return (() => { try { const decoded = xcodec.Decode(accountAddress) return true } catch (e) { return false } })() } else { return rcodec.isValidAddress(accountAddress) } } /* Server side, check account activation */ const addressActivated = async address => { return new Promise((resolve, reject) => { const client = new xrplClient('wss://rippled.xrptipbot.com') client.then(connection => { connection.send({ command: 'account_info', account: address }).then(response => { if (typeof response.account_data !== 'undefined') { return resolve(response.account_data) } else { resolve(false) } connection.close() }) }).catch(reject) }) } [ 'r39wNbXPK25UJPfQiqkeeh2BRSceYHUo2C', 'XV5sbjUmgPpvXv4ixFWZ5ptAYZ6PD28Sq49uo34VyjnmK5H', 'XV5sbjUixFWZ5ptAYZ6PD28Sq49uomgPpvXv434VyjnmK5H' ].forEach(address => { console.log(`Address [ ${address} ] valid? ${addressValid(address) ? 'YES' : 'NO'}`) }); [ 'rPEPPER7kfTD9w2To4CQk6UCfuHM9c6GDY', 'r39wNbXPK25UJPfQiqkeeh2BRSceYHUo2C' ].forEach(address => { addressActivated(address).then(activated => { console.log(`Account [ ${address} ] activated? ${activated ? 'YES' : 'NO'}`) }) });
  • Account address prefix - /wietsewind/account-address-prefix
    Last edited 3 months ago
    const codec = require('ripple-address-codec') const findPrefix = (desiredPrefix, payloadLength) => { const rippleCodec = codec.codecs.ripple if (rippleCodec.base !== 58) { throw new Error('Only works for base58') } const factor = Math.log(256) / Math.log(rippleCodec.base) const totalLength = payloadLength + 4 // for checksum const chars = totalLength * factor const requiredChars = Math.ceil(chars + 0.2) const alphabetPosition = Math.floor((rippleCodec.alphabet.length) / 2) - 1 const padding = rippleCodec.alphabet[alphabetPosition] const rcPad = new Array(requiredChars + 1).join(padding) const template = desiredPrefix + rcPad const bytes = rippleCodec.decodeRaw(template) const version = bytes.slice(0, -totalLength) return version } console.log(findPrefix('X', 29))
  • Encode/Decode tagged XRPL addresses & destination tag - /wietsewind/encode-decode-tagged-xrpl-addresses-destination-tag
    Last edited 3 months ago
    const {Encode, Decode} = require('xrpl-tagged-address-codec') const tagged = Encode({ account: 'rPEPPER7kfTD9w2To4CQk6UCfuHM9c6GDY', tag: 495 }) console.log(tagged) const untagged = Decode(tagged) console.log(untagged)
  • XRPL X-Encoded address decode (API) - /wietsewind/xrpl-x-encoded-address-decode-api
    Last edited 3 months ago - from: https://xrpaddress.info/
    const fetch = require('node-fetch') fetch('https://xrpaddress.info/api/decode/XV5sbjUmgPpvXv4ixFWZ5ptAYZ6PD2q1qM6owqNbug8W6KV').then(r => { console.log('CDN endpoint: ' + r.headers.raw()['x-now-trace']) return r.json() }).then(r => { console.log(r) })
  • XRP Ledger Orderbook map/reduce - /wietsewind/xrp-ledger-orderbook-map-reduce
    Last edited 3 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 Wallet Generator (raw) - /wietsewind/ripple-wallet-generator-raw
    Last edited 3 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
  • Mnemonic with ripple-keypairs, w/o ripplelib - /wietsewind/mnemonic-with-ripple-keypairs-w-o-ripplelib
    Last edited 3 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)
  • Decode Signed XRP TX - /wietsewind/decode-signed-xrp-tx
    Last edited 3 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))
  • Ripple Mnemonic wallet generator - /wietsewind/ripple-mnemonic-wallet-generator
    Last edited 3 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