@ledgerhq/coin-canton 0.3.0 → 0.4.0-nightly.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.integ.test.example +2 -2
- package/.eslintrc.js +1 -0
- package/.unimportedrc.json +5 -10
- package/CHANGELOG.md +17 -0
- package/README.md +11 -0
- package/jest.config.js +1 -0
- package/lib/api/getBalance.integ.test.d.ts +2 -0
- package/lib/api/getBalance.integ.test.d.ts.map +1 -0
- package/lib/api/getBalance.integ.test.js +24 -0
- package/lib/api/getBalance.integ.test.js.map +1 -0
- package/lib/api/lastBlock.integ.test.d.ts +2 -0
- package/lib/api/lastBlock.integ.test.d.ts.map +1 -0
- package/lib/api/lastBlock.integ.test.js +35 -0
- package/lib/api/lastBlock.integ.test.js.map +1 -0
- package/lib/bridge/createTransaction.test.js +1 -1
- package/lib/bridge/createTransaction.test.js.map +1 -1
- package/lib/bridge/getTransactionStatus.js +1 -1
- package/lib/bridge/getTransactionStatus.js.map +1 -1
- package/lib/bridge/sync.d.ts.map +1 -1
- package/lib/bridge/sync.js +3 -3
- package/lib/bridge/sync.js.map +1 -1
- package/lib/common-logic/account/getBalance.d.ts +1 -1
- package/lib/common-logic/account/getBalance.d.ts.map +1 -1
- package/lib/common-logic/account/getBalance.js +21 -5
- package/lib/common-logic/account/getBalance.js.map +1 -1
- package/lib/common-logic/account/getBalance.unit.test.d.ts +2 -0
- package/lib/common-logic/account/getBalance.unit.test.d.ts.map +1 -0
- package/lib/common-logic/account/getBalance.unit.test.js +88 -0
- package/lib/common-logic/account/getBalance.unit.test.js.map +1 -0
- package/lib/common-logic/history/lastBlock.d.ts.map +1 -1
- package/lib/common-logic/history/lastBlock.js +7 -4
- package/lib/common-logic/history/lastBlock.js.map +1 -1
- package/lib/common-logic/history/lastBlock.test.d.ts +2 -0
- package/lib/common-logic/history/lastBlock.test.d.ts.map +1 -0
- package/lib/common-logic/history/lastBlock.test.js +43 -0
- package/lib/common-logic/history/lastBlock.test.js.map +1 -0
- package/lib/config.d.ts +11 -5
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js.map +1 -1
- package/lib/network/gateway.d.ts +77 -0
- package/lib/network/gateway.d.ts.map +1 -0
- package/lib/network/gateway.integ.test.d.ts +2 -0
- package/lib/network/gateway.integ.test.d.ts.map +1 -0
- package/lib/network/gateway.integ.test.js +61 -0
- package/lib/network/gateway.integ.test.js.map +1 -0
- package/lib/network/gateway.js +77 -0
- package/lib/network/gateway.js.map +1 -0
- package/lib/network/node.d.ts +2 -6
- package/lib/network/node.d.ts.map +1 -1
- package/lib/network/node.integ.test.d.ts +2 -0
- package/lib/network/node.integ.test.d.ts.map +1 -0
- package/lib/network/node.integ.test.js +42 -0
- package/lib/network/node.integ.test.js.map +1 -0
- package/lib/network/node.js +47 -24
- package/lib/network/node.js.map +1 -1
- package/lib/network/node.unit.test.d.ts +2 -0
- package/lib/network/node.unit.test.d.ts.map +1 -0
- package/lib/network/node.unit.test.js +31 -0
- package/lib/network/node.unit.test.js.map +1 -0
- package/lib/types/bridge.d.ts.map +1 -1
- package/lib-es/api/getBalance.integ.test.d.ts +2 -0
- package/lib-es/api/getBalance.integ.test.d.ts.map +1 -0
- package/lib-es/api/getBalance.integ.test.js +22 -0
- package/lib-es/api/getBalance.integ.test.js.map +1 -0
- package/lib-es/api/lastBlock.integ.test.d.ts +2 -0
- package/lib-es/api/lastBlock.integ.test.d.ts.map +1 -0
- package/lib-es/api/lastBlock.integ.test.js +33 -0
- package/lib-es/api/lastBlock.integ.test.js.map +1 -0
- package/lib-es/bridge/createTransaction.test.js +1 -1
- package/lib-es/bridge/createTransaction.test.js.map +1 -1
- package/lib-es/bridge/getTransactionStatus.js +1 -1
- package/lib-es/bridge/getTransactionStatus.js.map +1 -1
- package/lib-es/bridge/sync.d.ts.map +1 -1
- package/lib-es/bridge/sync.js +4 -4
- package/lib-es/bridge/sync.js.map +1 -1
- package/lib-es/common-logic/account/getBalance.d.ts +1 -1
- package/lib-es/common-logic/account/getBalance.d.ts.map +1 -1
- package/lib-es/common-logic/account/getBalance.js +18 -5
- package/lib-es/common-logic/account/getBalance.js.map +1 -1
- package/lib-es/common-logic/account/getBalance.unit.test.d.ts +2 -0
- package/lib-es/common-logic/account/getBalance.unit.test.d.ts.map +1 -0
- package/lib-es/common-logic/account/getBalance.unit.test.js +53 -0
- package/lib-es/common-logic/account/getBalance.unit.test.js.map +1 -0
- package/lib-es/common-logic/history/lastBlock.d.ts.map +1 -1
- package/lib-es/common-logic/history/lastBlock.js +5 -5
- package/lib-es/common-logic/history/lastBlock.js.map +1 -1
- package/lib-es/common-logic/history/lastBlock.test.d.ts +2 -0
- package/lib-es/common-logic/history/lastBlock.test.d.ts.map +1 -0
- package/lib-es/common-logic/history/lastBlock.test.js +38 -0
- package/lib-es/common-logic/history/lastBlock.test.js.map +1 -0
- package/lib-es/config.d.ts +11 -5
- package/lib-es/config.d.ts.map +1 -1
- package/lib-es/config.js.map +1 -1
- package/lib-es/network/gateway.d.ts +77 -0
- package/lib-es/network/gateway.d.ts.map +1 -0
- package/lib-es/network/gateway.integ.test.d.ts +2 -0
- package/lib-es/network/gateway.integ.test.d.ts.map +1 -0
- package/lib-es/network/gateway.integ.test.js +56 -0
- package/lib-es/network/gateway.integ.test.js.map +1 -0
- package/lib-es/network/gateway.js +65 -0
- package/lib-es/network/gateway.js.map +1 -0
- package/lib-es/network/node.d.ts +2 -6
- package/lib-es/network/node.d.ts.map +1 -1
- package/lib-es/network/node.integ.test.d.ts +2 -0
- package/lib-es/network/node.integ.test.d.ts.map +1 -0
- package/lib-es/network/node.integ.test.js +37 -0
- package/lib-es/network/node.integ.test.js.map +1 -0
- package/lib-es/network/node.js +40 -17
- package/lib-es/network/node.js.map +1 -1
- package/lib-es/network/node.unit.test.d.ts +2 -0
- package/lib-es/network/node.unit.test.d.ts.map +1 -0
- package/lib-es/network/node.unit.test.js +26 -0
- package/lib-es/network/node.unit.test.js.map +1 -0
- package/lib-es/types/bridge.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/api/getBalance.integ.test.ts +28 -0
- package/src/api/lastBlock.integ.test.ts +39 -0
- package/src/bridge/createTransaction.test.ts +1 -1
- package/src/bridge/getTransactionStatus.ts +1 -1
- package/src/bridge/sync.ts +6 -4
- package/src/common-logic/account/getBalance.ts +20 -5
- package/src/common-logic/account/getBalance.unit.test.ts +63 -0
- package/src/common-logic/history/lastBlock.test.ts +47 -0
- package/src/common-logic/history/lastBlock.ts +6 -5
- package/src/config.ts +14 -4
- package/src/network/gateway.integ.test.ts +76 -0
- package/src/network/gateway.ts +168 -0
- package/src/network/node.integ.test.ts +40 -0
- package/src/network/node.ts +45 -23
- package/src/network/node.unit.test.ts +29 -0
- package/src/types/bridge.ts +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// myModule.test.ts
|
|
2
|
+
import { getLedgerEnd, generateJWT } from "./node";
|
|
3
|
+
import coinConfig from "../config";
|
|
4
|
+
jest.mock("@ledgerhq/live-network", () => jest.fn().mockResolvedValue({ data: { offset: 12345 } }));
|
|
5
|
+
describe("generateJWT", () => {
|
|
6
|
+
it("should generate a valid JWT format", () => {
|
|
7
|
+
const jwt = generateJWT();
|
|
8
|
+
expect(jwt.split(".")).toHaveLength(3);
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
describe("getLedgerEnd", () => {
|
|
12
|
+
beforeAll(() => {
|
|
13
|
+
coinConfig.setCoinConfig(() => ({
|
|
14
|
+
nodeUrl: "http://node-url",
|
|
15
|
+
networkType: "mainnet",
|
|
16
|
+
status: {
|
|
17
|
+
type: "active",
|
|
18
|
+
},
|
|
19
|
+
}));
|
|
20
|
+
});
|
|
21
|
+
it("should return the ledger offset from API response", async () => {
|
|
22
|
+
const result = await getLedgerEnd();
|
|
23
|
+
expect(result).toBe(12345);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=node.unit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.unit.test.js","sourceRoot":"","sources":["../../src/network/node.unit.test.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,UAAU,MAAM,WAAW,CAAC;AAEnC,IAAI,CAAC,IAAI,CAAC,wBAAwB,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;AAEpG,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC;YAC9B,OAAO,EAAE,iBAAiB;YAC1B,WAAW,EAAE,SAAS;YACtB,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;aACf;SACF,CAAC,CAAC,CAAC;IACN,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,MAAM,GAAG,MAAM,YAAY,EAAE,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/types/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/types/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EACV,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,0BAA0B,EAC3B,MAAM,sBAAsB,CAAC;AAE9B,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,QAAQ,CAAC;IACjB,SAAS,EAAE,SAAS,CAAC;IACrB,WAAW,EAAE,SAAS,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,QAAQ,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,iBAAiB,GAAG;IAC5C,MAAM,EAAE,QAAQ,CAAC;IACjB,GAAG,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,oBAAoB,GAAG;IAClD,MAAM,EAAE,QAAQ,CAAC;IACjB,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,uBAAuB,CAAC;AACxD,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ledgerhq/coin-canton",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-nightly.0",
|
|
4
4
|
"description": "Canton coin integration",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ledger",
|
|
@@ -101,12 +101,12 @@
|
|
|
101
101
|
"bignumber.js": "^9.1.2",
|
|
102
102
|
"invariant": "^2.2.4",
|
|
103
103
|
"rxjs": "^7.8.1",
|
|
104
|
-
"@ledgerhq/coin-framework": "^6.2.0",
|
|
105
|
-
"@ledgerhq/cryptoassets": "^13.
|
|
106
|
-
"@ledgerhq/devices": "8.5.0",
|
|
107
|
-
"@ledgerhq/errors": "^6.
|
|
108
|
-
"@ledgerhq/live-env": "^2.
|
|
109
|
-
"@ledgerhq/live-network": "^2.0.
|
|
104
|
+
"@ledgerhq/coin-framework": "^6.2.1-nightly.0",
|
|
105
|
+
"@ledgerhq/cryptoassets": "^13.27.0-nightly.0",
|
|
106
|
+
"@ledgerhq/devices": "8.5.1-nightly.0",
|
|
107
|
+
"@ledgerhq/errors": "^6.25.0-nightly.0",
|
|
108
|
+
"@ledgerhq/live-env": "^2.15.0-nightly.1",
|
|
109
|
+
"@ledgerhq/live-network": "^2.0.16-nightly.1",
|
|
110
110
|
"@ledgerhq/types-live": "^6.82.0"
|
|
111
111
|
},
|
|
112
112
|
"devDependencies": {
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"jest": "^29.7.0",
|
|
118
118
|
"ts-jest": "^29.1.1",
|
|
119
119
|
"typescript": "^5.4.5",
|
|
120
|
-
"@ledgerhq/types-cryptoassets": "^7.
|
|
120
|
+
"@ledgerhq/types-cryptoassets": "^7.26.0-nightly.1",
|
|
121
121
|
"@ledgerhq/disable-network-setup": "^0.0.0"
|
|
122
122
|
},
|
|
123
123
|
"scripts": {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AlpacaApi } from "@ledgerhq/coin-framework/lib/api/types";
|
|
2
|
+
import { createApi } from ".";
|
|
3
|
+
|
|
4
|
+
let api: AlpacaApi;
|
|
5
|
+
|
|
6
|
+
describe("devnet", () => {
|
|
7
|
+
beforeAll(() => {
|
|
8
|
+
api = createApi({
|
|
9
|
+
nodeUrl: "https://wallet-validator-devnet-canton.ledger-test.com/v2",
|
|
10
|
+
networkType: "devnet",
|
|
11
|
+
gatewayUrl: "https://canton-gateway.api.live.ledger-test.com",
|
|
12
|
+
useGateway: true,
|
|
13
|
+
nativeInstrumentId:
|
|
14
|
+
"6e9fc50fb94e56751b49f09ba2dc84da53a9d7cff08115ebb4f6b7a12d0c990c:Splice.Amulet:Amulet",
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("getBalance", () => {
|
|
19
|
+
it("should return user balance", async () => {
|
|
20
|
+
const balance = await api.getBalance(
|
|
21
|
+
"party-4f2e1485107adf5f::122027c6dbbbdbffe0fa3122ae05175f3b9328e879e9ce96b670354deb64a45683c1",
|
|
22
|
+
);
|
|
23
|
+
expect(balance.length).toBeGreaterThanOrEqual(1);
|
|
24
|
+
const nativeBalance = balance.find(b => b.asset.type === "native");
|
|
25
|
+
expect(nativeBalance?.value).toBeGreaterThanOrEqual(0);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { AlpacaApi } from "@ledgerhq/coin-framework/lib/api/types";
|
|
2
|
+
import { createApi } from ".";
|
|
3
|
+
import { CantonCoinConfig } from "../config";
|
|
4
|
+
|
|
5
|
+
let api: AlpacaApi;
|
|
6
|
+
|
|
7
|
+
describe.skip("localnet", () => {
|
|
8
|
+
beforeAll(() => {
|
|
9
|
+
api = createApi({
|
|
10
|
+
nodeUrl: "http://localhost:2975/v2",
|
|
11
|
+
networkType: "localnet",
|
|
12
|
+
} satisfies Partial<CantonCoinConfig>);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe("lastBlock", () => {
|
|
16
|
+
it("should return ledger end", async () => {
|
|
17
|
+
const lastBlock = await api.lastBlock();
|
|
18
|
+
expect(lastBlock.height).toBeGreaterThan(0);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe("devnet", () => {
|
|
24
|
+
beforeAll(() => {
|
|
25
|
+
api = createApi({
|
|
26
|
+
nodeUrl: "https://wallet-validator-devnet-canton.ledger-test.com/v2",
|
|
27
|
+
networkType: "devnet",
|
|
28
|
+
gatewayUrl: "https://canton-gateway.api.live.ledger-test.com",
|
|
29
|
+
useGateway: true,
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("lastBlock", () => {
|
|
34
|
+
it("should return ledger end", async () => {
|
|
35
|
+
const lastBlock = await api.lastBlock();
|
|
36
|
+
expect(lastBlock.height).toBeGreaterThan(0);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -7,6 +7,6 @@ describe("createTransaction", () => {
|
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
it("should create a transaction with boilerplate family", () => {
|
|
10
|
-
expect(createTransaction({} as AccountLike<Account>).family).toEqual("
|
|
10
|
+
expect(createTransaction({} as AccountLike<Account>).family).toEqual("canton");
|
|
11
11
|
});
|
|
12
12
|
});
|
|
@@ -25,7 +25,7 @@ export const getTransactionStatus: AccountBridge<
|
|
|
25
25
|
const warnings: Record<string, Error> = {};
|
|
26
26
|
|
|
27
27
|
// reserveAmount is the minimum amount of currency that an account must hold in order to stay activated
|
|
28
|
-
const reserveAmount = new BigNumber(coinConfig.getCoinConfig().minReserve);
|
|
28
|
+
const reserveAmount = new BigNumber(coinConfig.getCoinConfig().minReserve || 0);
|
|
29
29
|
const estimatedFees = new BigNumber(transaction.fee || 0);
|
|
30
30
|
const totalSpent = new BigNumber(transaction.amount).plus(estimatedFees);
|
|
31
31
|
const amount = new BigNumber(transaction.amount);
|
package/src/bridge/sync.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { Operation } from "@ledgerhq/types-live";
|
|
|
3
3
|
import { encodeAccountId } from "@ledgerhq/coin-framework/account/index";
|
|
4
4
|
import { GetAccountShape, mergeOps } from "@ledgerhq/coin-framework/bridge/jsHelpers";
|
|
5
5
|
import { getTransactions } from "../network/indexer";
|
|
6
|
-
import { getAccountInfo,
|
|
6
|
+
import { getAccountInfo, getLedgerEnd } from "../network/node";
|
|
7
7
|
|
|
8
8
|
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
|
|
9
9
|
import { BoilerplateOperation } from "../network/types";
|
|
@@ -73,13 +73,15 @@ export const getAccountShape: GetAccountShape = async info => {
|
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
// blockheight retrieval
|
|
76
|
-
const blockHeight = await
|
|
76
|
+
const blockHeight = await getLedgerEnd();
|
|
77
77
|
|
|
78
78
|
// Account info retrieval + spendable balance calculation
|
|
79
79
|
const accountInfo = await getAccountInfo(address);
|
|
80
80
|
const balance = new BigNumber(accountInfo.account_data.Balance);
|
|
81
|
-
const reserveMin = coinConfig.getCoinConfig().minReserve;
|
|
82
|
-
const spendableBalance = new BigNumber(accountInfo.account_data.Balance).minus(
|
|
81
|
+
const reserveMin = coinConfig.getCoinConfig().minReserve || 0;
|
|
82
|
+
const spendableBalance = new BigNumber(accountInfo.account_data.Balance).minus(
|
|
83
|
+
BigNumber(reserveMin),
|
|
84
|
+
);
|
|
83
85
|
|
|
84
86
|
// Tx history fetching
|
|
85
87
|
const oldOperations = initialAccount?.operations || [];
|
|
@@ -1,8 +1,23 @@
|
|
|
1
1
|
import { Balance } from "@ledgerhq/coin-framework/api/types";
|
|
2
|
-
import {
|
|
2
|
+
import { getBalance as gatewayGetBalance, type InstrumentBalance } from "../../network/gateway";
|
|
3
|
+
import coinConfig from "../../config";
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const useGateway = () => coinConfig.getCoinConfig().useGateway === true;
|
|
6
|
+
const getNativeId = () => coinConfig.getCoinConfig().nativeInstrumentId;
|
|
7
|
+
|
|
8
|
+
function adaptInstrument(instrument: InstrumentBalance): Balance {
|
|
9
|
+
return {
|
|
10
|
+
value: BigInt(instrument.amount),
|
|
11
|
+
locked: instrument.locked === true ? BigInt(instrument.amount) : BigInt(0),
|
|
12
|
+
asset:
|
|
13
|
+
getNativeId() === instrument.instrumentId
|
|
14
|
+
? { type: "native" }
|
|
15
|
+
: { type: "token", assetReference: instrument.instrumentId },
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function getBalance(partyId: string): Promise<Balance[]> {
|
|
20
|
+
if (useGateway())
|
|
21
|
+
return (await gatewayGetBalance(partyId)).map(instrument => adaptInstrument(instrument));
|
|
22
|
+
else throw new Error("Not implemented");
|
|
8
23
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { getBalance as getBalanceFromNetwork } from "../../network/gateway";
|
|
2
|
+
import * as coinConfigModule from "../../config";
|
|
3
|
+
import { getBalance } from "./getBalance";
|
|
4
|
+
import { Balance } from "@ledgerhq/coin-framework/api/types";
|
|
5
|
+
|
|
6
|
+
jest.mock("../../network/gateway", () => ({
|
|
7
|
+
getBalance: jest.fn(),
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
describe("getBalance", () => {
|
|
11
|
+
const mockGetCoinConfig = jest.spyOn(coinConfigModule.default, "getCoinConfig");
|
|
12
|
+
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
jest.clearAllMocks();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("should return adapted balances when useGateway is true", async () => {
|
|
18
|
+
mockGetCoinConfig.mockReturnValue({
|
|
19
|
+
useGateway: true,
|
|
20
|
+
nativeInstrumentId: "native-id",
|
|
21
|
+
} as any);
|
|
22
|
+
|
|
23
|
+
const mockInstruments = [
|
|
24
|
+
{
|
|
25
|
+
instrumentId: "native-id",
|
|
26
|
+
amount: "1000",
|
|
27
|
+
locked: false,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
instrumentId: "token-123",
|
|
31
|
+
amount: "5000",
|
|
32
|
+
locked: true,
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
(getBalanceFromNetwork as jest.Mock).mockResolvedValue(mockInstruments);
|
|
37
|
+
|
|
38
|
+
const result = await getBalance("party-id");
|
|
39
|
+
|
|
40
|
+
expect(getBalanceFromNetwork).toHaveBeenCalledWith("party-id");
|
|
41
|
+
expect(result).toEqual<Balance[]>([
|
|
42
|
+
{
|
|
43
|
+
value: BigInt(1000),
|
|
44
|
+
locked: BigInt(0),
|
|
45
|
+
asset: { type: "native" },
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
value: BigInt(5000),
|
|
49
|
+
locked: BigInt(5000),
|
|
50
|
+
asset: { type: "token", assetReference: "token-123" },
|
|
51
|
+
},
|
|
52
|
+
]);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should throw an error when useGateway is false (not implemented with node)", async () => {
|
|
56
|
+
mockGetCoinConfig.mockReturnValue({
|
|
57
|
+
useGateway: false,
|
|
58
|
+
} as any);
|
|
59
|
+
|
|
60
|
+
await expect(getBalance("party-id")).rejects.toThrow("Not implemented");
|
|
61
|
+
expect(getBalanceFromNetwork).not.toHaveBeenCalled();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { lastBlock } from "./lastBlock";
|
|
2
|
+
import { getLedgerEnd as gatewayGetLedgerEnd } from "../../network/gateway";
|
|
3
|
+
import { getLedgerEnd as nodeGetLedgerEnd } from "../../network/node";
|
|
4
|
+
|
|
5
|
+
jest.mock("../../network/gateway", () => ({
|
|
6
|
+
getLedgerEnd: jest.fn(),
|
|
7
|
+
}));
|
|
8
|
+
jest.mock("../../network/node", () => ({
|
|
9
|
+
getLedgerEnd: jest.fn(),
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
jest.mock("../../config", () => ({
|
|
13
|
+
__esModule: true,
|
|
14
|
+
default: {
|
|
15
|
+
getCoinConfig: jest.fn(),
|
|
16
|
+
},
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
import coinConfig from "../../config";
|
|
20
|
+
|
|
21
|
+
describe("lastBlock", () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
jest.clearAllMocks();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should use gateway.getLedgerEnd when useGateway is true", async () => {
|
|
27
|
+
(coinConfig.getCoinConfig as jest.Mock).mockReturnValue({ useGateway: true });
|
|
28
|
+
(gatewayGetLedgerEnd as jest.Mock).mockResolvedValue(100);
|
|
29
|
+
|
|
30
|
+
const result = await lastBlock();
|
|
31
|
+
|
|
32
|
+
expect(result).toEqual({ height: 100 });
|
|
33
|
+
expect(gatewayGetLedgerEnd).toHaveBeenCalledTimes(1);
|
|
34
|
+
expect(nodeGetLedgerEnd).not.toHaveBeenCalled();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should use node.getLedgerEnd when useGateway is false", async () => {
|
|
38
|
+
(coinConfig.getCoinConfig as jest.Mock).mockReturnValue({ useGateway: false });
|
|
39
|
+
(nodeGetLedgerEnd as jest.Mock).mockResolvedValue(200);
|
|
40
|
+
|
|
41
|
+
const result = await lastBlock();
|
|
42
|
+
|
|
43
|
+
expect(result).toEqual({ height: 200 });
|
|
44
|
+
expect(nodeGetLedgerEnd).toHaveBeenCalledTimes(1);
|
|
45
|
+
expect(gatewayGetLedgerEnd).not.toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { BlockInfo } from "@ledgerhq/coin-framework/api/index";
|
|
2
|
-
import {
|
|
2
|
+
import { getLedgerEnd as nodeGetLedgerEnd } from "../../network/node";
|
|
3
|
+
import { getLedgerEnd } from "../../network/gateway";
|
|
4
|
+
import coinConfig from "../../config";
|
|
5
|
+
|
|
6
|
+
const useGateway = () => coinConfig.getCoinConfig().useGateway === true;
|
|
3
7
|
|
|
4
8
|
export async function lastBlock(): Promise<BlockInfo> {
|
|
5
|
-
const result = await getLastBlock();
|
|
6
9
|
return {
|
|
7
|
-
height:
|
|
8
|
-
hash: result.blockHash,
|
|
9
|
-
time: new Date(result.timestamp),
|
|
10
|
+
height: useGateway() ? await getLedgerEnd() : await nodeGetLedgerEnd(),
|
|
10
11
|
};
|
|
11
12
|
}
|
package/src/config.ts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
import buildCoinConfig, { type CurrencyConfig } from "@ledgerhq/coin-framework/config";
|
|
1
|
+
import buildCoinConfig, { CoinConfig, type CurrencyConfig } from "@ledgerhq/coin-framework/config";
|
|
2
|
+
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
|
|
2
3
|
|
|
3
4
|
export type CantonConfig = {
|
|
4
|
-
nodeUrl
|
|
5
|
-
|
|
5
|
+
nodeUrl?: string;
|
|
6
|
+
nodeId?: string;
|
|
7
|
+
gatewayUrl?: string;
|
|
8
|
+
// TODELETE
|
|
9
|
+
minReserve?: number;
|
|
10
|
+
networkType: "mainnet" | "devnet" | "localnet";
|
|
11
|
+
useGateway?: boolean;
|
|
12
|
+
nativeInstrumentId?: string;
|
|
6
13
|
};
|
|
7
14
|
|
|
8
15
|
export type CantonCoinConfig = CurrencyConfig & CantonConfig;
|
|
9
16
|
|
|
10
|
-
const coinConfig
|
|
17
|
+
const coinConfig: {
|
|
18
|
+
setCoinConfig: (config: CoinConfig<CantonCoinConfig>) => void;
|
|
19
|
+
getCoinConfig: (currency?: CryptoCurrency) => CantonCoinConfig;
|
|
20
|
+
} = buildCoinConfig<CantonCoinConfig>();
|
|
11
21
|
|
|
12
22
|
export default coinConfig;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import coinConfig from "../config";
|
|
2
|
+
import {
|
|
3
|
+
getLedgerEnd,
|
|
4
|
+
prepareOnboarding,
|
|
5
|
+
getBalance,
|
|
6
|
+
getTransactions,
|
|
7
|
+
getPartyById,
|
|
8
|
+
getPartyByPubKey,
|
|
9
|
+
} from "./gateway";
|
|
10
|
+
|
|
11
|
+
describe("gateway (devnet)", () => {
|
|
12
|
+
beforeAll(() => {
|
|
13
|
+
coinConfig.setCoinConfig(() => ({
|
|
14
|
+
gatewayUrl: "https://canton-gateway.api.live.ledger-test.com",
|
|
15
|
+
useGateway: true,
|
|
16
|
+
networkType: "devnet",
|
|
17
|
+
status: {
|
|
18
|
+
type: "active",
|
|
19
|
+
},
|
|
20
|
+
}));
|
|
21
|
+
});
|
|
22
|
+
describe("prepareOnboarding", () => {
|
|
23
|
+
it("should prepare onboarding", async () => {
|
|
24
|
+
const response = await prepareOnboarding(
|
|
25
|
+
"c59f7f29374d24506dd6490a5db472cf00958e195e146f3dc9c97f96d5c51097",
|
|
26
|
+
"ed25519",
|
|
27
|
+
);
|
|
28
|
+
expect(response).toHaveProperty("party_id");
|
|
29
|
+
expect(response).toHaveProperty("party_name");
|
|
30
|
+
expect(response).toHaveProperty("public_key_fingerprint");
|
|
31
|
+
expect(response).toHaveProperty("topology_transactions_hash");
|
|
32
|
+
}, 30000);
|
|
33
|
+
});
|
|
34
|
+
describe("getLedgerEnd", () => {
|
|
35
|
+
it("should return ledger end", async () => {
|
|
36
|
+
const end = await getLedgerEnd();
|
|
37
|
+
expect(end).toBeGreaterThanOrEqual(0);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("getBalance", () => {
|
|
42
|
+
it("should return user balance", async () => {
|
|
43
|
+
const balance = await getBalance(
|
|
44
|
+
"party-4f2e1485107adf5f::122027c6dbbbdbffe0fa3122ae05175f3b9328e879e9ce96b670354deb64a45683c1",
|
|
45
|
+
);
|
|
46
|
+
expect(balance.length).toBeGreaterThanOrEqual(1);
|
|
47
|
+
expect(balance[0].amount).toBeGreaterThanOrEqual(0);
|
|
48
|
+
expect(balance[0].instrumentId.includes("Splice")).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("getPartyById", () => {
|
|
53
|
+
it.skip("should return party info", async () => {
|
|
54
|
+
const party = await getPartyById("4f2e1485107adf5f");
|
|
55
|
+
expect(party).toBeDefined();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("getPartyByPubKey", () => {
|
|
60
|
+
it.skip("should return party info", async () => {
|
|
61
|
+
const party = await getPartyByPubKey(
|
|
62
|
+
"122027c6dbbbdbffe0fa3122ae05175f3b9328e879e9ce96b670354deb64a45683c1",
|
|
63
|
+
);
|
|
64
|
+
expect(party).toBeDefined();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe("getTransactions", () => {
|
|
69
|
+
it("should return user transactions", async () => {
|
|
70
|
+
const { transactions } = await getTransactions(
|
|
71
|
+
"party-5f29bb32e9939939::12202becd8062a1d170209956cfd977fca76fcb4d2a892d08c77a7483f35a11d6440",
|
|
72
|
+
);
|
|
73
|
+
expect(transactions.length).toBeGreaterThanOrEqual(0);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import network from "@ledgerhq/live-network";
|
|
2
|
+
import coinConfig from "../config";
|
|
3
|
+
|
|
4
|
+
type OnboardingPrepareResponse = {
|
|
5
|
+
party_id: string;
|
|
6
|
+
party_name: string;
|
|
7
|
+
public_key_fingerprint: string;
|
|
8
|
+
topology_transactions_hash: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type OnboardingPrepareRequest = {
|
|
12
|
+
public_key: string;
|
|
13
|
+
public_key_type: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
type OnboardingSubmitRequest = {
|
|
17
|
+
prepare_request: OnboardingPrepareRequest;
|
|
18
|
+
prepare_response: OnboardingPrepareResponse;
|
|
19
|
+
signature: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type OnboardingSubmitResponse = {
|
|
23
|
+
party: {
|
|
24
|
+
party_id: string;
|
|
25
|
+
public_key: string;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type InstrumentBalance = {
|
|
30
|
+
instrumentId: string;
|
|
31
|
+
amount: number;
|
|
32
|
+
locked: boolean;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
type PartyInfo = {
|
|
36
|
+
party_id: string;
|
|
37
|
+
public_key: string;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
type Timestamp = {
|
|
41
|
+
seconds: number;
|
|
42
|
+
nanos: number;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
type BaseEvent = {
|
|
46
|
+
type: string;
|
|
47
|
+
contractId: string;
|
|
48
|
+
details: string;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
type CreatedEvent = BaseEvent & {
|
|
52
|
+
templateId: {
|
|
53
|
+
packageId: string;
|
|
54
|
+
moduleName: string;
|
|
55
|
+
entityName: string;
|
|
56
|
+
};
|
|
57
|
+
signatories: string[];
|
|
58
|
+
observers: string[];
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
type ExercisedEvent = BaseEvent & {
|
|
62
|
+
templateId: {
|
|
63
|
+
packageId: string;
|
|
64
|
+
moduleName: string;
|
|
65
|
+
entityName: string;
|
|
66
|
+
};
|
|
67
|
+
choice: string;
|
|
68
|
+
consuming: boolean;
|
|
69
|
+
actingParties: string[];
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
type Event = BaseEvent | CreatedEvent | ExercisedEvent;
|
|
73
|
+
|
|
74
|
+
type TxInfo = {
|
|
75
|
+
updateId: string;
|
|
76
|
+
commandId: string;
|
|
77
|
+
workflowId: string;
|
|
78
|
+
effectiveAt: Timestamp;
|
|
79
|
+
offset: number;
|
|
80
|
+
synchronizerId: string;
|
|
81
|
+
recordTime: Timestamp;
|
|
82
|
+
events: Event[];
|
|
83
|
+
traceContext: string;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const getGatewayUrl = () => coinConfig.getCoinConfig().gatewayUrl;
|
|
87
|
+
const getNodeId = () => coinConfig.getCoinConfig().nodeId || "ledger-live-devnet-prd";
|
|
88
|
+
|
|
89
|
+
export async function prepareOnboarding(
|
|
90
|
+
pubKey: string,
|
|
91
|
+
pubKeyType: string,
|
|
92
|
+
): Promise<OnboardingPrepareResponse> {
|
|
93
|
+
const { data } = await network<OnboardingPrepareResponse>({
|
|
94
|
+
method: "POST",
|
|
95
|
+
url: `${getGatewayUrl()}/v1/node/${getNodeId()}/onboarding/prepare`,
|
|
96
|
+
data: {
|
|
97
|
+
public_key: pubKey,
|
|
98
|
+
public_key_type: pubKeyType,
|
|
99
|
+
} satisfies OnboardingPrepareRequest,
|
|
100
|
+
});
|
|
101
|
+
return data;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function submitOnboarding(
|
|
105
|
+
prepareRequest: OnboardingPrepareRequest,
|
|
106
|
+
prepareResponse: OnboardingPrepareResponse,
|
|
107
|
+
signature: string,
|
|
108
|
+
) {
|
|
109
|
+
const { data } = await network<OnboardingSubmitResponse>({
|
|
110
|
+
method: "POST",
|
|
111
|
+
url: `${getGatewayUrl()}/v1/node/${getNodeId()}/onboarding/submit`,
|
|
112
|
+
data: {
|
|
113
|
+
prepare_request: prepareRequest,
|
|
114
|
+
prepare_response: prepareResponse,
|
|
115
|
+
signature,
|
|
116
|
+
} satisfies OnboardingSubmitRequest,
|
|
117
|
+
});
|
|
118
|
+
return data;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export async function getBalance(partyId: string): Promise<InstrumentBalance[]> {
|
|
122
|
+
const { data } = await network<InstrumentBalance[]>({
|
|
123
|
+
method: "GET",
|
|
124
|
+
url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${partyId}/balance`,
|
|
125
|
+
});
|
|
126
|
+
return data;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function getPartyById(partyId: string): Promise<PartyInfo> {
|
|
130
|
+
return await getParty(partyId, "ID");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export async function getPartyByPubKey(pubKey: string): Promise<PartyInfo> {
|
|
134
|
+
return await getParty(pubKey, "PK");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function getParty(identifier: string, by: "ID" | "PK"): Promise<PartyInfo> {
|
|
138
|
+
const { data } = await network<PartyInfo>({
|
|
139
|
+
method: "GET",
|
|
140
|
+
url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${identifier}`,
|
|
141
|
+
data: {
|
|
142
|
+
by,
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
return data;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export async function getTransactions(partyId: string): Promise<{
|
|
149
|
+
next: number;
|
|
150
|
+
transactions: TxInfo[];
|
|
151
|
+
}> {
|
|
152
|
+
const { data } = await network<{
|
|
153
|
+
next: number;
|
|
154
|
+
transactions: TxInfo[];
|
|
155
|
+
}>({
|
|
156
|
+
method: "GET",
|
|
157
|
+
url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${partyId}/transactions`,
|
|
158
|
+
});
|
|
159
|
+
return data;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export async function getLedgerEnd(): Promise<number> {
|
|
163
|
+
const { data } = await network<number>({
|
|
164
|
+
method: "GET",
|
|
165
|
+
url: `${getGatewayUrl()}/v1/node/${getNodeId()}/ledger-end`,
|
|
166
|
+
});
|
|
167
|
+
return data;
|
|
168
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import coinConfig from "../config";
|
|
2
|
+
import { getLedgerEnd } from "./node";
|
|
3
|
+
|
|
4
|
+
// enable manually, as it requires a running node locally
|
|
5
|
+
describe.skip("Node (localnet)", () => {
|
|
6
|
+
beforeAll(() => {
|
|
7
|
+
coinConfig.setCoinConfig(() => ({
|
|
8
|
+
gatewayUrl: "http://gateway.url",
|
|
9
|
+
nodeUrl: "http://localhost:2975/v2",
|
|
10
|
+
networkType: "localnet",
|
|
11
|
+
status: { type: "active" },
|
|
12
|
+
}));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe("getLedgerEnd", () => {
|
|
16
|
+
it("should return ledger end", async () => {
|
|
17
|
+
const end = await getLedgerEnd();
|
|
18
|
+
expect(end).toBeGreaterThan(0);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// enable manually, as it requires an auth token in env variable
|
|
24
|
+
describe.skip("Node (devnet)", () => {
|
|
25
|
+
beforeAll(() => {
|
|
26
|
+
coinConfig.setCoinConfig(() => ({
|
|
27
|
+
nodeUrl: "https://wallet-validator-devnet-canton.ledger-test.com/v2",
|
|
28
|
+
networkType: "devnet",
|
|
29
|
+
status: { type: "active" },
|
|
30
|
+
gatewayUrl: "http://gateway.url",
|
|
31
|
+
}));
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("getLedgerEnd", () => {
|
|
35
|
+
it("should return ledger end", async () => {
|
|
36
|
+
const end = await getLedgerEnd();
|
|
37
|
+
expect(end).toBeGreaterThan(0);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|