diff --git a/packages/ripple-binary-codec/test/binary-serializer.test.js b/packages/ripple-binary-codec/test/binary-serializer.test.js index 0e28ef27..46412fa3 100644 --- a/packages/ripple-binary-codec/test/binary-serializer.test.js +++ b/packages/ripple-binary-codec/test/binary-serializer.test.js @@ -111,6 +111,11 @@ const UNLReport = { meta: require('./fixtures/unl-report-meta-binary.json'), } +const Remit = { + tx: require('./fixtures/remit-tx.json'), + binary: require('./fixtures/remit-binary.json'), +} + function bytesListTest() { const list = new BytesList() .put(Buffer.from([0])) @@ -291,6 +296,12 @@ function nfTokenTest() { } } +function RemitTest() { + test('can serialize Remit', () => { + expect(encode(Remit.tx)).toEqual(Remit.binary) + }) +} + describe('Binary Serialization', function () { describe('nestedObjectTests', nestedObjectTests) describe('BytesList', bytesListTest) @@ -304,4 +315,5 @@ describe('Binary Serialization', function () { describe('TicketTest', ticketTest) describe('NFToken', nfTokenTest) describe('UNLReport', UNLReportTest) + describe('Remit', RemitTest) }) diff --git a/packages/ripple-binary-codec/test/fixtures/remit-binary.json b/packages/ripple-binary-codec/test/fixtures/remit-binary.json new file mode 100644 index 00000000..08b71aec --- /dev/null +++ b/packages/ripple-binary-codec/test/fixtures/remit-binary.json @@ -0,0 +1 @@ +"12005F22000000002403EDEB4A2E00000001201B03EE5D3150116F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B68400000000000000C732102F9E33F16DF9507705EC954E3F94EB5F10D1FC4A354606DBE6297DBB1096FE65474473045022100E3FAE0EDEC3D6A8FF6D81BC9CF8288A61B7EEDE8071E90FF9314CB4621058D10022043545CF631706D700CEE65A1DB83EFDD185413808292D9D90F14D87D3DC2D8CB701A04DEADBEEF81147990EC5D1D8DF69E070A968D4B186986FDF06ED0831449FF0C73CA6AF9733DA805F76CA2C37776B7C46B806314757C4A9ED08284D61F3D8807280795F858BAB61DE05C220000000150156F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B7504DEADBEEFE1F05CE05B6140000000000003E8E1E05B61D4838D7EA4C68000000000000000000000000000555344000000000006B80F0F1D98AEDA846ED981F741C398FB2C4FD1E1F100136320AED08CC1F50DD5F23A1948AF86153A3F3B7593E5EC77D65A02BB1B29E05AB6AE" diff --git a/packages/ripple-binary-codec/test/fixtures/remit-tx.json b/packages/ripple-binary-codec/test/fixtures/remit-tx.json new file mode 100644 index 00000000..35b72bb4 --- /dev/null +++ b/packages/ripple-binary-codec/test/fixtures/remit-tx.json @@ -0,0 +1,39 @@ +{ + "TransactionType": "Remit", + "Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo", + "Destination": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy", + "DestinationTag": 1, + "Fee": "12", + "Flags": 0, + "LastLedgerSequence": 65953073, + "Sequence": 65923914, + "SigningPubKey": "02F9E33F16DF9507705EC954E3F94EB5F10D1FC4A354606DBE6297DBB1096FE654", + "TxnSignature": "3045022100E3FAE0EDEC3D6A8FF6D81BC9CF8288A61B7EEDE8071E90FF9314CB4621058D10022043545CF631706D700CEE65A1DB83EFDD185413808292D9D90F14D87D3DC2D8CB", + "Amounts": [ + { + "AmountEntry": { + "Amount": "1000" + } + }, + { + "AmountEntry": { + "Amount": { + "currency": "USD", + "issuer": "rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX", + "value": "1" + } + } + } + ], + "MintURIToken": { + "URI": "DEADBEEF", + "Digest": "6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B", + "Flags": 1 + }, + "URITokenIDs": [ + "AED08CC1F50DD5F23A1948AF86153A3F3B7593E5EC77D65A02BB1B29E05AB6AE" + ], + "InvoiceID": "6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B", + "Blob": "DEADBEEF", + "Inform": "rB5Ux4Lv2nRx6eeoAAsZmtctnBQ2LiACnk" +} diff --git a/packages/xrpl/src/models/common/index.ts b/packages/xrpl/src/models/common/index.ts index 65f64938..da0b946a 100644 --- a/packages/xrpl/src/models/common/index.ts +++ b/packages/xrpl/src/models/common/index.ts @@ -17,6 +17,8 @@ export interface IssuedCurrencyAmount extends IssuedCurrency { export type Amount = IssuedCurrencyAmount | string +export type AmountEntry = Amount + export interface Signer { Signer: { Account: string @@ -205,3 +207,21 @@ export interface EmitDetails { EmitHookHash: string EmitParentTxnID: string } + +/** + * The object that describes the uritoken in MintURIToken. + */ +export interface MintURIToken { + /** + * + */ + URI: string + /** + * + */ + Digest?: string + /** + * The flags that are set on the uritoken. + */ + Flags?: number +} diff --git a/packages/xrpl/src/models/transactions/index.ts b/packages/xrpl/src/models/transactions/index.ts index b88d4d9f..fbe05777 100644 --- a/packages/xrpl/src/models/transactions/index.ts +++ b/packages/xrpl/src/models/transactions/index.ts @@ -44,8 +44,9 @@ export { } from './paymentChannelClaim' export { PaymentChannelCreate } from './paymentChannelCreate' export { PaymentChannelFund } from './paymentChannelFund' -export { SetRegularKey } from './setRegularKey' +export { Remit } from './remit' export { SetHookFlagsInterface, SetHookFlags, SetHook } from './setHook' +export { SetRegularKey } from './setRegularKey' export { SignerListSet } from './signerListSet' export { TicketCreate } from './ticketCreate' export { TrustSetFlagsInterface, TrustSetFlags, TrustSet } from './trustSet' diff --git a/packages/xrpl/src/models/transactions/remit.ts b/packages/xrpl/src/models/transactions/remit.ts new file mode 100644 index 00000000..4a3324df --- /dev/null +++ b/packages/xrpl/src/models/transactions/remit.ts @@ -0,0 +1,200 @@ +import { ValidationError } from '../../errors' +import { AmountEntry, MintURIToken } from '../common' +import { isHex } from '../utils' + +import { BaseTransaction, validateBaseTransaction } from './common' + +const MAX_URI_LENGTH = 256 +const DIGEST_LENGTH = 64 +const MAX_ARRAY_LENGTH = 32 +const MAX_BLOB_LENGTH = 1024 + +/** + * A Remit transaction represents a transfer of value from one account to + * another. + * + * @category Transaction Models + */ +export interface Remit extends BaseTransaction { + TransactionType: 'Remit' + /** The unique address of the account receiving the payment. */ + Destination: string + /** + * Arbitrary tag that identifies the reason for the payment to the + * destination, or a hosted recipient to pay. + */ + DestinationTag?: number + /** + * + */ + Amounts?: AmountEntry[] + /** + * + */ + MintURIToken?: MintURIToken + /** + * Arbitrary 256-bit hash representing a specific reason or identifier for + * this payment. + */ + InvoiceID?: string + /** + * Hex value representing a VL Blob. + */ + Blob?: string + /** The unique address of the account to inform */ + Inform?: string +} + +/** + * Verify the form and type of a Remit at runtime. + * + * @param tx - A Remit Transaction. + * @throws When the Remit is malformed. + */ +// eslint-disable-next-line complexity -- ignore +export function validateRemit(tx: Record): void { + validateBaseTransaction(tx) + + if (tx.Amounts !== undefined) { + checkAmounts(tx) + } + if (tx.URITokenIDs !== undefined) { + checkURITokenIDs(tx) + } + if (tx.Destination === tx.Account) { + throw new ValidationError( + 'Remit: Destination must not be equal to the account', + ) + } + if (tx.DestinationTag != null && typeof tx.DestinationTag !== 'number') { + throw new ValidationError('Remit: DestinationTag must be a number') + } + if (tx.Inform === tx.Account || tx.inform === tx.Destination) { + throw new ValidationError( + 'Remit: Inform must not be equal to the account or destination', + ) + } + + if (tx.MintURIToken !== undefined) { + checkMintURIToken(tx) + } + + if (tx.Blob !== undefined && typeof tx.Blob !== 'string') { + throw new ValidationError('Remit: Blob must be a string') + } + + if (tx.Blob !== undefined && typeof tx.Blob === 'string') { + if (!isHex(tx.Blob)) { + throw new ValidationError('Remit: Blob must be a hex string') + } + if (tx.Blob.length > MAX_BLOB_LENGTH) { + throw new ValidationError('Remit: max size Blob') + } + } +} + +function checkAmounts(tx: Record): void { + if (!Array.isArray(tx.Amounts)) { + throw new ValidationError('Remit: Amounts must be an array') + } + if (tx.Amounts.length < 1) { + throw new ValidationError('Remit: empty field Amounts') + } + if (tx.Amounts.length > MAX_ARRAY_LENGTH) { + throw new ValidationError('Remit: max field Amounts') + } + const seen = new Set() + let seenXrp = false + for (const amount of tx.Amounts) { + if ( + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- ignore + amount.AmountEntry === undefined || + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- ignore + typeof amount.AmountEntry !== 'object' + ) { + throw new ValidationError('Remit: invalid Amounts.AmountEntry') + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- ignore + if (typeof amount.AmountEntry.Amount === 'string') { + // eslint-disable-next-line max-depth -- ignore + if (seenXrp) { + throw new ValidationError( + 'Remit: Duplicate Native amounts are not allowed', + ) + } + seenXrp = true + } else { + // eslint-disable-next-line max-len -- ignore + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access -- ignore + const amountKey = `${amount.AmountEntry.Amount.currency}:${amount.AmountEntry.Amount.issuer}` + // eslint-disable-next-line max-depth -- ingore + if (seen.has(amountKey)) { + throw new ValidationError('Remit: Duplicate amounts are not allowed') + } + seen.add(amountKey) + } + } +} + +function checkURITokenIDs(tx: Record): void { + if (!Array.isArray(tx.URITokenIDs)) { + throw new ValidationError('Remit: invalid field URITokenIDs') + } + if (tx.URITokenIDs.length < 1) { + throw new ValidationError('Remit: empty field URITokenIDs') + } + if (tx.URITokenIDs.length > MAX_ARRAY_LENGTH) { + throw new ValidationError('Remit: max field URITokenIDs') + } + const seen = new Set() + for (const token of tx.URITokenIDs) { + if (typeof token !== 'string' || !isHex(token)) { + throw new ValidationError('Remit: URITokenID must be a hex string') + } + if (token.length !== DIGEST_LENGTH) { + throw new ValidationError( + `Remit: URITokenID must be exactly ${DIGEST_LENGTH} characters`, + ) + } + if (seen.has(token)) { + throw new ValidationError('Remit: Duplicate URITokens are not allowed') + } + seen.add(token) + } +} + +// eslint-disable-next-line complexity -- ignore +function checkMintURIToken(tx: Record): void { + function isRecord(value: unknown): value is Record { + return value !== null && typeof value === 'object' + } + if (!isRecord(tx.MintURIToken)) { + throw new ValidationError('Remit: invalid MintURIToken') + } + if (tx.MintURIToken.URI === undefined) { + throw new ValidationError('Remit: missing field MintURIToken.URI') + } + if (typeof tx.MintURIToken.URI !== 'string' || !isHex(tx.MintURIToken.URI)) { + throw new ValidationError('Remit: MintURIToken.URI must be a hex string') + } + if (tx.MintURIToken.URI.length > MAX_URI_LENGTH) { + throw new ValidationError( + `Remit: URI must be less than ${MAX_URI_LENGTH} characters`, + ) + } + if ( + tx.MintURIToken.Digest !== undefined && + typeof tx.MintURIToken.Digest !== 'string' + ) { + throw new ValidationError(`Remit: MintURIToken.Digest must be a string`) + } + if ( + tx.MintURIToken.Digest !== undefined && + !isHex(tx.MintURIToken.Digest) && + tx.MintURIToken.Digest.length !== DIGEST_LENGTH + ) { + throw new ValidationError( + `Remit: Digest must be exactly ${DIGEST_LENGTH} characters`, + ) + } +} diff --git a/packages/xrpl/src/models/transactions/transaction.ts b/packages/xrpl/src/models/transactions/transaction.ts index df53e19e..ea6cc157 100644 --- a/packages/xrpl/src/models/transactions/transaction.ts +++ b/packages/xrpl/src/models/transactions/transaction.ts @@ -46,6 +46,7 @@ import { PaymentChannelFund, validatePaymentChannelFund, } from './paymentChannelFund' +import { Remit, validateRemit } from './remit' import { SetHook, validateSetHook } from './setHook' import { SetRegularKey, validateSetRegularKey } from './setRegularKey' import { SignerListSet, validateSignerListSet } from './signerListSet' @@ -90,6 +91,7 @@ export type Transaction = | PaymentChannelClaim | PaymentChannelCreate | PaymentChannelFund + | Remit | SetHook | SetRegularKey | SignerListSet @@ -220,14 +222,18 @@ export function validate(transaction: Record): void { validatePaymentChannelFund(tx) break - case 'SetRegularKey': - validateSetRegularKey(tx) + case 'Remit': + validateRemit(tx) break case 'SetHook': validateSetHook(tx) break + case 'SetRegularKey': + validateSetRegularKey(tx) + break + case 'SignerListSet': validateSignerListSet(tx) break diff --git a/packages/xrpl/test/models/remit.test.ts b/packages/xrpl/test/models/remit.test.ts new file mode 100644 index 00000000..10f350ef --- /dev/null +++ b/packages/xrpl/test/models/remit.test.ts @@ -0,0 +1,369 @@ +import { assert } from 'chai' + +import { validate, ValidationError } from '../../src' +import { validateRemit } from '../../src/models/transactions/remit' + +/** + * Remit Verification Testing. + * + * Providing runtime verification testing for each specific transaction type. + */ + +// eslint-disable-next-line max-statements -- ignore +describe('Remit', function () { + let remit + + beforeEach(function () { + remit = { + TransactionType: 'Remit', + Account: 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo', + Destination: 'rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy', + DestinationTag: 1, + Fee: '12', + Flags: 0, + LastLedgerSequence: 65953073, + Sequence: 65923914, + SigningPubKey: + '02F9E33F16DF9507705EC954E3F94EB5F10D1FC4A354606DBE6297DBB1096FE654', + TxnSignature: + '3045022100E3FAE0EDEC3D6A8FF6D81BC9CF8288A61B7EEDE8071E90FF9314CB4621058D10022043545CF631706D700CEE65A1DB83EFDD185413808292D9D90F14D87D3DC2D8CB', + Amounts: [ + { AmountEntry: { Amount: '1000' } }, + { + AmountEntry: { + Amount: { + currency: 'USD', + issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX', + value: '1', + }, + }, + }, + ], + MintURIToken: { + URI: 'DEADBEEF', + Digest: + '6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B', + Flags: 1, + }, + URITokenIDs: [ + 'AED08CC1F50DD5F23A1948AF86153A3F3B7593E5EC77D65A02BB1B29E05AB6AE', + ], + InvoiceID: + '6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B', + Blob: 'DEADBEEF', + Inform: 'rB5Ux4Lv2nRx6eeoAAsZmtctnBQ2LiACnk', + } as any + }) + + it(`verifies valid Remit`, function () { + assert.doesNotThrow(() => validateRemit(remit)) + assert.doesNotThrow(() => validate(remit)) + }) + + it(`throws w/ Bad Amounts`, function () { + remit.Amounts = {} + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: Amounts must be an array', + ) + }) + it(`throws w/ Empty Amounts`, function () { + remit.Amounts = [] + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: empty field Amounts', + ) + }) + it(`throws w/ Max Amounts`, function () { + remit.Amounts = [ + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + ] + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: max field Amounts', + ) + }) + it(`throws w/ Duplicate native amounts`, function () { + remit.Amounts = [ + { AmountEntry: { Amount: '1000' } }, + { AmountEntry: { Amount: '1000' } }, + ] + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: Duplicate Native amounts are not allowed', + ) + }) + it(`throws w/ Duplicate amounts`, function () { + remit.Amounts = [ + { + AmountEntry: { + Amount: { + currency: 'USD', + issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX', + value: '1', + }, + }, + }, + { + AmountEntry: { + Amount: { + currency: 'USD', + issuer: 'rcXY84C4g14iFp6taFXjjQGVeHqSCh9RX', + value: '1', + }, + }, + }, + ] + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: Duplicate amounts are not allowed', + ) + }) + it(`throws w/ Bad URITokenIDs`, function () { + remit.URITokenIDs = {} + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: invalid field URITokenIDs', + ) + }) + it(`throws w/ Empty URITokenIDs`, function () { + remit.URITokenIDs = [] + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: empty field URITokenIDs', + ) + }) + it(`throws w/ Empty URITokenIDs`, function () { + remit.URITokenIDs = [ + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + 'DEADBEEF', + ] + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: max field URITokenIDs', + ) + }) + it(`throws w/ Invalid URITokenID`, function () { + remit.URITokenIDs = [1] + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: URITokenID must be a hex string', + ) + }) + it(`throws w/ Invalid URITokenID`, function () { + remit.URITokenIDs = ['ZZ11'] + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: URITokenID must be a hex string', + ) + }) + it(`throws w/ Duplicate URITokenIDs`, function () { + remit.URITokenIDs = ['DEADBEEF'] + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: URITokenID must be exactly 64 characters', + ) + }) + it(`throws w/ Duplicate URITokenIDs`, function () { + remit.URITokenIDs = [ + 'AED08CC1F50DD5F23A1948AF86153A3F3B7593E5EC77D65A02BB1B29E05AB6AE', + 'AED08CC1F50DD5F23A1948AF86153A3F3B7593E5EC77D65A02BB1B29E05AB6AE', + ] + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: Duplicate URITokens are not allowed', + ) + }) + // it(`throws w/ Bad MintURIToken`, function () { + // remit.MintURIToken = [] + // assert.throws( + // () => validateRemit(remit), + // ValidationError, + // 'Remit: invalid MintURIToken', + // ) + // }) + it(`throws w/ Missing MintURIToken.URI`, function () { + remit.MintURIToken = {} + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: missing field MintURIToken.URI', + ) + }) + it(`throws w/ Bad MintURIToken.URI`, function () { + remit.MintURIToken = { + URI: 1, + } + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: MintURIToken.URI must be a hex string', + ) + }) + it(`throws w/ Bad MintURIToken.URI`, function () { + remit.MintURIToken = { + URI: 'ZZ11', + } + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: MintURIToken.URI must be a hex string', + ) + }) + it(`throws w/ Bad MintURIToken Less than 1`, function () { + remit.MintURIToken = { + URI: '', + } + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: MintURIToken.URI must be a hex string', + ) + }) + it(`throws w/ Bad MintURIToken.Digest`, function () { + remit.MintURIToken = { + URI: 'DEADBEEF', + Digest: 1, + } + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: MintURIToken.Digest must be a string', + ) + }) + it(`throws w/ Bad MintURIToken.Digest`, function () { + remit.MintURIToken = { + URI: 'DEADBEEF', + Digest: 'ZZ11', + } + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: Digest must be exactly 64 characters', + ) + }) + it(`throws w/ Bad Destination`, function () { + remit.Destination = 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo' + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: Destination must not be equal to the account', + ) + }) + it(`throws w/ Bad Destination Tag`, function () { + remit.DestinationTag = '1' + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: DestinationTag must be a number', + ) + }) + it(`throws w/ Bad Inform`, function () { + remit.Inform = 'rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo' + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: Inform must not be equal to the account or destination', + ) + }) + it(`throws w/ Bad Blob Type`, function () { + remit.Blob = 1 + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: Blob must be a string', + ) + }) + it(`throws w/ Bad Blob Not Hex`, function () { + remit.Blob = 'ZZ11' + assert.throws( + () => validateRemit(remit), + ValidationError, + 'Remit: Blob must be a hex string', + ) + }) + // it(`throws w/ Bad Blob Max Size`, function () { + // remit.Blob = '' + // assert.throws( + // () => validateRemit(remit), + // ValidationError, + // 'Remit: Blob must be a hex string', + // ) + // }) +})