wietsewind's notebooks

  • Get XRPL Exchanged Value - /wietsewind/get-xrpl-exchanged-value
    Last edited 2 days ago
    const Client = require('rippled-ws-client') const TxParser = require('ripple-lib-transactionparser') const main = async () => { console.log('Connecting') const connection = await new Client('wss://xrpl.ws') console.log('Connected, requesting transaction') const transaction = await connection.send({ command: 'tx', transaction: '63488A0526DC0196AB89DD7DAE2A972A2E75808086287C02587603E8C46B6532' }) console.log('Tx by Account', transaction.Account) console.log(TxParser.parseBalanceChanges(transaction.meta)[transaction.Account]) return connection.close() } main()
  • Verify XRPL Signature (XUMM) - /wietsewind/verify-xrpl-signature-xumm
    Last edited 8 days ago
    const verifySignature = require('verify-xrpl-signature').verifySignature const someTx = '228000000024000000D568400000000000000C732102C71103C10E706EFCBACDBC1A1F505D0421369CD625A9953990393E14202DC15274463044022035B6ABAC593979FBB745E8DB71B2CCDC255220EFE03ECC9037F7E0DA6356F0A302201119ED7F26D4131A2E24607B60911ED7E01571FD82F433640562C755135D397981146C09EF73F2C503101303D9716D3209A90732ACBD' // { // "Flags": 2147483648, // "Sequence": 213, // "Fee": "12", // "SigningPubKey": "02C71103C10E706EFCBACDBC1A1F505D0421369CD625A9953990393E14202DC152", // "TxnSignature": "3044022035B6ABAC593979FBB745E8DB71B2CCDC255220EFE03ECC9037F7E0DA6356F0A302201119ED7F26D4131A2E24607B60911ED7E01571FD82F433640562C755135D3979", // "Account": "rwiEtsEY8YRxgHQgvWXsxyUBSZzTMqL2EX" // } console.log(verifySignature(someTx)) // In case of explicit MultiSign signer verification: // console.log(verifySignature(someTx, 'rwiETSee2wMz3SBnAG8hkMsCgvGy9LWbZ1'))
  • Ripple Wallet Generator (raw) - /wietsewind/ripple-wallet-generator-raw
    Last edited a month 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
  • Coil monetization to UUID - /wietsewind/coil-monetization-to-uuid
    Last edited 3 months ago
    const uuidParse = require('uuid-parse') const base64url = require('base64url') const urlPart = 'Jgsl3HHISgu9oP9T2IwLOg' const bytes = base64url.toBuffer(urlPart) console.log(bytes) const uuid = uuidParse.unparse(bytes) console.log('Decoded: ' + uuid) console.log('Reversed: ' + base64url.fromBase64(Buffer.from(uuidParse.parse(uuid)).toString('base64')))
  • XRPL Memo PoW tryout - /wietsewind/xrpl-memo-pow-tryout
    Last edited 8 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 8 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 8 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 8 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 8 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 8 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)