|
| 1 | +/** |
| 2 | + * StrKey examples for ALL supported types in js-stellar-base: |
| 3 | + * G: ed25519PublicKey |
| 4 | + * S: ed25519SecretSeed |
| 5 | + * M: med25519PublicKey (muxed account, 32-byte ed25519 + 8-byte ID) |
| 6 | + * T: preAuthTx (32-byte hash) |
| 7 | + * X: sha256Hash (32-byte hash) |
| 8 | + * P: signedPayload (32-byte ed25519 + 4-byte len + payload[4..64]) |
| 9 | + * C: contract (32-byte) |
| 10 | + * L: liquidityPool (32-byte) |
| 11 | + * B: claimableBalance (1-byte discriminant + 32-byte hash) |
| 12 | + * |
| 13 | + * Run: |
| 14 | + * npm i stellar-base |
| 15 | + * node strkey-examples.mjs |
| 16 | + */ |
| 17 | + |
| 18 | +import crypto from 'node:crypto'; |
| 19 | +import { StrKey, Keypair } from 'stellar-base'; |
| 20 | + |
| 21 | +function rb(n) { |
| 22 | + return crypto.randomBytes(n); |
| 23 | +} |
| 24 | + |
| 25 | +function u32be(n) { |
| 26 | + const b = Buffer.alloc(4); |
| 27 | + b.writeUInt32BE(n, 0); |
| 28 | + return b; |
| 29 | +} |
| 30 | + |
| 31 | +function roundTrip(label, encodeFn, decodeFn, isValidFn, raw) { |
| 32 | + const enc = encodeFn(raw); |
| 33 | + const ok = isValidFn(enc); |
| 34 | + const dec = decodeFn(enc); |
| 35 | + |
| 36 | + console.log(`\n== ${label} ==`); |
| 37 | + console.log(`encoded: ${enc}`); |
| 38 | + console.log(`isValid: ${ok}`); |
| 39 | + console.log(`rawLen : ${raw.length}`); |
| 40 | + console.log(`decLen : ${dec.length}`); |
| 41 | + console.log(`match : ${Buffer.compare(Buffer.from(raw), Buffer.from(dec)) === 0}`); |
| 42 | +} |
| 43 | + |
| 44 | +/* --------------------------- |
| 45 | + * G / S via Keypair |
| 46 | + * -------------------------- */ |
| 47 | +{ |
| 48 | + const kp = Keypair.random(); |
| 49 | + |
| 50 | + // G: ed25519 public key (32 bytes) |
| 51 | + const rawPub = kp.rawPublicKey(); // Buffer(32) |
| 52 | + roundTrip( |
| 53 | + 'G (ed25519PublicKey)', |
| 54 | + StrKey.encodeEd25519PublicKey, |
| 55 | + StrKey.decodeEd25519PublicKey, |
| 56 | + StrKey.isValidEd25519PublicKey, |
| 57 | + rawPub |
| 58 | + ); |
| 59 | + |
| 60 | + // S: ed25519 secret seed (32 bytes) |
| 61 | + const rawSeed = kp.rawSecretKey(); // Buffer(32) |
| 62 | + roundTrip( |
| 63 | + 'S (ed25519SecretSeed)', |
| 64 | + StrKey.encodeEd25519SecretSeed, |
| 65 | + StrKey.decodeEd25519SecretSeed, |
| 66 | + StrKey.isValidEd25519SecretSeed, |
| 67 | + rawSeed |
| 68 | + ); |
| 69 | + |
| 70 | + // (Bonus) Show the familiar string forms too |
| 71 | + console.log('\nKeypair string forms:'); |
| 72 | + console.log(`G...: ${kp.publicKey()}`); |
| 73 | + console.log(`S...: ${kp.secret()}`); |
| 74 | +} |
| 75 | + |
| 76 | +/* --------------------------- |
| 77 | + * M: med25519PublicKey |
| 78 | + * - 32 bytes ed25519 + 8 bytes ID |
| 79 | + * -------------------------- */ |
| 80 | +{ |
| 81 | + const rawM = Buffer.concat([rb(32), rb(8)]); // 40 bytes |
| 82 | + roundTrip( |
| 83 | + 'M (med25519PublicKey)', |
| 84 | + StrKey.encodeMed25519PublicKey, |
| 85 | + StrKey.decodeMed25519PublicKey, |
| 86 | + StrKey.isValidMed25519PublicKey, |
| 87 | + rawM |
| 88 | + ); |
| 89 | +} |
| 90 | + |
| 91 | +/* --------------------------- |
| 92 | + * T: preAuthTx (32 bytes) |
| 93 | + * -------------------------- */ |
| 94 | +{ |
| 95 | + const rawT = rb(32); |
| 96 | + // Note: js-stellar-base doesn’t expose isValidPreAuthTx in the snippet you pasted, |
| 97 | + // so we just encode/decode and then validate by decoding. |
| 98 | + const enc = StrKey.encodePreAuthTx(rawT); |
| 99 | + const dec = StrKey.decodePreAuthTx(enc); |
| 100 | + |
| 101 | + console.log('\n== T (preAuthTx) =='); |
| 102 | + console.log(`encoded: ${enc}`); |
| 103 | + console.log(`rawLen : ${rawT.length}`); |
| 104 | + console.log(`decLen : ${dec.length}`); |
| 105 | + console.log(`match : ${Buffer.compare(rawT, dec) === 0}`); |
| 106 | +} |
| 107 | + |
| 108 | +/* --------------------------- |
| 109 | + * X: sha256Hash (32 bytes) |
| 110 | + * -------------------------- */ |
| 111 | +{ |
| 112 | + const rawX = rb(32); |
| 113 | + const enc = StrKey.encodeSha256Hash(rawX); |
| 114 | + const dec = StrKey.decodeSha256Hash(enc); |
| 115 | + |
| 116 | + console.log('\n== X (sha256Hash) =='); |
| 117 | + console.log(`encoded: ${enc}`); |
| 118 | + console.log(`rawLen : ${rawX.length}`); |
| 119 | + console.log(`decLen : ${dec.length}`); |
| 120 | + console.log(`match : ${Buffer.compare(rawX, dec) === 0}`); |
| 121 | +} |
| 122 | + |
| 123 | +/* --------------------------- |
| 124 | + * P: signedPayload |
| 125 | + * - 32 bytes signer + 4 bytes payload length + payload (4..64 bytes) |
| 126 | + * -------------------------- */ |
| 127 | +{ |
| 128 | + const signer = rb(32); |
| 129 | + const payload = rb(32); // choose any length 4..64 |
| 130 | + const rawP = Buffer.concat([signer, u32be(payload.length), payload]); |
| 131 | + |
| 132 | + roundTrip( |
| 133 | + 'P (signedPayload)', |
| 134 | + StrKey.encodeSignedPayload, |
| 135 | + StrKey.decodeSignedPayload, |
| 136 | + StrKey.isValidSignedPayload, |
| 137 | + rawP |
| 138 | + ); |
| 139 | +} |
| 140 | + |
| 141 | +/* --------------------------- |
| 142 | + * C: contract (32 bytes) |
| 143 | + * -------------------------- */ |
| 144 | +{ |
| 145 | + const rawC = rb(32); |
| 146 | + roundTrip( |
| 147 | + 'C (contract)', |
| 148 | + StrKey.encodeContract, |
| 149 | + StrKey.decodeContract, |
| 150 | + StrKey.isValidContract, |
| 151 | + rawC |
| 152 | + ); |
| 153 | +} |
| 154 | + |
| 155 | +/* --------------------------- |
| 156 | + * L: liquidityPool (32 bytes) |
| 157 | + * -------------------------- */ |
| 158 | +{ |
| 159 | + const rawL = rb(32); |
| 160 | + roundTrip( |
| 161 | + 'L (liquidityPool)', |
| 162 | + StrKey.encodeLiquidityPool, |
| 163 | + StrKey.decodeLiquidityPool, |
| 164 | + StrKey.isValidLiquidityPool, |
| 165 | + rawL |
| 166 | + ); |
| 167 | +} |
| 168 | + |
| 169 | +/* --------------------------- |
| 170 | + * B: claimableBalance |
| 171 | + * - 1 byte discriminant + 32 bytes hash |
| 172 | + * - discriminant is usually 0 for the V0 type |
| 173 | + * -------------------------- */ |
| 174 | +{ |
| 175 | + const discriminant = Buffer.from([0x00]); |
| 176 | + const cbHash = rb(32); |
| 177 | + const rawB = Buffer.concat([discriminant, cbHash]); // 33 bytes |
| 178 | + |
| 179 | + roundTrip( |
| 180 | + 'B (claimableBalance)', |
| 181 | + StrKey.encodeClaimableBalance, |
| 182 | + StrKey.decodeClaimableBalance, |
| 183 | + StrKey.isValidClaimableBalance, |
| 184 | + rawB |
| 185 | + ); |
| 186 | +} |
| 187 | + |
| 188 | +/* --------------------------- |
| 189 | + * Introspection helpers (from your snippet) |
| 190 | + * -------------------------- */ |
| 191 | +{ |
| 192 | + const examples = [ |
| 193 | + Keypair.random().publicKey(), // G... |
| 194 | + Keypair.random().secret(), // S... |
| 195 | + StrKey.encodeContract(rb(32)), // C... |
| 196 | + StrKey.encodeLiquidityPool(rb(32)), // L... |
| 197 | + StrKey.encodeClaimableBalance(Buffer.concat([Buffer.from([0]), rb(32)])) // B... |
| 198 | + ]; |
| 199 | + |
| 200 | + console.log('\n== getVersionByteForPrefix examples =='); |
| 201 | + for (const s of examples) { |
| 202 | + const vb = StrKey.getVersionByteForPrefix(s); |
| 203 | + console.log(`${s.slice(0, 1)}... -> versionByte: ${vb}`); |
| 204 | + } |
| 205 | +} |
0 commit comments