mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-19 19:55:51 +00:00
Refactor and simplify code (#8)
* Remove dependency on x-address-codec * Version 3.0.0
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- '0.12'
|
- 6
|
||||||
|
- 8
|
||||||
|
- 9
|
||||||
script:
|
script:
|
||||||
- npm test --coverage
|
- yarn compile
|
||||||
- npm run codecov
|
- yarn test
|
||||||
- npm run lint
|
- yarn lint
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# ripple-address-codec [](https://npmjs.org/package/ripple-address-codec) [](https://travis-ci.org/ripple/ripple-address-codec) [](http://codecov.io/github/ripple/ripple-address-codec?branch=master)
|
# ripple-address-codec [](https://npmjs.org/package/ripple-address-codec)
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
@@ -34,66 +34,3 @@
|
|||||||
112,
|
112,
|
||||||
114 ]
|
114 ]
|
||||||
```
|
```
|
||||||
|
|
||||||
## And ?? There's more to the wonderful world than ripple
|
|
||||||
|
|
||||||
We give you the kitchen sink.
|
|
||||||
|
|
||||||
```js
|
|
||||||
> console.log(api)
|
|
||||||
{ Codec: [Function: AddressCodec],
|
|
||||||
codecs:
|
|
||||||
{ bitcoin:
|
|
||||||
{ alphabet: '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz',
|
|
||||||
codec: [Object],
|
|
||||||
base: 58 },
|
|
||||||
ripple:
|
|
||||||
{ alphabet: 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz',
|
|
||||||
codec: [Object],
|
|
||||||
base: 58 },
|
|
||||||
tipple:
|
|
||||||
{ alphabet: 'RPShNAF39wBUDnEGHJKLM4pQrsT7VWXYZ2bcdeCg65jkm8ofqi1tuvaxyz',
|
|
||||||
codec: [Object],
|
|
||||||
base: 58 },
|
|
||||||
stellar:
|
|
||||||
{ alphabet: 'gsphnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCr65jkm8oFqi1tuvAxyz',
|
|
||||||
codec: [Object],
|
|
||||||
base: 58 } },
|
|
||||||
decode: [Function: decode],
|
|
||||||
encode: [Function: encode],
|
|
||||||
decodeEdSeed: [Function],
|
|
||||||
encodeEdSeed: [Function],
|
|
||||||
isValidEdSeed: [Function],
|
|
||||||
decodeSeed: [Function],
|
|
||||||
encodeSeed: [Function],
|
|
||||||
isValidSeed: [Function],
|
|
||||||
decodeAccountID: [Function],
|
|
||||||
encodeAccountID: [Function],
|
|
||||||
isValidAccountID: [Function],
|
|
||||||
decodeAddress: [Function],
|
|
||||||
encodeAddress: [Function],
|
|
||||||
isValidAddress: [Function],
|
|
||||||
decodeNodePublic: [Function],
|
|
||||||
encodeNodePublic: [Function],
|
|
||||||
isValidNodePublic: [Function],
|
|
||||||
decodeNodePrivate: [Function],
|
|
||||||
encodeNodePrivate: [Function],
|
|
||||||
isValidNodePrivate: [Function],
|
|
||||||
decodeK256Seed: [Function],
|
|
||||||
encodeK256Seed: [Function],
|
|
||||||
isValidK256Seed: [Function] }
|
|
||||||
```
|
|
||||||
|
|
||||||
# Decode a bip32 bitcoin public key
|
|
||||||
|
|
||||||
```js
|
|
||||||
var pubVersion = [0x04, 0x88, 0xB2, 0x1E];
|
|
||||||
var options = {version: pubVersion, alphabet: 'bitcoin'};
|
|
||||||
var key = 'xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5e4cp9LB';
|
|
||||||
var decoded = api.decode(key, options);
|
|
||||||
var reencoded = api.encode(decoded, options);
|
|
||||||
console.log(key);
|
|
||||||
// 'xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5e4cp9LB'
|
|
||||||
console.log(reencoded);
|
|
||||||
// 'xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5e4cp9LB'
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -1,33 +1,32 @@
|
|||||||
{
|
{
|
||||||
"name": "ripple-address-codec",
|
"name": "ripple-address-codec",
|
||||||
"version": "2.0.2",
|
"version": "3.0.0",
|
||||||
"description": "encodes/decodes base58 encoded ripple identifiers",
|
"description": "encodes/decodes base58 encoded ripple identifiers",
|
||||||
"main": "src/index.js",
|
"main": "dist/index.js",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"create-hash": "^1.1.2",
|
"base-x": "3.0.4",
|
||||||
"x-address-codec": "^0.7.2"
|
"create-hash": "^1.1.2"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/ripple/ripple-address-codec.git"
|
"url": "git://github.com/ripple/ripple-address-codec.git"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "istanbul test _mocha",
|
"compile": "tsc",
|
||||||
"prepublish": "npm test && npm run lint",
|
"test": "tsc && istanbul test _mocha",
|
||||||
"codecov": "cat ./coverage/coverage.json | ./node_modules/codecov.io/bin/codecov.io.js",
|
"lint": "tslint -p ./"
|
||||||
"lint": "if ! [ -f eslintrc ]; then curl -o eslintrc 'https://raw.githubusercontent.com/ripple/javascript-style-guide/master/eslintrc'; fi; eslint -c eslintrc src/*.js test/*.js"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^10.12.0",
|
||||||
"codecov.io": "^0.1.6",
|
"codecov.io": "^0.1.6",
|
||||||
"coveralls": "~2.11.4",
|
"coveralls": "~2.11.4",
|
||||||
"eslint": "^4.19.1",
|
"eslint": "^4.19.1",
|
||||||
"eslint-plugin-no-unused-expressions": "^0.1.0",
|
"eslint-plugin-no-unused-expressions": "^0.1.0",
|
||||||
"istanbul": "~0.3.21",
|
"istanbul": "~0.3.21",
|
||||||
"mocha": "^5.0.5"
|
"mocha": "^5.0.5",
|
||||||
},
|
"tslint": "^5.11.0",
|
||||||
"readmeFilename": "README.md",
|
"tslint-eslint-rules": "^5.4.0",
|
||||||
"engines": {
|
"typescript": "^3.1.3"
|
||||||
"node": ">=0.12.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const createHash = require('create-hash')
|
|
||||||
const apiFactory = require('x-address-codec')
|
|
||||||
|
|
||||||
const NODE_PUBLIC = 28
|
|
||||||
const NODE_PRIVATE = 32
|
|
||||||
const ACCOUNT_ID = 0
|
|
||||||
const FAMILY_SEED = 33
|
|
||||||
const ED25519_SEED = [0x01, 0xE1, 0x4B]
|
|
||||||
|
|
||||||
module.exports = apiFactory({
|
|
||||||
sha256: function(bytes) {
|
|
||||||
return createHash('sha256').update(new Buffer(bytes)).digest()
|
|
||||||
},
|
|
||||||
defaultAlphabet: 'ripple',
|
|
||||||
codecMethods: {
|
|
||||||
EdSeed: {
|
|
||||||
expectedLength: 16,
|
|
||||||
version: ED25519_SEED
|
|
||||||
},
|
|
||||||
Seed: {
|
|
||||||
// TODO: Use a map, not a parallel array
|
|
||||||
versionTypes: ['ed25519', 'secp256k1'],
|
|
||||||
versions: [ED25519_SEED, FAMILY_SEED],
|
|
||||||
expectedLength: 16
|
|
||||||
},
|
|
||||||
AccountID: {version: ACCOUNT_ID, expectedLength: 20},
|
|
||||||
Address: {version: ACCOUNT_ID, expectedLength: 20},
|
|
||||||
NodePublic: {version: NODE_PUBLIC, expectedLength: 33},
|
|
||||||
NodePrivate: {version: NODE_PRIVATE, expectedLength: 32},
|
|
||||||
K256Seed: {version: FAMILY_SEED, expectedLength: 16}}
|
|
||||||
})
|
|
||||||
1
packages/ripple-address-codec/src/index.ts
Normal file
1
packages/ripple-address-codec/src/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './xrp-codec'
|
||||||
59
packages/ripple-address-codec/src/utils.ts
Normal file
59
packages/ripple-address-codec/src/utils.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
function seqEqual(arr1, arr2) {
|
||||||
|
if (arr1.length !== arr2.length) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < arr1.length; i++) {
|
||||||
|
if (arr1[i] !== arr2[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSequence(val) {
|
||||||
|
return val.length !== undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenates all `arguments` into a single array. Each argument can be either
|
||||||
|
* a single element or a sequence, which has a `length` property and supports
|
||||||
|
* element retrieval via sequence[ix].
|
||||||
|
*
|
||||||
|
* > concatArgs(1, [2, 3], new Buffer([4,5]), new Uint8Array([6, 7]));
|
||||||
|
* [1,2,3,4,5,6,7]
|
||||||
|
*
|
||||||
|
* @return {Array} - concatenated arguments
|
||||||
|
*/
|
||||||
|
function concatArgs() {
|
||||||
|
const ret = []
|
||||||
|
const _len = arguments.length
|
||||||
|
const args = Array(_len)
|
||||||
|
|
||||||
|
for (let _key = 0; _key < _len; _key++) {
|
||||||
|
args[_key] = arguments[_key]
|
||||||
|
}
|
||||||
|
|
||||||
|
args.forEach(function (arg) {
|
||||||
|
if (isSequence(arg)) {
|
||||||
|
for (let j = 0; j < arg.length; j++) {
|
||||||
|
ret.push(arg[j])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret.push(arg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSet(o) {
|
||||||
|
return o !== null && o !== undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
seqEqual: seqEqual,
|
||||||
|
concatArgs: concatArgs,
|
||||||
|
isSet: isSet
|
||||||
|
}
|
||||||
219
packages/ripple-address-codec/src/xrp-codec.ts
Normal file
219
packages/ripple-address-codec/src/xrp-codec.ts
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
/**
|
||||||
|
* Codec class
|
||||||
|
*/
|
||||||
|
|
||||||
|
const baseCodec = require('base-x')
|
||||||
|
const {seqEqual, concatArgs} = require('.//utils')
|
||||||
|
|
||||||
|
class Codec {
|
||||||
|
sha256: (bytes: Uint8Array) => Buffer
|
||||||
|
alphabet: string
|
||||||
|
codec: any
|
||||||
|
base: number
|
||||||
|
|
||||||
|
constructor(options: {
|
||||||
|
sha256: (bytes: Uint8Array) => Buffer,
|
||||||
|
alphabet: string
|
||||||
|
}) {
|
||||||
|
this.sha256 = options.sha256
|
||||||
|
this.alphabet = options.alphabet
|
||||||
|
this.codec = baseCodec(this.alphabet)
|
||||||
|
this.base = this.alphabet.length
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encoder.
|
||||||
|
*
|
||||||
|
* @param bytes Buffer of data to encode.
|
||||||
|
* @param opts Options object including the version bytes and the expected length of the data to encode.
|
||||||
|
*/
|
||||||
|
encode(bytes: Buffer, opts: {
|
||||||
|
versions: number[],
|
||||||
|
expectedLength: number
|
||||||
|
}) {
|
||||||
|
const versions = opts.versions
|
||||||
|
return this.encodeVersioned(bytes, versions, opts.expectedLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
encodeVersioned(bytes: Buffer, versions: number[], expectedLength: number) {
|
||||||
|
if (expectedLength && bytes.length !== expectedLength) {
|
||||||
|
throw new Error('unexpected_payload_length: bytes.length does not match expectedLength')
|
||||||
|
}
|
||||||
|
return this.encodeChecked(concatArgs(versions, bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
encodeChecked(buffer: Buffer) {
|
||||||
|
const check = this.sha256(this.sha256(buffer)).slice(0, 4)
|
||||||
|
return this.encodeRaw(concatArgs(buffer, check))
|
||||||
|
}
|
||||||
|
|
||||||
|
encodeRaw(bytes: Buffer) {
|
||||||
|
return this.codec.encode(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decoder.
|
||||||
|
*
|
||||||
|
* @param base58string Base58Check-encoded string to decode.
|
||||||
|
* @param opts Options object including the version byte(s) and the expected length of the data after decoding.
|
||||||
|
*/
|
||||||
|
decode(base58string: string, opts: {
|
||||||
|
versions?: (number | number[])[],
|
||||||
|
expectedLength?: number,
|
||||||
|
versionTypes?: ['ed25519', 'secp256k1']
|
||||||
|
} = {}) {
|
||||||
|
const versions = Array.isArray(opts.versions) ? opts.versions : [opts.versions]
|
||||||
|
const types = opts.versionTypes
|
||||||
|
if (versions) {
|
||||||
|
const withoutSum = this.decodeChecked(base58string)
|
||||||
|
const ret: {
|
||||||
|
version: number[] | null,
|
||||||
|
bytes: Buffer | null,
|
||||||
|
type: string | null // for seeds, 'ed25519' | 'secp256k1'
|
||||||
|
} = {
|
||||||
|
version: null,
|
||||||
|
bytes: null,
|
||||||
|
type: null
|
||||||
|
}
|
||||||
|
if (versions.length > 1 && !opts.expectedLength) {
|
||||||
|
throw new Error('expectedLength is required because there are >= 2 possible versions')
|
||||||
|
}
|
||||||
|
const versionLengthGuess = typeof versions[0] === 'number' ? 1 : (versions[0] as number[]).length
|
||||||
|
const payloadLength = opts.expectedLength || withoutSum.length - versionLengthGuess
|
||||||
|
const versionBytes = withoutSum.slice(0, -payloadLength)
|
||||||
|
const payload = withoutSum.slice(-payloadLength)
|
||||||
|
|
||||||
|
let foundVersion = false
|
||||||
|
for (let i = 0; i < versions.length; i++) {
|
||||||
|
const version: number[] = Array.isArray(versions[i]) ? versions[i] as number[] : [versions[i] as number]
|
||||||
|
if (seqEqual(versionBytes, version)) {
|
||||||
|
ret.version = version
|
||||||
|
ret.bytes = payload
|
||||||
|
if (types) {
|
||||||
|
ret.type = types[i]
|
||||||
|
}
|
||||||
|
foundVersion = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundVersion) {
|
||||||
|
throw new Error('version_invalid: version bytes do not match any of the provided version(s)')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.expectedLength && ret.bytes.length !== opts.expectedLength) {
|
||||||
|
throw new Error('unexpected_payload_length: payload length does not match expectedLength')
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume that base58string is 'checked'
|
||||||
|
return this.decodeChecked(base58string)
|
||||||
|
}
|
||||||
|
|
||||||
|
decodeChecked(base58string: string) {
|
||||||
|
const buffer = this.decodeRaw(base58string)
|
||||||
|
if (buffer.length < 5) {
|
||||||
|
throw new Error('invalid_input_size: decoded data must have length >= 5')
|
||||||
|
}
|
||||||
|
if (!this.verifyCheckSum(buffer)) {
|
||||||
|
throw new Error('checksum_invalid')
|
||||||
|
}
|
||||||
|
return buffer.slice(0, -4)
|
||||||
|
}
|
||||||
|
|
||||||
|
decodeRaw(base58string: string) {
|
||||||
|
return this.codec.decode(base58string)
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyCheckSum(bytes: Buffer) {
|
||||||
|
const computed = this.sha256(this.sha256(bytes.slice(0, -4))).slice(0, 4)
|
||||||
|
const checksum = bytes.slice(-4)
|
||||||
|
return seqEqual(computed, checksum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XRP codec
|
||||||
|
*/
|
||||||
|
|
||||||
|
const createHash = require('create-hash')
|
||||||
|
|
||||||
|
const NODE_PUBLIC = 28
|
||||||
|
const ACCOUNT_ID = 0
|
||||||
|
const FAMILY_SEED = 0x21 // 33
|
||||||
|
const ED25519_SEED = [0x01, 0xE1, 0x4B] // [1, 225, 75]
|
||||||
|
|
||||||
|
const codecOptions = {
|
||||||
|
sha256: function(bytes: Uint8Array) {
|
||||||
|
return createHash('sha256').update(Buffer.from(bytes)).digest()
|
||||||
|
},
|
||||||
|
alphabet: 'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz'
|
||||||
|
}
|
||||||
|
|
||||||
|
const codecWithXrpAlphabet = new Codec(codecOptions)
|
||||||
|
|
||||||
|
// entropy is a Buffer of size 16
|
||||||
|
// type is 'ed25519' or 'secp256k1'
|
||||||
|
export function encodeSeed(entropy: Buffer, type: 'ed25519' | 'secp256k1'): string {
|
||||||
|
if (entropy.length !== 16) {
|
||||||
|
throw new Error('entropy must have length 16')
|
||||||
|
}
|
||||||
|
if (type !== 'ed25519' && type !== 'secp256k1') {
|
||||||
|
throw new Error('type must be ed25519 or secp256k1')
|
||||||
|
}
|
||||||
|
const opts = {
|
||||||
|
expectedLength: 16,
|
||||||
|
|
||||||
|
// for secp256k1, use `FAMILY_SEED`
|
||||||
|
versions: type === 'ed25519' ? ED25519_SEED : [FAMILY_SEED]
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefixes entropy with version bytes
|
||||||
|
return codecWithXrpAlphabet.encode(entropy, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decodeSeed(seed: string, opts: {
|
||||||
|
versionTypes?: ['ed25519', 'secp256k1'],
|
||||||
|
versions?: (number | number[])[]
|
||||||
|
expectedLength?: number
|
||||||
|
} = {}) {
|
||||||
|
if (!opts.versionTypes || !opts.versions) {
|
||||||
|
opts.versionTypes = ['ed25519', 'secp256k1']
|
||||||
|
opts.versions = [ED25519_SEED, FAMILY_SEED]
|
||||||
|
}
|
||||||
|
if (!opts.expectedLength) {
|
||||||
|
opts.expectedLength = 16
|
||||||
|
}
|
||||||
|
return codecWithXrpAlphabet.decode(seed, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function encodeAccountID(bytes: Buffer): string {
|
||||||
|
const opts = {versions: [ACCOUNT_ID], expectedLength: 20}
|
||||||
|
return codecWithXrpAlphabet.encode(bytes, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decodeAccountID(accountId: string): Buffer {
|
||||||
|
const opts = {versions: [ACCOUNT_ID], expectedLength: 20}
|
||||||
|
return codecWithXrpAlphabet.decode(accountId, opts).bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decodeNodePublic(base58string: string): Buffer {
|
||||||
|
const opts = {versions: [NODE_PUBLIC], expectedLength: 33}
|
||||||
|
return codecWithXrpAlphabet.decode(base58string, opts).bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
export function encodeNodePublic(bytes: Buffer): string {
|
||||||
|
const opts = {versions: [NODE_PUBLIC], expectedLength: 33}
|
||||||
|
return codecWithXrpAlphabet.encode(bytes, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address === AccountID
|
||||||
|
export function isValidAddress(address: string): boolean {
|
||||||
|
try {
|
||||||
|
this.decodeAccountID(address)
|
||||||
|
} catch (e) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const assert = require('assert')
|
const assert = require('assert')
|
||||||
const api = require('../')
|
const api = require('../dist')
|
||||||
|
|
||||||
function toHex(bytes) {
|
function toHex(bytes) {
|
||||||
return new Buffer(bytes).toString('hex').toUpperCase()
|
return new Buffer(bytes).toString('hex').toUpperCase()
|
||||||
@@ -15,11 +15,11 @@ function toBytes(hex) {
|
|||||||
|
|
||||||
describe('ripple-address-codec', function() {
|
describe('ripple-address-codec', function() {
|
||||||
function makeTest(type, base58, hex) {
|
function makeTest(type, base58, hex) {
|
||||||
it('can translate between ' + hex + ' and ' + base58, function() {
|
it(`can translate between ${hex} and ${base58} (encode ${type})`, function() {
|
||||||
const actual = api['encode' + type](toBytes(hex))
|
const actual = api['encode' + type](toBytes(hex))
|
||||||
assert.equal(actual, base58)
|
assert.equal(actual, base58)
|
||||||
})
|
})
|
||||||
it('can translate between ' + base58 + ' and ' + hex, function() {
|
it(`can translate between ${base58} and ${hex} (decode ${type})`, function() {
|
||||||
const buf = api['decode' + type](base58)
|
const buf = api['decode' + type](base58)
|
||||||
assert.equal(toHex(buf), hex)
|
assert.equal(toHex(buf), hex)
|
||||||
})
|
})
|
||||||
@@ -33,13 +33,7 @@ describe('ripple-address-codec', function() {
|
|||||||
'n9MXXueo837zYH36DvMc13BwHcqtfAWNJY5czWVbp7uYTj7x17TH',
|
'n9MXXueo837zYH36DvMc13BwHcqtfAWNJY5czWVbp7uYTj7x17TH',
|
||||||
'0388E5BA87A000CB807240DF8C848EB0B5FFA5C8E5A521BC8E105C0F0A44217828')
|
'0388E5BA87A000CB807240DF8C848EB0B5FFA5C8E5A521BC8E105C0F0A44217828')
|
||||||
|
|
||||||
makeTest('K256Seed', 'sn259rEFXrQrWyx3Q7XneWcwV6dfL',
|
it('can decode arbitrary seeds', function() {
|
||||||
'CF2DE378FBDD7E2EE87D486DFB5A7BFF')
|
|
||||||
|
|
||||||
makeTest('EdSeed', 'sEdTM1uX8pu2do5XvTnutH6HsouMaM2',
|
|
||||||
'4C3A1D213FBDFB14C7C28D609469B341')
|
|
||||||
|
|
||||||
it('can decode arbitray seeds', function() {
|
|
||||||
const decoded = api.decodeSeed('sEdTM1uX8pu2do5XvTnutH6HsouMaM2')
|
const decoded = api.decodeSeed('sEdTM1uX8pu2do5XvTnutH6HsouMaM2')
|
||||||
assert.equal(toHex(decoded.bytes), '4C3A1D213FBDFB14C7C28D609469B341')
|
assert.equal(toHex(decoded.bytes), '4C3A1D213FBDFB14C7C28D609469B341')
|
||||||
assert.equal(decoded.type, 'ed25519')
|
assert.equal(decoded.type, 'ed25519')
|
||||||
|
|||||||
81
packages/ripple-address-codec/test/xrp-codec-test.js
Normal file
81
packages/ripple-address-codec/test/xrp-codec-test.js
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/* eslint-disable no-unused-expressions/no-unused-expressions */
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const assert = require('assert')
|
||||||
|
const api = require('../dist/xrp-codec')
|
||||||
|
|
||||||
|
function toHex(bytes) {
|
||||||
|
return new Buffer(bytes).toString('hex').toUpperCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
function toBytes(hex) {
|
||||||
|
return new Buffer(hex, 'hex').toJSON().data
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('ripple-address-codec', function() {
|
||||||
|
|
||||||
|
describe('encodeSeed', function() {
|
||||||
|
|
||||||
|
it('encodes a secp256k1 seed', function() {
|
||||||
|
const result = api.encodeSeed(toBytes('CF2DE378FBDD7E2EE87D486DFB5A7BFF'), 'secp256k1')
|
||||||
|
assert.equal(result, 'sn259rEFXrQrWyx3Q7XneWcwV6dfL')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('encodes low secp256k1 seed', function() {
|
||||||
|
const result = api.encodeSeed(toBytes('00000000000000000000000000000000'), 'secp256k1')
|
||||||
|
assert.equal(result, 'sp6JS7f14BuwFY8Mw6bTtLKWauoUs')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('encodes high secp256k1 seed', function() {
|
||||||
|
const result = api.encodeSeed(toBytes('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'), 'secp256k1')
|
||||||
|
assert.equal(result, 'saGwBRReqUNKuWNLpUAq8i8NkXEPN')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('encodes an ed25519 seed', function() {
|
||||||
|
const result = api.encodeSeed(toBytes('4C3A1D213FBDFB14C7C28D609469B341'), 'ed25519')
|
||||||
|
assert.equal(result, 'sEdTM1uX8pu2do5XvTnutH6HsouMaM2')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('encodes low ed25519 seed', function() {
|
||||||
|
const result = api.encodeSeed(toBytes('00000000000000000000000000000000'), 'ed25519')
|
||||||
|
assert.equal(result, 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('encodes high ed25519 seed', function() {
|
||||||
|
const result = api.encodeSeed(toBytes('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'), 'ed25519')
|
||||||
|
assert.equal(result, 'sEdV19BLfeQeKdEXyYA4NhjPJe6XBfG')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('decodeSeed', function() {
|
||||||
|
|
||||||
|
it('can decode an Ed25519 seed', function() {
|
||||||
|
const decoded = api.decodeSeed('sEdTM1uX8pu2do5XvTnutH6HsouMaM2')
|
||||||
|
assert.equal(toHex(decoded.bytes), '4C3A1D213FBDFB14C7C28D609469B341')
|
||||||
|
assert.equal(decoded.type, 'ed25519')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can decode a secp256k1 seed', function() {
|
||||||
|
const decoded = api.decodeSeed('sn259rEFXrQrWyx3Q7XneWcwV6dfL')
|
||||||
|
assert.equal(toHex(decoded.bytes), 'CF2DE378FBDD7E2EE87D486DFB5A7BFF')
|
||||||
|
assert.equal(decoded.type, 'secp256k1')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('encodeAccountID', function() {
|
||||||
|
|
||||||
|
it('can encode an AccountID', function() {
|
||||||
|
const encoded = api.encodeAccountID(toBytes('BA8E78626EE42C41B46D46C3048DF3A1C3C87072'))
|
||||||
|
assert.equal(encoded, 'rJrRMgiRgrU6hDF4pgu5DXQdWyPbY35ErN')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('decodeNodePublic', function() {
|
||||||
|
|
||||||
|
it('can decode a NodePublic', function() {
|
||||||
|
const decoded = api.decodeNodePublic('n9MXXueo837zYH36DvMc13BwHcqtfAWNJY5czWVbp7uYTj7x17TH')
|
||||||
|
assert.equal(toHex(decoded), '0388E5BA87A000CB807240DF8C848EB0B5FFA5C8E5A521BC8E105C0F0A44217828')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
25
packages/ripple-address-codec/tsconfig.json
Normal file
25
packages/ripple-address-codec/tsconfig.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6",
|
||||||
|
"lib": [
|
||||||
|
"es2017"
|
||||||
|
],
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src",
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"strictNullChecks": false,
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"removeComments": false,
|
||||||
|
"preserveConstEnums": false,
|
||||||
|
"suppressImplicitAnyIndexErrors": false,
|
||||||
|
"sourceMap": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"allowJs": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
74
packages/ripple-address-codec/tslint.json
Normal file
74
packages/ripple-address-codec/tslint.json
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"tslint-eslint-rules"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"ban": [true, ["alert"]],
|
||||||
|
"no-arg": true,
|
||||||
|
"no-conditional-assignment": true,
|
||||||
|
"no-console": false,
|
||||||
|
"no-constant-condition": true,
|
||||||
|
"no-control-regex": true,
|
||||||
|
"no-debugger": true,
|
||||||
|
"no-duplicate-case": true,
|
||||||
|
"no-empty": true,
|
||||||
|
"no-empty-character-class": true,
|
||||||
|
"no-eval": true,
|
||||||
|
"no-ex-assign": true,
|
||||||
|
"no-extra-boolean-cast": true,
|
||||||
|
"no-extra-semi": true,
|
||||||
|
"no-switch-case-fall-through": true,
|
||||||
|
"no-inner-declarations": [true, "functions"],
|
||||||
|
"no-invalid-regexp": true,
|
||||||
|
"no-invalid-this": false,
|
||||||
|
"no-irregular-whitespace": true,
|
||||||
|
"ter-no-irregular-whitespace": true,
|
||||||
|
"label-position": true,
|
||||||
|
"indent": [true, "spaces", 2],
|
||||||
|
"linebreak-style": [true, "unix"],
|
||||||
|
"no-multi-spaces": true,
|
||||||
|
"no-consecutive-blank-lines": [true, 2],
|
||||||
|
"no-unused-expression": true,
|
||||||
|
"no-construct": true,
|
||||||
|
"no-duplicate-variable": true,
|
||||||
|
"no-regex-spaces": true,
|
||||||
|
"no-shadowed-variable": true,
|
||||||
|
"ter-no-sparse-arrays": true,
|
||||||
|
"no-trailing-whitespace": true,
|
||||||
|
"no-string-throw": true,
|
||||||
|
"no-unexpected-multiline": true,
|
||||||
|
"no-use-before-declare": true,
|
||||||
|
"no-var-keyword": true,
|
||||||
|
"no-magic-numbers": false,
|
||||||
|
"array-bracket-spacing": [true, "never"],
|
||||||
|
"ter-arrow-body-style": false,
|
||||||
|
"ter-arrow-parens": [true, "as-needed"],
|
||||||
|
"ter-arrow-spacing": true,
|
||||||
|
"block-spacing": true,
|
||||||
|
"brace-style": [true, "1tbs", {"allowSingleLine": true}],
|
||||||
|
"variable-name": false,
|
||||||
|
"trailing-comma": [true, {"multiline": "never", "singleline": "never"}],
|
||||||
|
"cyclomatic-complexity": [false, 11],
|
||||||
|
"curly": [true, "all"],
|
||||||
|
"switch-default": false,
|
||||||
|
"eofline": true,
|
||||||
|
"triple-equals": true,
|
||||||
|
"forin": false,
|
||||||
|
"handle-callback-err": true,
|
||||||
|
"ter-max-len": [true, 120],
|
||||||
|
"new-parens": true,
|
||||||
|
"object-curly-spacing": [true, "never"],
|
||||||
|
"object-literal-shorthand": false,
|
||||||
|
"one-variable-per-declaration": [true, "ignore-for-loop"],
|
||||||
|
"ter-prefer-arrow-callback": false,
|
||||||
|
"prefer-const": true,
|
||||||
|
"object-literal-key-quotes": false,
|
||||||
|
"quotemark": [true, "single"],
|
||||||
|
"radix": true,
|
||||||
|
"semicolon": [true, "never"],
|
||||||
|
"space-in-parens": [true, "never"],
|
||||||
|
"comment-format": [true, "check-space"],
|
||||||
|
"use-isnan": true,
|
||||||
|
"valid-typeof": true
|
||||||
|
}
|
||||||
|
}
|
||||||
2085
packages/ripple-address-codec/yarn.lock
Normal file
2085
packages/ripple-address-codec/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user