Allow XAddress Issuers (#1471)

* feat: Allow clients to use XAddresses for issuers
This commit is contained in:
Nathan Nichols
2021-07-30 11:16:01 -07:00
committed by GitHub
parent 6e0fff2ad6
commit d9a42c8669
10 changed files with 101 additions and 13 deletions

View File

@@ -1,8 +1,9 @@
import * as _ from 'lodash'
import BigNumber from 'bignumber.js'
import {deriveKeypair} from 'ripple-keypairs'
import {Amount, RippledAmount} from './types/objects'
import {RippledAmount} from './types/objects'
import {ValidationError} from './errors'
import {xAddressToClassicAddress} from 'ripple-address-codec'
function isValidSecret(secret: string): boolean {
try {
@@ -105,20 +106,31 @@ function xrpToDrops(xrp: BigNumber.Value): string {
.toString(10)
}
function toRippledAmount(amount: Amount): RippledAmount {
function toRippledAmount(amount: RippledAmount): RippledAmount {
if (typeof amount === 'string')
return amount;
if (amount.currency === 'XRP') {
return xrpToDrops(amount.value)
}
if (amount.currency === 'drops') {
return amount.value
}
let issuer = amount.counterparty || amount.issuer
let tag: number | false = false;
try {
({classicAddress: issuer, tag} = xAddressToClassicAddress(issuer))
} catch (e) { /* not an X-address */ }
if (tag !== false) {
throw new ValidationError("Issuer X-address includes a tag")
}
return {
currency: amount.currency,
issuer: amount.counterparty
? amount.counterparty
: amount.issuer
? amount.issuer
: undefined,
issuer,
value: amount.value
}
}

View File

@@ -1,6 +1,6 @@
import * as utils from './utils'
const offerFlags = utils.common.txFlags.OfferCreate
import {validate, iso8601ToRippleTime} from '../common'
import {validate, iso8601ToRippleTime, toRippledAmount} from '../common'
import {Instructions, Prepare, OfferCreateTransaction} from './types'
import {FormattedOrderSpecification} from '../common/types/objects/index'
import {RippleAPI} from '..'
@@ -9,10 +9,10 @@ function createOrderTransaction(
account: string,
order: FormattedOrderSpecification
): OfferCreateTransaction {
const takerPays = utils.common.toRippledAmount(
const takerPays = toRippledAmount(
order.direction === 'buy' ? order.quantity : order.totalPrice
)
const takerGets = utils.common.toRippledAmount(
const takerGets = toRippledAmount(
order.direction === 'buy' ? order.totalPrice : order.quantity
)

View File

@@ -1,7 +1,6 @@
import * as _ from 'lodash'
import * as utils from './utils'
const validate = utils.common.validate
const toRippledAmount = utils.common.toRippledAmount
const paymentFlags = utils.common.txFlags.Payment
const ValidationError = utils.common.errors.ValidationError
import {Instructions, Prepare, TransactionJSON} from './types'
@@ -12,7 +11,7 @@ import {
MinAdjustment,
Memo
} from '../common/types/objects'
import {xrpToDrops} from '../common'
import {toRippledAmount, xrpToDrops} from '../common'
import {RippleAPI} from '..'
import {getClassicAccountAndTag, ClassicAccountAndTag} from './utils'

View File

@@ -2,6 +2,7 @@ import BigNumber from 'bignumber.js'
import * as common from '../common'
import {Memo} from '../common/types/objects'
import {Instructions, Prepare, TransactionJSON} from './types'
import {toRippledAmount} from '../common'
import {RippleAPI} from '..'
import {ValidationError} from '../common/errors'
import {xAddressToClassicAddress, isValidXAddress} from 'ripple-address-codec'
@@ -200,6 +201,16 @@ function prepareTransaction(
}
}
function convertIssuedCurrencyToAccountIfPresent(fieldName: string): void {
const amount = txJSON[fieldName]
if (typeof amount === 'number'
|| amount instanceof Array
|| amount == null)
return
newTxJSON[fieldName] = toRippledAmount(amount)
}
// DepositPreauth:
convertToClassicAccountIfPresent('Authorize')
convertToClassicAccountIfPresent('Unauthorize')
@@ -210,6 +221,18 @@ function prepareTransaction(
// SetRegularKey:
convertToClassicAccountIfPresent('RegularKey')
// Payment
convertIssuedCurrencyToAccountIfPresent('Amount')
convertIssuedCurrencyToAccountIfPresent('SendMax')
convertIssuedCurrencyToAccountIfPresent('DeliverMin')
// OfferCreate
convertIssuedCurrencyToAccountIfPresent('TakerPays')
convertIssuedCurrencyToAccountIfPresent('TakerGets')
// TrustSet
convertIssuedCurrencyToAccountIfPresent('LimitAmount')
setCanonicalFlag(newTxJSON)
function prepareMaxLedgerVersion(): Promise<void> {

View File

@@ -1075,6 +1075,34 @@ export default <TestSuite>{
assertResultMatch(response, expectedResponse, 'prepare')
},
'xaddress-issuer': async (api, address) => {
const localInstructions = {
...instructionsWithMaxLedgerVersionOffset,
maxFee: '0.000012'
}
const txJSON = {
TransactionType: 'Payment',
Account: address,
Destination: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
Amount: {
currency: 'USD',
issuer: 'XVbehP2sFMQAd5orFAy8Lt6vLHGiDhA7VMAnsv9H6WpuB1s',
value: '0.01'
},
SendMax: {
currency: 'USD',
issuer: 'XVbehP2sFMQAd5orFAy8Lt6vLHGiDhA7VMAnsv9H6WpuB1s',
value: '0.01'
},
Flags: 0
}
const response = await api.prepareTransaction(txJSON, localInstructions)
assertResultMatch(response, responses.preparePayment.normal, 'prepare')
},
'PaymentChannelCreate': async (api, address) => {
const localInstructions = {
...instructionsWithMaxLedgerVersionOffset,

View File

@@ -50,6 +50,15 @@ export default <TestSuite>{
)
},
'xaddress-issuer': async (api, address) => {
const result = await api.prepareTrustline(
address,
requests.prepareTrustline.issuedXAddress,
instructionsWithMaxLedgerVersionOffset
)
assertResultMatch(result, responses.prepareTrustline.issuedXAddress, 'prepare')
},
'with ticket': async (api, address) => {
const localInstructions = {
...instructionsWithMaxLedgerVersionOffset,

View File

@@ -72,7 +72,8 @@ module.exports = {
prepareTrustline: {
simple: require('./prepare-trustline-simple'),
complex: require('./prepare-trustline'),
frozen: require('./prepare-trustline-frozen.json')
frozen: require('./prepare-trustline-frozen.json'),
issuedXAddress: require('./prepare-trustline-issuer-xaddress.json')
},
sign: {
normal: require('./sign'),

View File

@@ -0,0 +1,6 @@
{
"currency": "BTC",
"counterparty": "XVbehP2sFMQAd5orFAy8Lt6vLHGiDhA7VMAnsv9H6WpuB1s",
"limit": "0.1"
}

View File

@@ -204,6 +204,7 @@ module.exports = {
simple: require('./prepare-trustline-simple'),
ticket: require('./prepare-trustline-ticket'),
frozen: require('./prepare-trustline-frozen'),
issuedXAddress: require('./prepare-trustline-issuer-xaddress.json'),
complex: require('./prepare-trustline')
},
sign: {

View File

@@ -0,0 +1,9 @@
{
"txJSON": "{\"Flags\":2147483648,\"TransactionType\":\"TrustSet\",\"Account\":\"r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59\",\"LimitAmount\":{\"value\":\"0.1\",\"currency\":\"BTC\",\"issuer\":\"rMH4UxPrbuMa1spCBR98hLLyNJp4d8p4tM\"},\"LastLedgerSequence\":8820051,\"Fee\":\"12\",\"Sequence\":23}",
"instructions": {
"fee": "0.000012",
"sequence": 23,
"maxLedgerVersion": 8820051
}
}