mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-20 12:15:51 +00:00
@@ -1,51 +0,0 @@
|
||||
'use strict';
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const execSync = require('child_process').execSync;
|
||||
const ejs = require('ejs');
|
||||
const renderFromPaths =
|
||||
require('json-schema-to-markdown-table').renderFromPaths;
|
||||
const ROOT = path.dirname(path.normalize(__dirname));
|
||||
|
||||
function strip(string) {
|
||||
return string.replace(/^\s+|\s+$/g, '');
|
||||
}
|
||||
|
||||
function importFile(relativePath) {
|
||||
const absolutePath = path.join(ROOT, relativePath);
|
||||
return strip(fs.readFileSync(absolutePath).toString('utf-8'));
|
||||
}
|
||||
|
||||
function renderFixture(fixtureRelativePath) {
|
||||
const json = importFile(path.join('test', 'fixtures', fixtureRelativePath));
|
||||
return '\n```json\n' + json + '\n```\n';
|
||||
}
|
||||
|
||||
function renderSchema(schemaRelativePath) {
|
||||
const schemasPath = path.join(ROOT, 'src', 'common', 'schemas');
|
||||
const schemaPath = path.join(schemasPath, schemaRelativePath);
|
||||
return renderFromPaths(schemaPath, schemasPath);
|
||||
}
|
||||
|
||||
function main() {
|
||||
const locals = {
|
||||
importFile: importFile,
|
||||
renderFixture: renderFixture,
|
||||
renderSchema: renderSchema
|
||||
};
|
||||
|
||||
const indexPath = path.join(ROOT, 'docs', 'src', 'index.md.ejs');
|
||||
ejs.renderFile(indexPath, locals, function(error, output) {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
} else {
|
||||
const outputPath = path.join(ROOT, 'docs', 'index.md');
|
||||
fs.writeFileSync(outputPath, output);
|
||||
execSync('npm run doctoc', {cwd: ROOT});
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
function checkEOL {
|
||||
local changedFiles=$(git --no-pager diff --name-only -M100% --diff-filter=AM --relative $(git merge-base FETCH_HEAD origin/HEAD) FETCH_HEAD)
|
||||
local result=0
|
||||
for name in $changedFiles; do
|
||||
grep -c -U -q $'\r' $name
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "windows eol found in $name" >&2
|
||||
result=1
|
||||
fi
|
||||
done
|
||||
if [ $result -eq 1 ]; then
|
||||
false
|
||||
fi
|
||||
}
|
||||
|
||||
checkEOL
|
||||
@@ -1,98 +0,0 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
NODE_INDEX="$1"
|
||||
TOTAL_NODES="$2"
|
||||
|
||||
function checkEOL {
|
||||
./scripts/checkeol.sh
|
||||
}
|
||||
|
||||
lint() {
|
||||
echo "tslint $(node_modules/.bin/tslint --version)"
|
||||
npm run lint
|
||||
}
|
||||
|
||||
unittest() {
|
||||
# test "src"
|
||||
|
||||
# TODO: replace/upgrade mocha-junit-reporter
|
||||
#mocha test --reporter mocha-junit-reporter --reporter-options mochaFile=$CIRCLE_TEST_REPORTS/test-results.xml
|
||||
|
||||
npm test --coverage
|
||||
#npm run coveralls
|
||||
|
||||
# test compiled version in "dist/npm"
|
||||
$(npm bin)/babel -D --optional runtime --ignore "**/node_modules/**" -d test-compiled/ test/
|
||||
echo "--reporter spec --timeout 5000 --slow 500" > test-compiled/mocha.opts
|
||||
mkdir -p test-compiled/node_modules
|
||||
ln -nfs ../../dist/npm test-compiled/node_modules/xrpl-local
|
||||
mocha --opts test-compiled/mocha.opts test-compiled
|
||||
|
||||
#compile tests for browser testing
|
||||
#gulp build-min build-tests
|
||||
#node --harmony test-compiled/mocked-server.js > /dev/null &
|
||||
|
||||
#echo "Running tests in PhantomJS"
|
||||
#mocha-phantomjs test/localRunner.html
|
||||
#echo "Running tests using minified version in PhantomJS"
|
||||
#mocha-phantomjs test/localRunnerMin.html
|
||||
|
||||
#echo "Running tests in SauceLabs"
|
||||
#http-server &
|
||||
#npm run sauce
|
||||
|
||||
#pkill -f mocked-server.js
|
||||
#pkill -f http-server
|
||||
rm -rf test-compiled
|
||||
}
|
||||
|
||||
integrationtest() {
|
||||
mocha test/integration/integration.js
|
||||
|
||||
# run integration tests in PhantomJS
|
||||
#gulp build-tests build-min
|
||||
#echo "Running integragtion tests in PhantomJS"
|
||||
#mocha-phantomjs test/localIntegrationRunner.html
|
||||
}
|
||||
|
||||
doctest() {
|
||||
mv docs/index.md docs/index.md.save
|
||||
npm run docgen
|
||||
mv docs/index.md docs/index.md.test
|
||||
mv docs/index.md.save docs/index.md
|
||||
cmp docs/index.md docs/index.md.test
|
||||
rm docs/index.md.test
|
||||
}
|
||||
|
||||
oneNode() {
|
||||
checkEOL
|
||||
doctest
|
||||
lint
|
||||
unittest
|
||||
integrationtest
|
||||
}
|
||||
|
||||
twoNodes() {
|
||||
case "$NODE_INDEX" in
|
||||
0) doctest; lint; integrationtest;;
|
||||
1) checkEOL; unittest;;
|
||||
*) echo "ERROR: invalid usage"; exit 2;;
|
||||
esac
|
||||
}
|
||||
|
||||
threeNodes() {
|
||||
case "$NODE_INDEX" in
|
||||
0) doctest; lint; integrationtest;;
|
||||
1) checkEOL;;
|
||||
2) unittest;;
|
||||
*) echo "ERROR: invalid usage"; exit 2;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "$TOTAL_NODES" in
|
||||
"") oneNode;;
|
||||
1) oneNode;;
|
||||
2) twoNodes;;
|
||||
3) threeNodes;;
|
||||
*) echo "ERROR: invalid usage"; exit 2;;
|
||||
esac
|
||||
@@ -1,18 +0,0 @@
|
||||
echo "PUBLISH"
|
||||
|
||||
function exit_on_error {
|
||||
res=$?
|
||||
[[ ${res:-99} -eq 0 ]] || exit $res
|
||||
}
|
||||
|
||||
rm -rf build
|
||||
|
||||
npm install
|
||||
gulp
|
||||
npm test
|
||||
exit_on_error
|
||||
|
||||
echo ""
|
||||
echo "publish to npm"
|
||||
npm publish
|
||||
exit_on_error
|
||||
@@ -1,18 +0,0 @@
|
||||
echo "PUBLISH RELEASE CANDIDATE"
|
||||
|
||||
function exit_on_error {
|
||||
res=$?
|
||||
[[ ${res:-99} -eq 0 ]] || exit $res
|
||||
}
|
||||
|
||||
rm -rf build
|
||||
|
||||
npm install
|
||||
gulp
|
||||
npm test
|
||||
exit_on_error
|
||||
|
||||
echo ""
|
||||
echo "publish rc to npm"
|
||||
npm publish --tag beta
|
||||
exit_on_error
|
||||
@@ -250,7 +250,7 @@ export class Connection extends EventEmitter {
|
||||
this.ws = createWebSocket(this.url, this.config)
|
||||
|
||||
if (this.ws == null) {
|
||||
throw new Error('Connect: created null websocket')
|
||||
throw new XrplError('Connect: created null websocket')
|
||||
}
|
||||
|
||||
this.ws.on('error', (error) => this.onConnectionFailed(error))
|
||||
@@ -422,7 +422,7 @@ export class Connection extends EventEmitter {
|
||||
*/
|
||||
private async onceOpen(connectionTimeoutID: NodeJS.Timeout): Promise<void> {
|
||||
if (this.ws == null) {
|
||||
throw new Error('onceOpen: ws is null')
|
||||
throw new XrplError('onceOpen: ws is null')
|
||||
}
|
||||
|
||||
// Once the connection completes successfully, remove all old listeners
|
||||
@@ -436,7 +436,7 @@ export class Connection extends EventEmitter {
|
||||
// Handle a closed connection: reconnect if it was unexpected
|
||||
this.ws.once('close', (code, reason) => {
|
||||
if (this.ws == null) {
|
||||
throw new Error('onceClose: ws is null')
|
||||
throw new XrplError('onceClose: ws is null')
|
||||
}
|
||||
|
||||
this.clearHeartbeatInterval()
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
import * as assert from 'assert'
|
||||
import { EventEmitter } from 'events'
|
||||
|
||||
import { ValidationError, XrplError } from '../errors'
|
||||
import * as errors from '../errors'
|
||||
import { NotFoundError, ValidationError, XrplError } from '../errors'
|
||||
import {
|
||||
Request,
|
||||
Response,
|
||||
@@ -85,18 +84,19 @@ import {
|
||||
UnsubscribeResponse,
|
||||
} from '../models/methods'
|
||||
import { BaseRequest, BaseResponse } from '../models/methods/baseMethod'
|
||||
import autofill from '../sugar/autofill'
|
||||
import { getBalances, getXrpBalance } from '../sugar/balances'
|
||||
import getFee from '../sugar/fee'
|
||||
import getLedgerIndex from '../sugar/ledgerIndex'
|
||||
import getOrderbook from '../sugar/orderbook'
|
||||
import {
|
||||
autofill,
|
||||
ensureClassicAddress,
|
||||
getLedgerIndex,
|
||||
getOrderbook,
|
||||
getFee,
|
||||
getBalances,
|
||||
getXrpBalance,
|
||||
submit,
|
||||
submitSigned,
|
||||
submitReliable,
|
||||
submitSignedReliable,
|
||||
} from '../sugar/submit'
|
||||
import { ensureClassicAddress } from '../sugar/utils'
|
||||
} from '../sugar'
|
||||
import fundWallet from '../wallet/fundWallet'
|
||||
|
||||
import {
|
||||
@@ -394,7 +394,7 @@ class Client extends EventEmitter {
|
||||
>(req: T, resp: U): Promise<U> {
|
||||
if (!resp.result.marker) {
|
||||
return Promise.reject(
|
||||
new errors.NotFoundError('response does not have a next page'),
|
||||
new NotFoundError('response does not have a next page'),
|
||||
)
|
||||
}
|
||||
const nextPageRequest = { ...req, marker: resp.result.marker }
|
||||
|
||||
@@ -33,7 +33,7 @@ export default class RequestManager {
|
||||
public cancel(id: string | number): void {
|
||||
const promise = this.promisesAwaitingResponse.get(id)
|
||||
if (promise == null) {
|
||||
throw new Error(`No existing promise with id ${id}`)
|
||||
throw new XrplError(`No existing promise with id ${id}`)
|
||||
}
|
||||
clearTimeout(promise.timer)
|
||||
this.deletePromise(id)
|
||||
@@ -49,7 +49,7 @@ export default class RequestManager {
|
||||
public resolve(id: string | number, response: Response): void {
|
||||
const promise = this.promisesAwaitingResponse.get(id)
|
||||
if (promise == null) {
|
||||
throw new Error(`No existing promise with id ${id}`)
|
||||
throw new XrplError(`No existing promise with id ${id}`)
|
||||
}
|
||||
clearTimeout(promise.timer)
|
||||
promise.resolve(response)
|
||||
@@ -66,7 +66,7 @@ export default class RequestManager {
|
||||
public reject(id: string | number, error: Error): void {
|
||||
const promise = this.promisesAwaitingResponse.get(id)
|
||||
if (promise == null) {
|
||||
throw new Error(`No existing promise with id ${id}`)
|
||||
throw new XrplError(`No existing promise with id ${id}`)
|
||||
}
|
||||
clearTimeout(promise.timer)
|
||||
// TODO: figure out how to have a better stack trace for an error
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* eslint-disable max-classes-per-file -- Errors can be defined in the same file */
|
||||
import { inspect } from 'util'
|
||||
|
||||
// TODO: replace all `new Error`s with `new XrplError`s
|
||||
|
||||
/**
|
||||
* Base Error class for xrpl.js. All Errors thrown by xrpl.js should throw
|
||||
* XrplErrors.
|
||||
|
||||
@@ -34,10 +34,12 @@ export interface Signer {
|
||||
}
|
||||
|
||||
export interface Memo {
|
||||
Memo: {
|
||||
MemoData?: string
|
||||
MemoType?: string
|
||||
MemoFormat?: string
|
||||
}
|
||||
}
|
||||
|
||||
export type StreamType =
|
||||
| 'consensus'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BaseRequest, BaseResponse } from './baseMethod'
|
||||
import type { BaseRequest, BaseResponse } from './baseMethod'
|
||||
|
||||
/**
|
||||
* The ping command returns an acknowledgement, so that clients can test the
|
||||
@@ -17,7 +17,5 @@ export interface PingRequest extends BaseRequest {
|
||||
* @category Responses
|
||||
*/
|
||||
export interface PingResponse extends BaseResponse {
|
||||
// TODO: figure out if there's a better way to type this
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types -- actually should be an empty object
|
||||
result: {}
|
||||
result: { role?: string; unlimited?: boolean }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Amount, Currency, Path, StreamType } from '../common'
|
||||
import Offer from '../ledger/offer'
|
||||
import { Offer } from '../ledger'
|
||||
import { OfferCreate, Transaction } from '../transactions'
|
||||
import TransactionMetadata from '../transactions/metadata'
|
||||
|
||||
@@ -66,18 +66,17 @@ export interface SubscribeRequest extends BaseRequest {
|
||||
url_password?: string
|
||||
}
|
||||
|
||||
type BooksSnapshot = Offer[]
|
||||
|
||||
/**
|
||||
* Response expected from a {@link SubscribeRequest}.
|
||||
*
|
||||
* @category Responses
|
||||
*/
|
||||
export interface SubscribeResponse extends BaseResponse {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types -- actually should be an empty object
|
||||
result: {} | LedgerStreamResponse | BooksSnapshot
|
||||
result: Record<string, never> | LedgerStreamResponse | BooksSnapshot
|
||||
}
|
||||
|
||||
type BooksSnapshot = Offer[]
|
||||
|
||||
interface BaseStream {
|
||||
type: string
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Currency, StreamType } from '../common'
|
||||
|
||||
import { BaseRequest, BaseResponse } from './baseMethod'
|
||||
import type { BaseRequest, BaseResponse } from './baseMethod'
|
||||
|
||||
interface Book {
|
||||
taker_gets: Currency
|
||||
|
||||
@@ -144,11 +144,10 @@ export interface BaseTransaction {
|
||||
* validated or rejected.
|
||||
*/
|
||||
LastLedgerSequence?: number
|
||||
// TODO: Make Memo match the format of Signer (By including the Memo: wrapper inside the Interface)
|
||||
/**
|
||||
* Additional arbitrary information used to identify this transaction.
|
||||
*/
|
||||
Memos?: Array<{ Memo: Memo }>
|
||||
Memos?: Memo[]
|
||||
/**
|
||||
* Array of objects that represent a multi-signature which authorizes this
|
||||
* transaction.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
|
||||
import type { Client } from '..'
|
||||
import { XrplError } from '../errors'
|
||||
|
||||
const NUM_DECIMAL_PLACES = 6
|
||||
const BASE_10 = 10
|
||||
@@ -25,7 +26,7 @@ export default async function getFee(
|
||||
const baseFee = serverInfo.validated_ledger?.base_fee_xrp
|
||||
|
||||
if (baseFee == null) {
|
||||
throw new Error('getFee: Could not get base_fee_xrp from server_info')
|
||||
throw new XrplError('getFee: Could not get base_fee_xrp from server_info')
|
||||
}
|
||||
|
||||
const baseFeeXrp = new BigNumber(baseFee)
|
||||
|
||||
13
src/sugar/index.ts
Normal file
13
src/sugar/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export { default as autofill } from './autofill'
|
||||
|
||||
export { getBalances, getXrpBalance } from './balances'
|
||||
|
||||
export { default as getFee } from './fee'
|
||||
|
||||
export { default as getLedgerIndex } from './ledgerIndex'
|
||||
|
||||
export { default as getOrderbook } from './orderbook'
|
||||
|
||||
export * from './submit'
|
||||
|
||||
export * from './utils'
|
||||
@@ -1,76 +0,0 @@
|
||||
import { classicAddressToXAddress } from 'ripple-address-codec'
|
||||
import keypairs from 'ripple-keypairs'
|
||||
|
||||
import ECDSA from '../ecdsa'
|
||||
import { UnexpectedError } from '../errors'
|
||||
|
||||
export interface GeneratedAddress {
|
||||
xAddress: string
|
||||
classicAddress?: string
|
||||
secret: string
|
||||
}
|
||||
|
||||
interface GenerateAddressOptions {
|
||||
// The entropy to use to generate the seed.
|
||||
entropy?: Uint8Array | number[]
|
||||
|
||||
// The digital signature algorithm to generate an address for. Can be `ecdsa-secp256k1` (default) or `ed25519`.
|
||||
algorithm?: ECDSA
|
||||
|
||||
/*
|
||||
* Specifies whether the address is intended for use on a test network such as Testnet or Devnet.
|
||||
* If `true`, the address should only be used for testing, and will start with `T`.
|
||||
* If `false` (default), the address should only be used on mainnet, and will start with `X`.
|
||||
*/
|
||||
test?: boolean
|
||||
|
||||
// If `true`, return the classic address, in addition to the X-address.
|
||||
includeClassicAddress?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Move this function to be a static function of the Wallet Class.
|
||||
* TODO: Doc this function.
|
||||
*
|
||||
* @param options - Options for generating X-Address.
|
||||
* @returns A generated address.
|
||||
* @throws When cannot generate an address.
|
||||
*/
|
||||
function generateXAddress(
|
||||
options: GenerateAddressOptions = {},
|
||||
): GeneratedAddress {
|
||||
try {
|
||||
const generateSeedOptions: {
|
||||
entropy?: Uint8Array
|
||||
algorithm?: ECDSA
|
||||
} = {
|
||||
algorithm: options.algorithm,
|
||||
}
|
||||
if (options.entropy) {
|
||||
generateSeedOptions.entropy = Uint8Array.from(options.entropy)
|
||||
}
|
||||
const secret = keypairs.generateSeed(generateSeedOptions)
|
||||
const keypair = keypairs.deriveKeypair(secret)
|
||||
const classicAddress = keypairs.deriveAddress(keypair.publicKey)
|
||||
const returnValue: GeneratedAddress = {
|
||||
xAddress: classicAddressToXAddress(
|
||||
classicAddress,
|
||||
false,
|
||||
options.test ?? false,
|
||||
),
|
||||
secret,
|
||||
}
|
||||
if (options.includeClassicAddress) {
|
||||
returnValue.classicAddress = classicAddress
|
||||
}
|
||||
return returnValue
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new UnexpectedError(error.message)
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export { generateXAddress }
|
||||
@@ -6,7 +6,7 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { decode, encode } from 'ripple-binary-codec'
|
||||
|
||||
import { ValidationError } from '../../errors'
|
||||
import { ValidationError, XrplError } from '../../errors'
|
||||
import type { Ledger } from '../../models/ledger'
|
||||
import { LedgerEntry } from '../../models/ledger'
|
||||
import { Transaction } from '../../models/transactions'
|
||||
@@ -61,7 +61,7 @@ function addLengthPrefix(hex: string): string {
|
||||
]) + hex
|
||||
)
|
||||
}
|
||||
throw new Error('Variable integer overflow.')
|
||||
throw new XrplError('Variable integer overflow.')
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,7 +76,6 @@ export function hashSignedTx(tx: Transaction | string): string {
|
||||
let txObject: Transaction
|
||||
if (typeof tx === 'string') {
|
||||
txBlob = tx
|
||||
// TODO: type ripple-binary-codec with Transaction
|
||||
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Required until updated in binary codec. */
|
||||
txObject = decode(tx) as unknown as Transaction
|
||||
} else {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { XrplError } from '../../../errors'
|
||||
import hashPrefix from '../hashPrefix'
|
||||
import sha512Half from '../sha512Half'
|
||||
|
||||
@@ -54,7 +55,7 @@ class InnerNode extends Node {
|
||||
} else if (existingNode instanceof Leaf) {
|
||||
if (existingNode.tag === tag) {
|
||||
// Collision
|
||||
throw new Error(
|
||||
throw new XrplError(
|
||||
'Tried to add a node to a SHAMap that was already in there.',
|
||||
)
|
||||
} else {
|
||||
@@ -79,7 +80,7 @@ class InnerNode extends Node {
|
||||
*/
|
||||
public setNode(slot: number, node: Node): void {
|
||||
if (slot < 0 || slot > SLOT_MAX) {
|
||||
throw new Error('Invalid slot: slot must be between 0-15.')
|
||||
throw new XrplError('Invalid slot: slot must be between 0-15.')
|
||||
}
|
||||
this.leaves[slot] = node
|
||||
this.empty = false
|
||||
@@ -94,7 +95,7 @@ class InnerNode extends Node {
|
||||
*/
|
||||
public getNode(slot: number): Node | undefined {
|
||||
if (slot < 0 || slot > SLOT_MAX) {
|
||||
throw new Error('Invalid slot: slot must be between 0-15.')
|
||||
throw new XrplError('Invalid slot: slot must be between 0-15.')
|
||||
}
|
||||
return this.leaves[slot]
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { XrplError } from '../../../errors'
|
||||
import hashPrefix from '../hashPrefix'
|
||||
import sha512Half from '../sha512Half'
|
||||
|
||||
@@ -30,13 +31,13 @@ class Leaf extends Node {
|
||||
/**
|
||||
* Add item to Leaf.
|
||||
*
|
||||
* @param _tag - Index of the Node.
|
||||
* @param _node - Node to insert.
|
||||
* @param tag - Index of the Node.
|
||||
* @param node - Node to insert.
|
||||
* @throws When called, because LeafNodes cannot addItem.
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this -- no `this` needed here
|
||||
public addItem(_tag: string, _node: Node): void {
|
||||
throw new Error('Cannot call addItem on a LeafNode')
|
||||
public addItem(tag: string, node: Node): void {
|
||||
throw new XrplError('Cannot call addItem on a LeafNode')
|
||||
this.addItem(tag, node)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,7 +61,7 @@ class Leaf extends Node {
|
||||
return sha512Half(txNodePrefix + this.data + this.tag)
|
||||
}
|
||||
default:
|
||||
throw new Error('Tried to hash a SHAMap node of unknown type.')
|
||||
throw new XrplError('Tried to hash a SHAMap node of unknown type.')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import { Response } from '../models/methods'
|
||||
|
||||
import getBalanceChanges from './balanceChanges'
|
||||
import { deriveKeypair, deriveXAddress } from './derive'
|
||||
import { generateXAddress } from './generateAddress'
|
||||
import {
|
||||
hashSignedTx,
|
||||
hashTx,
|
||||
@@ -124,7 +123,6 @@ export {
|
||||
isValidSecret,
|
||||
isValidAddress,
|
||||
hashes,
|
||||
generateXAddress,
|
||||
deriveKeypair,
|
||||
deriveXAddress,
|
||||
signPaymentChannelClaim,
|
||||
|
||||
@@ -5,12 +5,15 @@ import { isValidClassicAddress } from 'ripple-address-codec'
|
||||
|
||||
import type { Client } from '..'
|
||||
import { RippledError, XRPLFaucetError } from '../errors'
|
||||
import { GeneratedAddress } from '../utils/generateAddress'
|
||||
|
||||
import Wallet from '.'
|
||||
|
||||
interface FaucetWallet {
|
||||
account: GeneratedAddress
|
||||
account: {
|
||||
xAddress: string
|
||||
classicAddress?: string
|
||||
secret: string
|
||||
}
|
||||
amount: number
|
||||
balance: number
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ import { sign as signWithKeypair, verify } from 'ripple-keypairs'
|
||||
|
||||
import { ValidationError } from '../errors'
|
||||
import { Signer } from '../models/common'
|
||||
import { Transaction } from '../models/transactions'
|
||||
import { validateBaseTransaction } from '../models/transactions/common'
|
||||
import { Transaction, validate } from '../models/transactions'
|
||||
|
||||
import Wallet from '.'
|
||||
|
||||
@@ -37,11 +36,9 @@ function multisign(transactions: Array<Transaction | string>): string {
|
||||
|
||||
/*
|
||||
* This will throw a more clear error for JS users if any of the supplied transactions has incorrect formatting
|
||||
* TODO: Replace this with validate() (The general validation function for all Transactions)
|
||||
* also make validate accept '| Transaction' to avoid type casting here.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- validate does not accept Transaction type
|
||||
validateBaseTransaction(tx as unknown as Record<string, unknown>)
|
||||
validate(tx as unknown as Record<string, unknown>)
|
||||
if (tx.Signers == null || tx.Signers.length === 0) {
|
||||
throw new ValidationError(
|
||||
"For multisigning all transactions must include a Signers field containing an array of signatures. You may have forgotten to pass the 'forMultisign' parameter when signing.",
|
||||
@@ -162,7 +159,9 @@ function addressToBigNumber(address: string): BigNumber {
|
||||
|
||||
function getDecodedTransaction(txOrBlob: Transaction | string): Transaction {
|
||||
if (typeof txOrBlob === 'object') {
|
||||
return txOrBlob
|
||||
// We need this to handle X-addresses in multisigning
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- We are casting here to get strong typing
|
||||
return decode(encode(txOrBlob)) as unknown as Transaction
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- We are casting here to get strong typing
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { BookOffersRequest, ValidationError } from 'xrpl-local'
|
||||
import { OfferFlags } from 'xrpl-local/models/ledger/offer'
|
||||
import { BookOffersRequest } from 'xrpl-local'
|
||||
import { ValidationError, XrplError } from 'xrpl-local/errors'
|
||||
import { OfferFlags } from 'xrpl-local/models/ledger'
|
||||
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
@@ -52,7 +53,7 @@ function normalRippledResponse(
|
||||
) {
|
||||
return rippled.book_offers.fabric.requestBookOffersAsksResponse(request)
|
||||
}
|
||||
throw new Error('unexpected end')
|
||||
throw new XrplError('unexpected end')
|
||||
}
|
||||
|
||||
function xrpRippledResponse(
|
||||
|
||||
@@ -255,7 +255,7 @@ describe('Connection', function () {
|
||||
// overload websocket send on open when _ws exists
|
||||
this.client.connection.ws.send = function (_0, _1, _2): void {
|
||||
// recent ws throws this error instead of calling back
|
||||
throw new Error('WebSocket is not open: readyState 0 (CONNECTING)')
|
||||
throw new XrplError('WebSocket is not open: readyState 0 (CONNECTING)')
|
||||
}
|
||||
const request = { command: 'subscribe', streams: ['ledger'] }
|
||||
this.client.connection.request(request)
|
||||
@@ -340,20 +340,22 @@ describe('Connection', function () {
|
||||
if (connectsCount === num) {
|
||||
if (disconnectsCount !== num) {
|
||||
done(
|
||||
new Error(
|
||||
new XrplError(
|
||||
`disconnectsCount must be equal to ${num}(got ${disconnectsCount} instead)`,
|
||||
),
|
||||
)
|
||||
} else if (reconnectsCount !== num) {
|
||||
done(
|
||||
new Error(
|
||||
new XrplError(
|
||||
`reconnectsCount must be equal to ${num} (got ${reconnectsCount} instead)`,
|
||||
),
|
||||
)
|
||||
// eslint-disable-next-line no-negated-condition -- Necessary
|
||||
} else if (code !== 1006) {
|
||||
done(
|
||||
new Error(`disconnect must send code 1006 (got ${code} instead)`),
|
||||
new XrplError(
|
||||
`disconnect must send code 1006 (got ${code} instead)`,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
done()
|
||||
@@ -399,14 +401,14 @@ describe('Connection', function () {
|
||||
this.timeout(5000)
|
||||
// fail on reconnect/connection
|
||||
this.client.connection.reconnect = async (): Promise<void> => {
|
||||
throw new Error('error on reconnect')
|
||||
throw new XrplError('error on reconnect')
|
||||
}
|
||||
// Hook up a listener for the reconnect error event
|
||||
this.client.on('error', (error, message) => {
|
||||
if (error === 'reconnect' && message === 'error on reconnect') {
|
||||
return done()
|
||||
}
|
||||
return done(new Error('Expected error on reconnect'))
|
||||
return done(new XrplError('Expected error on reconnect'))
|
||||
})
|
||||
// Trigger a heartbeat
|
||||
this.client.connection.heartbeat()
|
||||
@@ -422,7 +424,7 @@ describe('Connection', function () {
|
||||
|
||||
it('should emit disconnected event with code 1006 (CLOSE_ABNORMAL)', function (done) {
|
||||
this.client.connection.once('error', (error) => {
|
||||
done(new Error(`should not throw error, got ${String(error)}`))
|
||||
done(new XrplError(`should not throw error, got ${String(error)}`))
|
||||
})
|
||||
this.client.connection.once('disconnected', (code) => {
|
||||
assert.strictEqual(code, 1006)
|
||||
@@ -597,14 +599,14 @@ describe('Connection', function () {
|
||||
it('should try to reconnect on empty subscribe response on reconnect', function (done) {
|
||||
this.timeout(23000)
|
||||
this.client.on('error', (error) => {
|
||||
done(error || new Error('Should not emit error.'))
|
||||
done(error || new XrplError('Should not emit error.'))
|
||||
})
|
||||
let disconnectedCount = 0
|
||||
this.client.on('connected', () => {
|
||||
done(
|
||||
disconnectedCount === 1
|
||||
? undefined
|
||||
: new Error('Wrong number of disconnects'),
|
||||
: new XrplError('Wrong number of disconnects'),
|
||||
)
|
||||
})
|
||||
this.client.on('disconnected', () => {
|
||||
@@ -622,7 +624,7 @@ describe('Connection', function () {
|
||||
.request({
|
||||
command: 'test_garbage',
|
||||
})
|
||||
.then(() => new Error('Should not have succeeded'))
|
||||
.then(() => new XrplError('Should not have succeeded'))
|
||||
.catch(done())
|
||||
})
|
||||
|
||||
|
||||
@@ -19,12 +19,11 @@ describe('Utility method integration tests', function () {
|
||||
const response = await (this.client as Client).request({
|
||||
command: 'ping',
|
||||
})
|
||||
const expected = {
|
||||
id: 0,
|
||||
const expected: unknown = {
|
||||
result: { role: 'admin', unlimited: true },
|
||||
type: 'response',
|
||||
}
|
||||
assert.deepEqual(_.omit(response, 'id'), _.omit(expected, 'id'))
|
||||
assert.deepEqual(_.omit(response, 'id'), expected)
|
||||
})
|
||||
|
||||
it('random', async function () {
|
||||
|
||||
@@ -3,6 +3,7 @@ import _ from 'lodash'
|
||||
import { Server as WebSocketServer } from 'ws'
|
||||
|
||||
import type { Request } from '../src'
|
||||
import { XrplError } from '../src/errors'
|
||||
import type {
|
||||
BaseResponse,
|
||||
ErrorResponse,
|
||||
@@ -15,7 +16,7 @@ function createResponse(
|
||||
response: Record<string, unknown>,
|
||||
): string {
|
||||
if (!('type' in response) && !('error' in response)) {
|
||||
throw new Error(
|
||||
throw new XrplError(
|
||||
`Bad response format. Must contain \`type\` or \`error\`. ${JSON.stringify(
|
||||
response,
|
||||
)}`,
|
||||
@@ -65,10 +66,10 @@ export default function createMockRippled(port: number): MockedWebSocketServer {
|
||||
try {
|
||||
request = JSON.parse(requestJSON)
|
||||
if (request.id == null) {
|
||||
throw new Error(`Request has no id: ${requestJSON}`)
|
||||
throw new XrplError(`Request has no id: ${requestJSON}`)
|
||||
}
|
||||
if (request.command == null) {
|
||||
throw new Error(`Request has no command: ${requestJSON}`)
|
||||
throw new XrplError(`Request has no id: ${requestJSON}`)
|
||||
}
|
||||
if (request.command === 'ping') {
|
||||
ping(conn, request)
|
||||
@@ -77,7 +78,7 @@ export default function createMockRippled(port: number): MockedWebSocketServer {
|
||||
} else if (request.command in mock.responses) {
|
||||
conn.send(createResponse(request, mock.getResponse(request)))
|
||||
} else {
|
||||
throw new Error(
|
||||
throw new XrplError(
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- We know it's there
|
||||
`No event handler registered in mock rippled for ${request.command}`,
|
||||
)
|
||||
@@ -117,14 +118,14 @@ export default function createMockRippled(port: number): MockedWebSocketServer {
|
||||
| ((r: Request) => Response | ErrorResponse),
|
||||
): void {
|
||||
if (typeof command !== 'string') {
|
||||
throw new Error('command is not a string')
|
||||
throw new XrplError('command is not a string')
|
||||
}
|
||||
if (
|
||||
typeof response === 'object' &&
|
||||
!('type' in response) &&
|
||||
!('error' in response)
|
||||
) {
|
||||
throw new Error(
|
||||
throw new XrplError(
|
||||
`Bad response format. Must contain \`type\` or \`error\`. ${JSON.stringify(
|
||||
response,
|
||||
)}`,
|
||||
@@ -135,7 +136,7 @@ export default function createMockRippled(port: number): MockedWebSocketServer {
|
||||
|
||||
mock.getResponse = (request: Request): Record<string, unknown> => {
|
||||
if (!(request.command in mock.responses)) {
|
||||
throw new Error(`No handler for ${request.command}`)
|
||||
throw new XrplError(`No handler for ${request.command}`)
|
||||
}
|
||||
const functionOrObject = mock.responses[request.command]
|
||||
if (typeof functionOrObject === 'function') {
|
||||
|
||||
@@ -40,6 +40,35 @@ describe('Payment', function () {
|
||||
assert.doesNotThrow(() => validate(paymentTransaction))
|
||||
})
|
||||
|
||||
it(`Verifies memos correctly`, function () {
|
||||
paymentTransaction.Memos = [
|
||||
{
|
||||
Memo: {
|
||||
MemoData: '32324324',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
assert.doesNotThrow(() => validate(paymentTransaction))
|
||||
})
|
||||
|
||||
it(`Verifies memos correctly`, function () {
|
||||
paymentTransaction.Memos = [
|
||||
{
|
||||
Memo: {
|
||||
MemoData: '32324324',
|
||||
MemoType: 121221,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
assert.throws(
|
||||
() => validate(paymentTransaction),
|
||||
ValidationError,
|
||||
'BaseTransaction: invalid Memos',
|
||||
)
|
||||
})
|
||||
|
||||
it(`throws when Amount is missing`, function () {
|
||||
delete paymentTransaction.Amount
|
||||
assert.throws(
|
||||
|
||||
@@ -4,6 +4,8 @@ import path from 'path'
|
||||
|
||||
import { Client } from 'xrpl-local'
|
||||
|
||||
import { XrplError } from '../src/errors'
|
||||
|
||||
/**
|
||||
* Client Test Runner.
|
||||
*
|
||||
@@ -27,10 +29,10 @@ describe('Client', function () {
|
||||
)
|
||||
for (const methodName of allPublicMethods) {
|
||||
if (!allTestedMethods.has(methodName)) {
|
||||
// TODO: Once migration is complete, remove `.skip()` so that missing tests are reported as failures.
|
||||
// eslint-disable-next-line mocha/no-skipped-tests -- See above TODO
|
||||
/** TODO: Remove the skip, rename methods. */
|
||||
// eslint-disable-next-line mocha/no-skipped-tests -- skip these tests for now.
|
||||
it.skip(`${methodName} - no test suite found`, function () {
|
||||
throw new Error(
|
||||
throw new XrplError(
|
||||
`Test file not found! Create file "test/client/${methodName}.ts".`,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -10,17 +10,15 @@ const HEX_ZERO =
|
||||
/**
|
||||
* Generates data to hash for testing.
|
||||
*
|
||||
* @param v - TODO: fill in.
|
||||
* @param int - TODO: fill in.
|
||||
* @returns TODO: fill in.
|
||||
*/
|
||||
// eslint-disable-next-line id-length -- TODO: figure out what this variable means
|
||||
function intToVuc(v: number): string {
|
||||
function intToVuc(int: number): string {
|
||||
let ret = ''
|
||||
|
||||
// eslint-disable-next-line id-length -- TODO: figure out what this variable means
|
||||
for (let i = 0; i < 32; i++) {
|
||||
for (let it = 0; it < 32; it++) {
|
||||
ret += '0'
|
||||
ret += v.toString(16).toUpperCase()
|
||||
ret += int.toString(16).toUpperCase()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any -- Necessary for these methods TODO: further cleanup */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types -- Necessary for these methods TODO: further cleanup */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any -- required for
|
||||
assertions. */
|
||||
import net from 'net'
|
||||
|
||||
import { assert } from 'chai'
|
||||
@@ -31,8 +31,8 @@ export function assertResultMatch(
|
||||
if (expected.txJSON) {
|
||||
assert(response.txJSON)
|
||||
assert.deepEqual(
|
||||
JSON.parse(response.txJSON as string),
|
||||
JSON.parse(expected.txJSON as string),
|
||||
JSON.parse(response.txJSON),
|
||||
JSON.parse(expected.txJSON),
|
||||
'checkResult: txJSON must match',
|
||||
)
|
||||
}
|
||||
@@ -58,7 +58,7 @@ export function assertResultMatch(
|
||||
* @param message - Expected error message/substring of the error message.
|
||||
*/
|
||||
export async function assertRejects(
|
||||
promise: PromiseLike<any>,
|
||||
promise: PromiseLike<unknown>,
|
||||
instanceOf: any,
|
||||
message?: string | RegExp,
|
||||
): Promise<void> {
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { UnexpectedError } from 'xrpl-local'
|
||||
import ECDSA from 'xrpl-local/ecdsa'
|
||||
import { generateXAddress } from 'xrpl-local/utils/generateAddress'
|
||||
|
||||
import responses from '../fixtures/responses'
|
||||
|
||||
describe('generateAddress', function () {
|
||||
it('generateAddress', function () {
|
||||
assert.deepEqual(
|
||||
generateXAddress({ entropy: new Array(16).fill(0) }),
|
||||
|
||||
// THEN we get the expected return value
|
||||
responses.generateXAddress,
|
||||
)
|
||||
})
|
||||
|
||||
it('generateAddress invalid entropy', function () {
|
||||
assert.throws(() => {
|
||||
/*
|
||||
* GIVEN entropy of 1 byte
|
||||
* WHEN generating an address
|
||||
*/
|
||||
generateXAddress({ entropy: new Array(1).fill(0) })
|
||||
|
||||
/*
|
||||
* THEN an UnexpectedError is thrown
|
||||
* because 16 bytes of entropy are required
|
||||
*/
|
||||
}, UnexpectedError)
|
||||
})
|
||||
|
||||
it('generateAddress with no options object', function () {
|
||||
// GIVEN no options
|
||||
|
||||
// WHEN generating an address
|
||||
const account = generateXAddress()
|
||||
|
||||
// THEN we get an object with an xAddress starting with 'x' and a secret starting with 's'
|
||||
assert(account.xAddress.startsWith('X'), 'Address must start with `X`')
|
||||
assert(account.secret.startsWith('s'), 'Secret must start with `s`')
|
||||
})
|
||||
|
||||
it('generateAddress with empty options object', function () {
|
||||
// GIVEN an empty options object
|
||||
const options = {}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = generateXAddress(options)
|
||||
|
||||
// THEN we get an object with an xAddress starting with 'x' and a secret starting with 's'
|
||||
assert(account.xAddress.startsWith('X'), 'Address must start with `X`')
|
||||
assert(account.secret.startsWith('s'), 'Secret must start with `s`')
|
||||
})
|
||||
|
||||
it('generateAddress with algorithm `ecdsa-secp256k1`', function () {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1'
|
||||
const options = {
|
||||
algorithm: ECDSA.secp256k1,
|
||||
includeClassicAddress: true,
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = generateXAddress(options)
|
||||
|
||||
// THEN we get an object with an address starting with 'r' and a secret starting with 's' (not 'sEd')
|
||||
assert(
|
||||
account.classicAddress?.startsWith('r'),
|
||||
'Address must start with `r`',
|
||||
)
|
||||
assert.deepEqual(
|
||||
account.secret.slice(0, 1),
|
||||
's',
|
||||
`Secret ${account.secret} must start with 's'`,
|
||||
)
|
||||
assert.notStrictEqual(
|
||||
account.secret.slice(0, 3),
|
||||
'sEd',
|
||||
`secp256k1 secret ${account.secret} must not start with 'sEd'`,
|
||||
)
|
||||
})
|
||||
|
||||
it('generateAddress with algorithm `ed25519`', function () {
|
||||
// GIVEN we want to use 'ed25519'
|
||||
const options = {
|
||||
algorithm: ECDSA.ed25519,
|
||||
includeClassicAddress: true,
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = generateXAddress(options)
|
||||
|
||||
// THEN we get an object with an address starting with 'r' and a secret starting with 'sEd'
|
||||
assert(
|
||||
account.classicAddress?.startsWith('r'),
|
||||
'Address must start with `r`',
|
||||
)
|
||||
assert.deepEqual(
|
||||
account.secret.slice(0, 3),
|
||||
'sEd',
|
||||
`Ed25519 secret ${account.secret} must start with 'sEd'`,
|
||||
)
|
||||
})
|
||||
|
||||
it('generateAddress with algorithm `ecdsa-secp256k1` and given entropy', function () {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options = {
|
||||
algorithm: ECDSA.secp256k1,
|
||||
entropy: new Array(16).fill(0),
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, responses.generateXAddress)
|
||||
})
|
||||
|
||||
it('generateAddress with algorithm `ed25519` and given entropy', function () {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options = {
|
||||
algorithm: ECDSA.ed25519,
|
||||
entropy: new Array(16).fill(0),
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
xAddress: 'X7xq1YJ4xmLSGGLhuakFQB9CebWYthQkgsvFC4LGFH871HB',
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE',
|
||||
})
|
||||
})
|
||||
|
||||
it('generateAddress with algorithm `ecdsa-secp256k1` and given entropy; include classic address', function () {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options = {
|
||||
algorithm: ECDSA.secp256k1,
|
||||
entropy: new Array(16).fill(0),
|
||||
includeClassicAddress: true,
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, responses.generateAddress)
|
||||
})
|
||||
|
||||
it('generateAddress with algorithm `ed25519` and given entropy; include classic address', function () {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options = {
|
||||
algorithm: ECDSA.ed25519,
|
||||
entropy: new Array(16).fill(0),
|
||||
includeClassicAddress: true,
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
xAddress: 'X7xq1YJ4xmLSGGLhuakFQB9CebWYthQkgsvFC4LGFH871HB',
|
||||
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE',
|
||||
classicAddress: 'r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7',
|
||||
})
|
||||
})
|
||||
|
||||
it('generateAddress with algorithm `ecdsa-secp256k1` and given entropy; include classic address; for test network use', function () {
|
||||
// GIVEN we want to use 'ecdsa-secp256k1' with entropy of zero
|
||||
const options = {
|
||||
algorithm: ECDSA.secp256k1,
|
||||
entropy: new Array(16).fill(0),
|
||||
includeClassicAddress: true,
|
||||
test: true,
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
const response = {
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
...responses.generateAddress,
|
||||
xAddress: 'TVG3TcCD58BD6MZqsNuTihdrhZwR8SzvYS8U87zvHsAcNw4',
|
||||
}
|
||||
assert.deepEqual(account, response)
|
||||
})
|
||||
|
||||
it('generateAddress with algorithm `ed25519` and given entropy; include classic address; for test network use', function () {
|
||||
// GIVEN we want to use 'ed25519' with entropy of zero
|
||||
const options = {
|
||||
algorithm: ECDSA.ed25519,
|
||||
entropy: new Array(16).fill(0),
|
||||
includeClassicAddress: true,
|
||||
test: true,
|
||||
}
|
||||
|
||||
// WHEN generating an address
|
||||
const account = generateXAddress(options)
|
||||
|
||||
// THEN we get the expected return value
|
||||
assert.deepEqual(account, {
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
xAddress: 'T7t4HeTMF5tT68agwuVbJwu23ssMPeh8dDtGysZoQiij1oo',
|
||||
secret: 'sEdSJHS4oiAdz7w2X2ni1gFiqtbJHqE',
|
||||
classicAddress: 'r9zRhGr7b6xPekLvT6wP4qNdWMryaumZS7',
|
||||
})
|
||||
})
|
||||
|
||||
it('generateAddress for test network use', function () {
|
||||
// GIVEN we want an address for test network use
|
||||
const options = { test: true }
|
||||
|
||||
// WHEN generating an address
|
||||
const account = generateXAddress(options)
|
||||
|
||||
// THEN we get an object with xAddress starting with 'T' and a secret starting with 's'
|
||||
|
||||
// generateAddress return value always includes xAddress to encourage X-address adoption
|
||||
assert.deepEqual(
|
||||
account.xAddress.slice(0, 1),
|
||||
'T',
|
||||
'Test addresses start with T',
|
||||
)
|
||||
|
||||
assert.deepEqual(
|
||||
account.secret.slice(0, 1),
|
||||
's',
|
||||
`Secret ${account.secret} must start with 's'`,
|
||||
)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user