Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(coin:xrp): add memo and destination tag in crafting #9076

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/calm-deers-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@ledgerhq/coin-xrp": major
"@ledgerhq/coin-framework": major
---

Evolve transaction type to allow arbitrary crafting properties
9 changes: 2 additions & 7 deletions libs/coin-framework/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,9 @@ export type Transaction = {
recipient: string;
amount: bigint;
fee: bigint;
supplement?: unknown;
};
} & Record<string, unknown>; // Field containing dedicated value for each blockchain
jprudent marked this conversation as resolved.
Show resolved Hide resolved

// TODO rename start to minHeight
// and add a `token: string` field to the pagination if we really need to support pagination
// (which is not the case for now)
// for now start is used as a minHeight from which we want to fetch ALL operations
// limit is unused for now
// TODO add a `token: string` field to the pagination if we really need to support pagination (which is not the case for now)
// see design document at https://ledgerhq.atlassian.net/wiki/spaces/BE/pages/5446205788/coin-modules+lama-adapter+APIs+refinements
export type Pagination = { minHeight: number };
export type Api = {
Expand Down
2 changes: 2 additions & 0 deletions libs/coin-modules/coin-xrp/src/api/index.integ.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ describe("Xrp Api", () => {
recipient: "rKRtUG15iBsCQRgrkeUEg5oX4Ae2zWZ89z",
amount: BigInt(10),
fee: BigInt(1),
memos: [{ data: "01", format: "02", type: "03" }],
destinationTag: 123,
});

// Then
Expand Down
2 changes: 1 addition & 1 deletion libs/coin-modules/coin-xrp/src/bridge/signOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const buildSignOperation =
recipient: transaction.recipient,
amount: BigInt(transaction.amount.toString()),
fee: BigInt(fee.toString()),
tag: transaction.tag,
destinationTag: transaction.tag,
},
publicKey,
);
Expand Down
12 changes: 10 additions & 2 deletions libs/coin-modules/coin-xrp/src/logic/craftTransaction.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { craftTransaction } from "./craftTransaction";

import { decode } from "ripple-binary-codec";
jest.mock("../network", () => ({
getLedgerIndex: () => 1,
}));
Expand Down Expand Up @@ -46,6 +46,8 @@ describe("craftTransaction", () => {
recipient: "rJe1St1G6BWMFmdrrcT7NdD3XT1NxTMEWN",
amount: BigInt(100_000_000),
fee: BigInt(100),
memos: [{ data: "01", format: "02", type: "03" }],
destinationTag: 123,
};
const pubKey = "public_key";

Expand All @@ -59,12 +61,18 @@ describe("craftTransaction", () => {
Account: "rPDf6SQStnNmw1knCu1ei7h6BcDAEUUqn5",
Amount: "100000000",
Destination: "rJe1St1G6BWMFmdrrcT7NdD3XT1NxTMEWN",
DestinationTag: undefined,
DestinationTag: 123,
Fee: "100",
Flags: 2147483648,
Sequence: 2,
LastLedgerSequence: 21,
Memos: [{ Memo: { MemoData: "01", MemoFormat: "02", MemoType: "03" } }],
});
expect(result.serializedTransaction).toBeDefined();
const binDecodedTx = decode(result.serializedTransaction);
expect(binDecodedTx.Memos).toEqual([
{ Memo: { MemoData: "01", MemoFormat: "02", MemoType: "03" } },
]);
expect(binDecodedTx.DestinationTag).toEqual(123);
});
});
44 changes: 38 additions & 6 deletions libs/coin-modules/coin-xrp/src/logic/craftTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,34 @@ import { UINT32_MAX, validateTag } from "./utils";
const LEDGER_OFFSET = 20;

const { TRANSACTION_TYPES } = XrplDefinitions;
type Memo = {
MemoData?: string;
MemoFormat?: string;
MemoType?: string;
};
type MemoWrapper = {
Memo: Memo;
};
type XrplTransaction = {
TransactionType: keyof typeof TRANSACTION_TYPES;
Flags: number;
Account: string;
Amount: string;
Destination: string;
DestinationTag: number | undefined;
DestinationTag?: number;
Fee: string;
Sequence: number;
LastLedgerSequence: number;
SigningPubKey?: string;
TxnSignature?: string;
Memos?: MemoWrapper[];
};

type MemoInput = {
data?: string;
format?: string;
type?: string;
};
export async function craftTransaction(
account: {
address: string;
Expand All @@ -31,31 +45,49 @@ export async function craftTransaction(
recipient: string;
amount: bigint;
fee: bigint;
tag?: number | null | undefined;
destinationTag?: number | null | undefined;
memos?: MemoInput[];
},
publicKey?: string,
): Promise<{
xrplTransaction: XrplTransaction;
serializedTransaction: string;
}> {
const tag = transaction.tag ? transaction.tag : undefined;
const xrplTransaction: XrplTransaction = {
TransactionType: "Payment",
Account: account.address,
Amount: transaction.amount.toString(),
Destination: transaction.recipient,
DestinationTag: tag,
Fee: transaction.fee.toString(),
Flags: 2147483648,
Sequence: account.nextSequenceNumber,
LastLedgerSequence: (await getLedgerIndex()) + LEDGER_OFFSET,
};

if (tag) {
function memoMapper(memoInput: MemoInput): MemoWrapper {
const memo: Memo = {};
if (memoInput.data) {
memo.MemoData = memoInput.data;
}
if (memoInput.format) {
memo.MemoFormat = memoInput.format;
}
if (memoInput.type) {
memo.MemoType = memoInput.type;
}
return { Memo: memo };
}

if (transaction.memos) {
xrplTransaction.Memos = transaction.memos.map(memoMapper);
}

if (transaction.destinationTag) {
invariant(
validateTag(new BigNumber(tag)),
validateTag(new BigNumber(transaction.destinationTag)),
`tag is set but is not in a valid format, should be between [0 - ${UINT32_MAX.toString()}]`,
);
xrplTransaction.DestinationTag = transaction.destinationTag;
hedi-edelbloute marked this conversation as resolved.
Show resolved Hide resolved
}

const serializedTransaction = publicKey
Expand Down
Loading