Skip to content

Commit

Permalink
feat: expose ledger-icp converters
Browse files Browse the repository at this point in the history
Signed-off-by: David Dal Busco <[email protected]>
  • Loading branch information
peterpeterparker committed Sep 9, 2024
1 parent 90d1109 commit 0b75797
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { Principal } from "@dfinity/principal";
import { toNullable } from "@dfinity/utils";
import { mockAccountIdentifier } from "../../mocks/ledger.mock";
import { mockConsentMessageRequest } from "../../mocks/ledger.request.mock";
import type {
Icrc1TransferRequest,
Icrc2ApproveRequest,
TransferRequest,
} from "../../types/ledger_converters";
import {
toIcrc1TransferRawRequest,
toIcrc21ConsentMessageRawRequest,
toIcrc2ApproveRawRequest,
toTransferRawRequest,
} from "./ledger.request.converts";

describe("ledger.request.converts", () => {
const now = BigInt(Date.now()) * BigInt(1e6);

const mockTransferRequest: TransferRequest = {
to: mockAccountIdentifier,
amount: 123n,
memo: 456n,
fee: 10_000n,
fromSubAccount: [0, 1, 2],
createdAt: now,
};

const to = {
owner: Principal.fromHex("abcd"),
subaccount: [] as [],
};

const mockIcrc1TransferRequest: Icrc1TransferRequest = {
to,
fromSubAccount: [0, 1, 2],
amount: 1_000_000n,
fee: 11_000n,
icrc1Memo: new Uint8Array([1, 2, 3]),
createdAt: now,
};

const mockIcrc2ApproveRequest: Icrc2ApproveRequest = {
spender: to,
fromSubAccount: [0, 1, 2],
expected_allowance: 5_000n,
expires_at: now + 200n,
amount: 1_200_000n,
fee: 12_000n,
icrc1Memo: new Uint8Array([1, 2, 3]),
createdAt: now,
};

it("toTransferRawRequest should return a valid raw request", () => {
const result = toTransferRawRequest(mockTransferRequest);

expect(result.to).toEqual(mockTransferRequest.to.toUint8Array());
expect(result.fee).toEqual({ e8s: mockTransferRequest.fee });
expect(result.amount).toEqual({ e8s: mockTransferRequest.amount });
expect(result.memo).toEqual(mockTransferRequest.memo);
expect(result.created_at_time).toEqual([
{ timestamp_nanos: mockTransferRequest.createdAt },
]);
expect(result.from_subaccount).toEqual([
new Uint8Array(mockTransferRequest.fromSubAccount ?? []),
]);
});

it("toIcrc1TransferRawRequest should return a valid ICRC-1 raw request", () => {
const result = toIcrc1TransferRawRequest(mockIcrc1TransferRequest);

expect(result.to).toEqual(mockIcrc1TransferRequest.to);
expect(result.fee).toEqual(toNullable(mockIcrc1TransferRequest.fee));
expect(result.amount).toEqual(mockIcrc1TransferRequest.amount);
expect(result.memo).toEqual(toNullable(mockIcrc1TransferRequest.icrc1Memo));
expect(result.created_at_time).toEqual(
toNullable(mockIcrc1TransferRequest.createdAt),
);
expect(result.from_subaccount).toEqual(
toNullable(mockIcrc1TransferRequest.fromSubAccount),
);
});

it("toIcrc2ApproveRawRequest should return a valid ICRC-2 raw request", () => {
const result = toIcrc2ApproveRawRequest(mockIcrc2ApproveRequest);

expect(result.spender).toEqual(mockIcrc2ApproveRequest.spender);
expect(result.fee).toEqual(toNullable(mockIcrc2ApproveRequest.fee));
expect(result.memo).toEqual(toNullable(mockIcrc2ApproveRequest.icrc1Memo));
expect(result.created_at_time).toEqual(
toNullable(mockIcrc2ApproveRequest.createdAt),
);
expect(result.amount).toEqual(mockIcrc2ApproveRequest.amount);
expect(result.expected_allowance).toEqual(
toNullable(mockIcrc2ApproveRequest.expected_allowance),
);
expect(result.expires_at).toEqual(
toNullable(mockIcrc2ApproveRequest.expires_at),
);
expect(result.from_subaccount).toEqual(
toNullable(mockIcrc2ApproveRequest.fromSubAccount),
);
});

it("toIcrc21ConsentMessageRawRequest should return a valid ICRC-21 generic consent message request", () => {
const result = toIcrc21ConsentMessageRawRequest(mockConsentMessageRequest);

expect(result.method).toEqual(mockConsentMessageRequest.method);
expect(result.arg).toEqual(mockConsentMessageRequest.arg);
expect(result.user_preferences.metadata.language).toEqual(
mockConsentMessageRequest.userPreferences.metadata.language,
);
expect(result.user_preferences.metadata.utc_offset_minutes).toEqual(
toNullable(
mockConsentMessageRequest.userPreferences.metadata.utcOffsetMinutes,
),
);
});

it("toIcrc21ConsentMessageRawRequest should return a valid ICRC-21 line display consent message request", () => {
const lineDisplay = {
charactersPerLine: 2,
linesPerPage: 10,
};

const consentMessageRequest = {
...mockConsentMessageRequest,
userPreferences: {
...mockConsentMessageRequest.userPreferences,
deriveSpec: {
LineDisplay: lineDisplay,
},
},
};

const result = toIcrc21ConsentMessageRawRequest(consentMessageRequest);

expect(result.user_preferences.device_spec).toEqual(
toNullable({
LineDisplay: {
characters_per_line: lineDisplay.charactersPerLine,
lines_per_page: lineDisplay.linesPerPage,
},
}),
);
});
});
1 change: 1 addition & 0 deletions packages/ledger-icp/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type {
Value,
} from "../candid/ledger";
export { AccountIdentifier, SubAccount } from "./account_identifier";
export * from "./canisters/ledger/ledger.request.converts";
export * from "./errors/ledger.errors";
export { IndexCanister } from "./index.canister";
export { LedgerCanister } from "./ledger.canister";
Expand Down
36 changes: 13 additions & 23 deletions packages/ledger-icp/src/ledger.canister.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
} from "./errors/ledger.errors";
import { LedgerCanister } from "./ledger.canister";
import { mockAccountIdentifier, mockPrincipal } from "./mocks/ledger.mock";
import { mockConsentMessageRequest } from "./mocks/ledger.request.mock";
import type {
Icrc21ConsentMessageRequest,
Icrc2ApproveRequest,
Expand Down Expand Up @@ -1059,19 +1060,6 @@ describe("LedgerCanister", () => {
});

describe("icrc21ConsentMessage", () => {
const consentMessageRequest: Icrc21ConsentMessageRequest = {
method: "icrc1_transfer",
arg: new Uint8Array([1, 2, 3]),
userPreferences: {
metadata: {
language: "en-US",
},
deriveSpec: {
GenericDisplay: null,
},
},
};

const consentMessageResponse: icrc21_consent_message_response = {
Ok: {
consent_message: {
Expand Down Expand Up @@ -1111,12 +1099,14 @@ describe("LedgerCanister", () => {
certifiedServiceOverride: service,
});

const response = await ledger.icrc21ConsentMessage(consentMessageRequest);
const response = await ledger.icrc21ConsentMessage(
mockConsentMessageRequest,
);

expect(response).toEqual(consentMessageResponse.Ok);
expect(service.icrc21_canister_call_consent_message).toBeCalledWith({
method: consentMessageRequest.method,
arg: consentMessageRequest.arg,
method: mockConsentMessageRequest.method,
arg: mockConsentMessageRequest.arg,
user_preferences: {
metadata: {
language: "en-US",
Expand All @@ -1142,7 +1132,7 @@ describe("LedgerCanister", () => {
});

const requestWithLineDisplay: Icrc21ConsentMessageRequest = {
...consentMessageRequest,
...mockConsentMessageRequest,
userPreferences: {
metadata: {
language: "en-US",
Expand Down Expand Up @@ -1192,7 +1182,7 @@ describe("LedgerCanister", () => {
});

const requestWithUtcOffset: Icrc21ConsentMessageRequest = {
...consentMessageRequest,
...mockConsentMessageRequest,
userPreferences: {
metadata: {
language: "en-US",
Expand Down Expand Up @@ -1246,7 +1236,7 @@ describe("LedgerCanister", () => {
});

await expect(
ledger.icrc21ConsentMessage(consentMessageRequest),
ledger.icrc21ConsentMessage(mockConsentMessageRequest),
).rejects.toThrowError(new GenericError(errorDescription, BigInt(500)));
});

Expand All @@ -1272,7 +1262,7 @@ describe("LedgerCanister", () => {
});

await expect(
ledger.icrc21ConsentMessage(consentMessageRequest),
ledger.icrc21ConsentMessage(mockConsentMessageRequest),
).rejects.toThrowError(
new InsufficientPaymentError(insufficientPaymentDescription),
);
Expand Down Expand Up @@ -1301,7 +1291,7 @@ describe("LedgerCanister", () => {
});

await expect(
ledger.icrc21ConsentMessage(consentMessageRequest),
ledger.icrc21ConsentMessage(mockConsentMessageRequest),
).rejects.toThrowError(
new UnsupportedCanisterCallError(unsupportedCanisterCallDescription),
);
Expand Down Expand Up @@ -1330,7 +1320,7 @@ describe("LedgerCanister", () => {
});

await expect(
ledger.icrc21ConsentMessage(consentMessageRequest),
ledger.icrc21ConsentMessage(mockConsentMessageRequest),
).rejects.toThrowError(
new ConsentMessageUnavailableError(
consentMessageUnavailableDescription,
Expand Down Expand Up @@ -1361,7 +1351,7 @@ describe("LedgerCanister", () => {
});

await expect(
ledger.icrc21ConsentMessage(consentMessageRequest),
ledger.icrc21ConsentMessage(mockConsentMessageRequest),
).rejects.toThrowError(
new ConsentMessageError(`Unknown error type ${JSON.stringify(Err)}`),
);
Expand Down
14 changes: 14 additions & 0 deletions packages/ledger-icp/src/mocks/ledger.request.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Icrc21ConsentMessageRequest } from "../types/ledger_converters";

export const mockConsentMessageRequest: Icrc21ConsentMessageRequest = {
method: "icrc1_transfer",
arg: new Uint8Array([1, 2, 3]),
userPreferences: {
metadata: {
language: "en-US",
},
deriveSpec: {
GenericDisplay: null,
},
},
};

0 comments on commit 0b75797

Please sign in to comment.