ripple / ripple-binary-codec

Convert between json and hex representations of transactions and ledger entries on the XRP Ledger. Moved to: https://github.com/XRPLF/xrpl.js/tree/develop/packages/ripple-binary-codec
https://github.com/XRPLF/xrpl.js/tree/develop/packages/ripple-binary-codec
ISC License
19 stars 45 forks source link

Encoding / decoding with defined paths will add undefined values #117

Closed tadejgolobic closed 3 years ago

tadejgolobic commented 3 years ago

Hi, we found a problem in this lib. This is breaking change: https://github.com/ripple/ripple-binary-codec/pull/96/files

As you are aware, JSON does not recognize undefined as value, so this toJSON() function, should not return undefined values.

Furthermore, this introduces an issue in ripple-lib repository. Check following example:

const rippleLib = require('ripple-lib')

const xrp = new rippleLib.RippleAPI({
    server: 'wss://s.altnet.rippletest.net:51233'
})

const wallet = {
    address: 'rNm8U52GibQ6st5QKwCUhvjg3xVsHTH9gk',
    secret: 'ss7ueBLGRSbojgPGHpH3mXNTETP8m'
};

const paymentPathFind = {
    source: {
        address: wallet.address,
    },
    destination: {
        address: 'rKT4JX4cCof6LcDYRz8o3rGRu7qxzZ2Zwj',
        amount: {
            value: '1',
            currency: 'USD',
        },
    },
}

const payment = {
    source: {
        address: wallet.address,
        maxAmount: {
            currency: 'XRP',
            value: '10'
        },
    },
    destination: {
        address: 'rKT4JX4cCof6LcDYRz8o3rGRu7qxzZ2Zwj',
        amount: {
            value: '1',
            currency: 'USD',
        },
    },
}

const start = async function() {
    try {
        await xrp.connect();
        const paths = await xrp.getPaths(paymentPathFind);
        console.log('PATHS: ', paths);
        payment.paths = paths[0].paths;
        const preparedPayment = await xrp.preparePayment(wallet.address, payment);
        console.log('PAYMENT: ', preparedPayment);
        const signed = xrp.sign(preparedPayment.txJSON, wallet.secret);
        console.log('SIGN: ', signed);
    }catch(err) {
        console.log('ERROR: ', err);
    }
}

start();

You will get error with following backtrace:

ERROR:  ValidationError: Serialized transaction does not match original txJSON. See `error.data`
    at checkTxSerialization (/home/tadejgolobic/github.com/test/node_modules/ripple-lib/dist/npm/transaction/sign.js:129:23)
    at signWithKeypair (/home/tadejgolobic/github.com/test/node_modules/ripple-lib/dist/npm/transaction/sign.js:62:5)
    at RippleAPI.sign (/home/tadejgolobic/github.com/test/node_modules/ripple-lib/dist/npm/transaction/sign.js:149:16)
    at start (/home/tadejgolobic/github.com/test/index.js:50:28)

This is because ripple-lib encodes and decodes transaction here: Encode: https://github.com/ripple/ripple-lib/blob/4aa76b38f95e31108dcad153346dfe9a3e0e0cfc/src/transaction/sign.ts#L59 Decode: https://github.com/ripple/ripple-lib/blob/4aa76b38f95e31108dcad153346dfe9a3e0e0cfc/src/transaction/sign.ts#L144

So after this decode, transaction does not match original transaction, because those undefined values were added by codec. However, original transaction cannot pass undefined values, since ripple-lib sign method works only with json strings, and as already mentioned in the beginning, json does not recognize undefined values.