@ledgerhq/coin-ton 0.7.0 → 0.8.0-next.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/CHANGELOG.md +15 -0
- package/jest.config.js +1 -0
- package/lib/__tests__/fixtures/common.fixtures.d.ts +3 -4
- package/lib/__tests__/fixtures/common.fixtures.d.ts.map +1 -1
- package/lib/__tests__/fixtures/common.fixtures.js +9 -1
- package/lib/__tests__/fixtures/common.fixtures.js.map +1 -1
- package/lib/__tests__/integration/bridge.integration.test.d.ts.map +1 -1
- package/lib/__tests__/integration/bridge.integration.test.js +2 -2
- package/lib/__tests__/integration/bridge.integration.test.js.map +1 -1
- package/lib/__tests__/unit/api.unit.test.js +1 -0
- package/lib/__tests__/unit/api.unit.test.js.map +1 -1
- package/lib/__tests__/unit/deviceTransactionConfig.unit.test.js +12 -3
- package/lib/__tests__/unit/deviceTransactionConfig.unit.test.js.map +1 -1
- package/lib/__tests__/unit/prepareTransaction.unit.test.js +38 -0
- package/lib/__tests__/unit/prepareTransaction.unit.test.js.map +1 -1
- package/lib/__tests__/unit/utils.unit.test.js +43 -1
- package/lib/__tests__/unit/utils.unit.test.js.map +1 -1
- package/lib/bridge/js.d.ts +3 -3
- package/lib/bridge/js.d.ts.map +1 -1
- package/lib/config.d.ts +2 -0
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js.map +1 -1
- package/lib/constants.d.ts +18 -0
- package/lib/constants.d.ts.map +1 -1
- package/lib/constants.js +20 -1
- package/lib/constants.js.map +1 -1
- package/lib/deviceTransactionConfig.d.ts.map +1 -1
- package/lib/deviceTransactionConfig.js +14 -3
- package/lib/deviceTransactionConfig.js.map +1 -1
- package/lib/estimateMaxSpendable.d.ts +3 -3
- package/lib/estimateMaxSpendable.d.ts.map +1 -1
- package/lib/estimateMaxSpendable.js +6 -5
- package/lib/estimateMaxSpendable.js.map +1 -1
- package/lib/getTransactionStatus.d.ts +3 -3
- package/lib/getTransactionStatus.d.ts.map +1 -1
- package/lib/getTransactionStatus.js +2 -2
- package/lib/getTransactionStatus.js.map +1 -1
- package/lib/prepareTransaction.d.ts +3 -3
- package/lib/prepareTransaction.d.ts.map +1 -1
- package/lib/prepareTransaction.js +1 -2
- package/lib/prepareTransaction.js.map +1 -1
- package/lib/signOperation.d.ts +4 -4
- package/lib/signOperation.d.ts.map +1 -1
- package/lib/signOperation.js.map +1 -1
- package/lib/synchronisation.d.ts +3 -3
- package/lib/synchronisation.d.ts.map +1 -1
- package/lib/synchronisation.js +4 -3
- package/lib/synchronisation.js.map +1 -1
- package/lib/types.d.ts +79 -2
- package/lib/types.d.ts.map +1 -1
- package/lib/utils.d.ts +8 -4
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +30 -5
- package/lib/utils.js.map +1 -1
- package/lib-es/__tests__/fixtures/common.fixtures.d.ts +3 -4
- package/lib-es/__tests__/fixtures/common.fixtures.d.ts.map +1 -1
- package/lib-es/__tests__/fixtures/common.fixtures.js +9 -1
- package/lib-es/__tests__/fixtures/common.fixtures.js.map +1 -1
- package/lib-es/__tests__/integration/bridge.integration.test.d.ts.map +1 -1
- package/lib-es/__tests__/integration/bridge.integration.test.js +1 -1
- package/lib-es/__tests__/integration/bridge.integration.test.js.map +1 -1
- package/lib-es/__tests__/unit/api.unit.test.js +1 -0
- package/lib-es/__tests__/unit/api.unit.test.js.map +1 -1
- package/lib-es/__tests__/unit/deviceTransactionConfig.unit.test.js +12 -3
- package/lib-es/__tests__/unit/deviceTransactionConfig.unit.test.js.map +1 -1
- package/lib-es/__tests__/unit/prepareTransaction.unit.test.js +15 -0
- package/lib-es/__tests__/unit/prepareTransaction.unit.test.js.map +1 -1
- package/lib-es/__tests__/unit/utils.unit.test.js +20 -1
- package/lib-es/__tests__/unit/utils.unit.test.js.map +1 -1
- package/lib-es/bridge/js.d.ts +3 -3
- package/lib-es/bridge/js.d.ts.map +1 -1
- package/lib-es/bridge/js.js +1 -1
- package/lib-es/bridge/js.js.map +1 -1
- package/lib-es/config.d.ts +2 -0
- package/lib-es/config.d.ts.map +1 -1
- package/lib-es/config.js.map +1 -1
- package/lib-es/constants.d.ts +18 -0
- package/lib-es/constants.d.ts.map +1 -1
- package/lib-es/constants.js +19 -0
- package/lib-es/constants.js.map +1 -1
- package/lib-es/deviceTransactionConfig.d.ts.map +1 -1
- package/lib-es/deviceTransactionConfig.js +15 -4
- package/lib-es/deviceTransactionConfig.js.map +1 -1
- package/lib-es/estimateMaxSpendable.d.ts +3 -3
- package/lib-es/estimateMaxSpendable.d.ts.map +1 -1
- package/lib-es/estimateMaxSpendable.js +7 -6
- package/lib-es/estimateMaxSpendable.js.map +1 -1
- package/lib-es/getTransactionStatus.d.ts +3 -3
- package/lib-es/getTransactionStatus.d.ts.map +1 -1
- package/lib-es/getTransactionStatus.js +2 -2
- package/lib-es/getTransactionStatus.js.map +1 -1
- package/lib-es/prepareTransaction.d.ts +3 -3
- package/lib-es/prepareTransaction.d.ts.map +1 -1
- package/lib-es/prepareTransaction.js +1 -2
- package/lib-es/prepareTransaction.js.map +1 -1
- package/lib-es/signOperation.d.ts +4 -4
- package/lib-es/signOperation.d.ts.map +1 -1
- package/lib-es/signOperation.js.map +1 -1
- package/lib-es/synchronisation.d.ts +3 -3
- package/lib-es/synchronisation.d.ts.map +1 -1
- package/lib-es/synchronisation.js +4 -3
- package/lib-es/synchronisation.js.map +1 -1
- package/lib-es/types.d.ts +79 -2
- package/lib-es/types.d.ts.map +1 -1
- package/lib-es/utils.d.ts +8 -4
- package/lib-es/utils.d.ts.map +1 -1
- package/lib-es/utils.js +29 -5
- package/lib-es/utils.js.map +1 -1
- package/package.json +8 -8
- package/src/__tests__/fixtures/common.fixtures.ts +12 -5
- package/src/__tests__/integration/bridge.integration.test.ts +3 -3
- package/src/__tests__/unit/api.unit.test.ts +1 -0
- package/src/__tests__/unit/deviceTransactionConfig.unit.test.ts +20 -3
- package/src/__tests__/unit/prepareTransaction.unit.test.ts +17 -0
- package/src/__tests__/unit/utils.unit.test.ts +22 -1
- package/src/bridge/js.ts +3 -3
- package/src/config.ts +2 -0
- package/src/constants.ts +20 -0
- package/src/deviceTransactionConfig.ts +23 -4
- package/src/estimateMaxSpendable.ts +13 -17
- package/src/getTransactionStatus.ts +9 -9
- package/src/prepareTransaction.ts +5 -6
- package/src/signOperation.ts +6 -4
- package/src/synchronisation.ts +17 -12
- package/src/types.ts +103 -1
- package/src/utils.ts +39 -8
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Address, toNano } from "@ton/core";
|
|
2
|
+
import { setCoinConfig } from "../../config";
|
|
2
3
|
import {
|
|
3
4
|
TOKEN_TRANSFER_FORWARD_AMOUNT,
|
|
4
5
|
TOKEN_TRANSFER_MAX_FEE,
|
|
@@ -13,6 +14,7 @@ import {
|
|
|
13
14
|
getTransferExpirationTime,
|
|
14
15
|
isAddressValid,
|
|
15
16
|
} from "../../utils";
|
|
17
|
+
import mockServer, { API_TON_ENDPOINT } from "../fixtures/api.fixtures";
|
|
16
18
|
import {
|
|
17
19
|
account,
|
|
18
20
|
transaction as baseTransaction,
|
|
@@ -90,6 +92,7 @@ describe("TON transfers", () => {
|
|
|
90
92
|
customPayload: null,
|
|
91
93
|
forwardAmount: BigInt(0),
|
|
92
94
|
forwardPayload: null,
|
|
95
|
+
knownJetton: null,
|
|
93
96
|
};
|
|
94
97
|
|
|
95
98
|
const nftPayload: TonPayloadFormat = {
|
|
@@ -139,6 +142,23 @@ describe("Get TON paths", () => {
|
|
|
139
142
|
});
|
|
140
143
|
|
|
141
144
|
describe("Build TON transaction", () => {
|
|
145
|
+
beforeAll(() => {
|
|
146
|
+
setCoinConfig(() => ({
|
|
147
|
+
status: {
|
|
148
|
+
type: "active",
|
|
149
|
+
},
|
|
150
|
+
infra: {
|
|
151
|
+
API_TON_ENDPOINT: API_TON_ENDPOINT,
|
|
152
|
+
KNOWN_JETTONS: [],
|
|
153
|
+
},
|
|
154
|
+
}));
|
|
155
|
+
mockServer.listen();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
afterAll(() => {
|
|
159
|
+
mockServer.close();
|
|
160
|
+
});
|
|
161
|
+
|
|
142
162
|
const seqno = 22;
|
|
143
163
|
|
|
144
164
|
test("Build TON transaction with an specific amount", () => {
|
|
@@ -184,7 +204,7 @@ describe("Build TON transaction", () => {
|
|
|
184
204
|
to: jettonTransfer.to.toString(),
|
|
185
205
|
payload: undefined,
|
|
186
206
|
}).toStrictEqual({
|
|
187
|
-
to: Address.parse(account.subAccounts?.[0].
|
|
207
|
+
to: Address.parse(account.subAccounts?.[0].jettonWallet ?? "").toString(),
|
|
188
208
|
seqno,
|
|
189
209
|
amount: toNano(TOKEN_TRANSFER_MAX_FEE),
|
|
190
210
|
bounce: true,
|
|
@@ -213,6 +233,7 @@ describe("Build TON transaction", () => {
|
|
|
213
233
|
customPayload: null,
|
|
214
234
|
forwardAmount: TOKEN_TRANSFER_FORWARD_AMOUNT.toString(),
|
|
215
235
|
forwardPayload: null,
|
|
236
|
+
knownJetton: null,
|
|
216
237
|
});
|
|
217
238
|
});
|
|
218
239
|
});
|
package/src/bridge/js.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import getAddressWrapper from "@ledgerhq/coin-framework/bridge/getAddressWrapper";
|
|
2
2
|
import {
|
|
3
3
|
getSerializedAddressParameters,
|
|
4
|
-
updateTransaction,
|
|
5
4
|
makeAccountBridgeReceive,
|
|
6
5
|
makeScanAccounts,
|
|
6
|
+
updateTransaction,
|
|
7
7
|
} from "@ledgerhq/coin-framework/bridge/jsHelpers";
|
|
8
8
|
import { SignerContext } from "@ledgerhq/coin-framework/signer";
|
|
9
9
|
|
|
@@ -18,7 +18,7 @@ import prepareTransaction from "../prepareTransaction";
|
|
|
18
18
|
import { buildSignOperation } from "../signOperation";
|
|
19
19
|
import { TonSigner } from "../signer";
|
|
20
20
|
import { getAccountShape, sync } from "../synchronisation";
|
|
21
|
-
import type { Transaction } from "../types";
|
|
21
|
+
import type { TonAccount, Transaction } from "../types";
|
|
22
22
|
|
|
23
23
|
export function buildCurrencyBridge(signerContext: SignerContext<TonSigner>): CurrencyBridge {
|
|
24
24
|
const getAddress = resolver(signerContext);
|
|
@@ -37,7 +37,7 @@ export function buildCurrencyBridge(signerContext: SignerContext<TonSigner>): Cu
|
|
|
37
37
|
|
|
38
38
|
export function buildAccountBridge(
|
|
39
39
|
signerContext: SignerContext<TonSigner>,
|
|
40
|
-
): AccountBridge<Transaction> {
|
|
40
|
+
): AccountBridge<Transaction, TonAccount> {
|
|
41
41
|
const getAddress = resolver(signerContext);
|
|
42
42
|
|
|
43
43
|
const receive = makeAccountBridgeReceive(getAddressWrapper(getAddress));
|
package/src/config.ts
CHANGED
package/src/constants.ts
CHANGED
|
@@ -26,6 +26,10 @@ export const TOKEN_TRANSFER_QUERY_ID = 0;
|
|
|
26
26
|
*/
|
|
27
27
|
export const MAX_COMMENT_BYTES = 120;
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Operation codes for Jetton (TON token standard) transactions.
|
|
31
|
+
* These codes are used to identify different types of token operations.
|
|
32
|
+
*/
|
|
29
33
|
export enum JettonOpCode {
|
|
30
34
|
Transfer = 0xf8a7ea5,
|
|
31
35
|
TransferNotification = 0x7362d09c,
|
|
@@ -34,3 +38,19 @@ export enum JettonOpCode {
|
|
|
34
38
|
Burn = 0x595f07bc,
|
|
35
39
|
BurnNotification = 0x7bdd97de,
|
|
36
40
|
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* TON blockchain workchain identifiers.
|
|
44
|
+
* MasterChain (-1) is used for validator operations and governance.
|
|
45
|
+
* BaseChain (0) is the main workchain used for regular accounts and smart contracts.
|
|
46
|
+
*/
|
|
47
|
+
export enum Workchain {
|
|
48
|
+
MasterChain = -1,
|
|
49
|
+
BaseChain = 0,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Default workchain used for TON addresses.
|
|
54
|
+
* BaseChain (0) is the standard workchain for user accounts and transactions.
|
|
55
|
+
*/
|
|
56
|
+
export const WORKCHAIN = Workchain.BaseChain;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { isTokenAccount } from "@ledgerhq/coin-framework/account/index";
|
|
1
|
+
import { getAccountCurrency, isTokenAccount } from "@ledgerhq/coin-framework/account/index";
|
|
2
|
+
import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies/index";
|
|
2
3
|
import { CommonDeviceTransactionField as DeviceTransactionField } from "@ledgerhq/coin-framework/transaction/common";
|
|
3
4
|
import type { Account, AccountLike } from "@ledgerhq/types-live";
|
|
5
|
+
import { toNano } from "@ton/core";
|
|
6
|
+
import { BigNumber } from "bignumber.js";
|
|
4
7
|
import { TOKEN_TRANSFER_MAX_FEE } from "./constants";
|
|
5
8
|
import type { Transaction, TransactionStatus } from "./types";
|
|
6
9
|
|
|
@@ -22,13 +25,29 @@ function getDeviceTransactionConfig(input: {
|
|
|
22
25
|
if (tokenTransfer) {
|
|
23
26
|
fields.push({
|
|
24
27
|
type: "text",
|
|
25
|
-
label: "Jetton
|
|
26
|
-
value:
|
|
28
|
+
label: "Jetton amount",
|
|
29
|
+
value: formatCurrencyUnit(
|
|
30
|
+
getAccountCurrency(input.account).units[0],
|
|
31
|
+
input.transaction.amount,
|
|
32
|
+
{
|
|
33
|
+
showCode: true,
|
|
34
|
+
disableRounding: true,
|
|
35
|
+
},
|
|
36
|
+
),
|
|
27
37
|
});
|
|
28
38
|
fields.push({
|
|
29
39
|
type: "text",
|
|
30
40
|
label: "Amount",
|
|
31
|
-
value:
|
|
41
|
+
value: input.parentAccount
|
|
42
|
+
? formatCurrencyUnit(
|
|
43
|
+
getAccountCurrency(input.parentAccount).units[0],
|
|
44
|
+
BigNumber(toNano(TOKEN_TRANSFER_MAX_FEE).toString()),
|
|
45
|
+
{
|
|
46
|
+
showCode: true,
|
|
47
|
+
disableRounding: true,
|
|
48
|
+
},
|
|
49
|
+
)
|
|
50
|
+
: TOKEN_TRANSFER_MAX_FEE,
|
|
32
51
|
});
|
|
33
52
|
} else {
|
|
34
53
|
if (input.transaction.useAllAmount) {
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
findSubAccountById,
|
|
3
|
-
getMainAccount,
|
|
4
|
-
isTokenAccount,
|
|
5
|
-
} from "@ledgerhq/coin-framework/account/index";
|
|
1
|
+
import { getMainAccount, isTokenAccount } from "@ledgerhq/coin-framework/account/index";
|
|
6
2
|
import type { Account, AccountBridge, AccountLike, TokenAccount } from "@ledgerhq/types-live";
|
|
7
3
|
import { BigNumber } from "bignumber.js";
|
|
8
4
|
import { fetchAccountInfo } from "./bridge/bridgeHelpers/api";
|
|
9
|
-
import type { Transaction } from "./types";
|
|
10
|
-
import { buildTonTransaction, getTonEstimatedFees } from "./utils";
|
|
5
|
+
import type { TonAccount, Transaction } from "./types";
|
|
6
|
+
import { buildTonTransaction, findSubAccountById, getTonEstimatedFees } from "./utils";
|
|
11
7
|
|
|
12
|
-
const estimateMaxSpendable: AccountBridge<
|
|
8
|
+
const estimateMaxSpendable: AccountBridge<
|
|
9
|
+
Transaction,
|
|
10
|
+
TonAccount
|
|
11
|
+
>["estimateMaxSpendable"] = async ({
|
|
13
12
|
account,
|
|
14
13
|
parentAccount,
|
|
15
14
|
transaction,
|
|
@@ -18,7 +17,7 @@ const estimateMaxSpendable: AccountBridge<Transaction, Account>["estimateMaxSpen
|
|
|
18
17
|
parentAccount?: Account | null | undefined;
|
|
19
18
|
transaction?: Transaction | null | undefined;
|
|
20
19
|
}): Promise<BigNumber> => {
|
|
21
|
-
const mainAccount = getMainAccount(account, parentAccount);
|
|
20
|
+
const mainAccount = getMainAccount(account, parentAccount) as TonAccount;
|
|
22
21
|
let balance = mainAccount.spendableBalance;
|
|
23
22
|
|
|
24
23
|
if (balance.eq(0)) return balance;
|
|
@@ -45,14 +44,11 @@ const estimateMaxSpendable: AccountBridge<Transaction, Account>["estimateMaxSpen
|
|
|
45
44
|
return subAccount.spendableBalance;
|
|
46
45
|
}
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
buildTonTransaction(transaction, accountInfo.seqno, mainAccount),
|
|
54
|
-
))
|
|
55
|
-
: BigNumber(0);
|
|
47
|
+
let estimatedFees = BigNumber(0);
|
|
48
|
+
if (transaction) {
|
|
49
|
+
const tonTx = buildTonTransaction(transaction, accountInfo.seqno, mainAccount);
|
|
50
|
+
estimatedFees = await getTonEstimatedFees(mainAccount, accountInfo.status === "uninit", tonTx);
|
|
51
|
+
}
|
|
56
52
|
|
|
57
53
|
if (balance.lte(estimatedFees)) return new BigNumber(0);
|
|
58
54
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isTokenAccount } from "@ledgerhq/coin-framework/account/index";
|
|
2
2
|
import {
|
|
3
3
|
AmountRequired,
|
|
4
4
|
InvalidAddress,
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
NotEnoughBalance,
|
|
7
7
|
RecipientRequired,
|
|
8
8
|
} from "@ledgerhq/errors";
|
|
9
|
-
import {
|
|
9
|
+
import { AccountBridge } from "@ledgerhq/types-live";
|
|
10
10
|
import { toNano } from "@ton/core";
|
|
11
11
|
import BigNumber from "bignumber.js";
|
|
12
12
|
import { MINIMUM_REQUIRED_BALANCE, TOKEN_TRANSFER_MAX_FEE } from "./constants";
|
|
@@ -16,8 +16,8 @@ import {
|
|
|
16
16
|
TonMinimumRequired,
|
|
17
17
|
TonNotEnoughBalanceInParentAccount,
|
|
18
18
|
} from "./errors";
|
|
19
|
-
import { Transaction, TransactionStatus } from "./types";
|
|
20
|
-
import { addressesAreEqual, commentIsValid, isAddressValid } from "./utils";
|
|
19
|
+
import { TonAccount, Transaction, TransactionStatus } from "./types";
|
|
20
|
+
import { addressesAreEqual, commentIsValid, findSubAccountById, isAddressValid } from "./utils";
|
|
21
21
|
|
|
22
22
|
type ValidatedTransactionFields = "recipient" | "sender" | "amount" | "transaction";
|
|
23
23
|
type ValidationIssues = Partial<Record<ValidatedTransactionFields, Error>>;
|
|
@@ -25,7 +25,7 @@ type ValidationIssues = Partial<Record<ValidatedTransactionFields, Error>>;
|
|
|
25
25
|
/**
|
|
26
26
|
* Validate an address for account transaction
|
|
27
27
|
*/
|
|
28
|
-
const validateRecipient = (account:
|
|
28
|
+
const validateRecipient = (account: TonAccount, tx: Transaction): Array<ValidationIssues> => {
|
|
29
29
|
const errors: ValidationIssues = {};
|
|
30
30
|
|
|
31
31
|
if (tx.recipient) {
|
|
@@ -52,7 +52,7 @@ const validateRecipient = (account: Account, tx: Transaction): Array<ValidationI
|
|
|
52
52
|
/**
|
|
53
53
|
* Validate the sender address for account transaction
|
|
54
54
|
*/
|
|
55
|
-
const validateSender = (account:
|
|
55
|
+
const validateSender = (account: TonAccount): Array<ValidationIssues> => {
|
|
56
56
|
const errors: ValidationIssues = {};
|
|
57
57
|
|
|
58
58
|
// Check if sender is matching the format of account valid ton address or not
|
|
@@ -68,7 +68,7 @@ const validateSender = (account: Account): Array<ValidationIssues> => {
|
|
|
68
68
|
};
|
|
69
69
|
|
|
70
70
|
const validateAmount = (
|
|
71
|
-
account:
|
|
71
|
+
account: TonAccount,
|
|
72
72
|
transaction: Transaction,
|
|
73
73
|
totalSpent: BigNumber,
|
|
74
74
|
): Array<ValidationIssues> => {
|
|
@@ -120,10 +120,10 @@ const validateComment = (transaction: Transaction): Array<ValidationIssues> => {
|
|
|
120
120
|
|
|
121
121
|
export const getTransactionStatus: AccountBridge<
|
|
122
122
|
Transaction,
|
|
123
|
-
|
|
123
|
+
TonAccount,
|
|
124
124
|
TransactionStatus
|
|
125
125
|
>["getTransactionStatus"] = async (
|
|
126
|
-
account:
|
|
126
|
+
account: TonAccount,
|
|
127
127
|
transaction: Transaction,
|
|
128
128
|
): Promise<TransactionStatus> => {
|
|
129
129
|
const subAccount = findSubAccountById(account, transaction.subAccountId ?? "");
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { findSubAccountById } from "@ledgerhq/coin-framework/account/index";
|
|
2
1
|
import { updateTransaction } from "@ledgerhq/coin-framework/bridge/jsHelpers";
|
|
3
|
-
import {
|
|
2
|
+
import { AccountBridge } from "@ledgerhq/types-live";
|
|
4
3
|
import { fetchAccountInfo } from "./bridge/bridgeHelpers/api";
|
|
5
|
-
import type { Transaction } from "./types";
|
|
6
|
-
import { buildTonTransaction, getTonEstimatedFees } from "./utils";
|
|
4
|
+
import type { TonAccount, Transaction } from "./types";
|
|
5
|
+
import { buildTonTransaction, findSubAccountById, getTonEstimatedFees } from "./utils";
|
|
7
6
|
|
|
8
|
-
const prepareTransaction: AccountBridge<Transaction,
|
|
9
|
-
account:
|
|
7
|
+
const prepareTransaction: AccountBridge<Transaction, TonAccount>["prepareTransaction"] = async (
|
|
8
|
+
account: TonAccount,
|
|
10
9
|
transaction: Transaction,
|
|
11
10
|
): Promise<Transaction> => {
|
|
12
11
|
const accountInfo = await fetchAccountInfo(account.freshAddress);
|
package/src/signOperation.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { Observable } from "rxjs";
|
|
|
8
8
|
import { fetchAccountInfo } from "./bridge/bridgeHelpers/api";
|
|
9
9
|
import { TOKEN_TRANSFER_MAX_FEE } from "./constants";
|
|
10
10
|
import type { TonSigner } from "./signer";
|
|
11
|
-
import type { TonCell, TonOperation, Transaction } from "./types";
|
|
11
|
+
import type { TonAccount, TonCell, TonOperation, Transaction } from "./types";
|
|
12
12
|
import { buildTonTransaction, getLedgerTonPath } from "./utils";
|
|
13
13
|
|
|
14
14
|
const packTransaction = (account: Account, needsInit: boolean, signature: TonCell): string => {
|
|
@@ -30,13 +30,15 @@ const packTransaction = (account: Account, needsInit: boolean, signature: TonCel
|
|
|
30
30
|
* Sign Transaction with Ledger hardware
|
|
31
31
|
*/
|
|
32
32
|
export const buildSignOperation =
|
|
33
|
-
(
|
|
33
|
+
(
|
|
34
|
+
signerContext: SignerContext<TonSigner>,
|
|
35
|
+
): AccountBridge<Transaction, TonAccount>["signOperation"] =>
|
|
34
36
|
({
|
|
35
37
|
account,
|
|
36
38
|
transaction,
|
|
37
39
|
deviceId,
|
|
38
40
|
}: {
|
|
39
|
-
account:
|
|
41
|
+
account: TonAccount;
|
|
40
42
|
transaction: Transaction;
|
|
41
43
|
deviceId: DeviceId;
|
|
42
44
|
}): Observable<SignOperationEvent> =>
|
|
@@ -87,7 +89,7 @@ export const buildSignOperation =
|
|
|
87
89
|
});
|
|
88
90
|
|
|
89
91
|
export const buildOptimisticOperation = (
|
|
90
|
-
account:
|
|
92
|
+
account: TonAccount,
|
|
91
93
|
transaction: Transaction,
|
|
92
94
|
): TonOperation => {
|
|
93
95
|
const { recipient, amount, fees, comment, useAllAmount, subAccountId } = transaction;
|
package/src/synchronisation.ts
CHANGED
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
import { decodeOperationId } from "@ledgerhq/coin-framework/operation";
|
|
15
15
|
import { log } from "@ledgerhq/logs";
|
|
16
16
|
import { TokenCurrency } from "@ledgerhq/types-cryptoassets";
|
|
17
|
-
import { Account, SubAccount } from "@ledgerhq/types-live";
|
|
18
17
|
import BigNumber from "bignumber.js";
|
|
19
18
|
import flatMap from "lodash/flatMap";
|
|
20
19
|
import {
|
|
@@ -30,9 +29,12 @@ import {
|
|
|
30
29
|
mapTxToOps,
|
|
31
30
|
} from "./bridge/bridgeHelpers/txn";
|
|
32
31
|
import { getSyncHash } from "./logic";
|
|
33
|
-
import { TonOperation } from "./types";
|
|
32
|
+
import { TonAccount, TonOperation, TonSubAccount } from "./types";
|
|
34
33
|
|
|
35
|
-
export const getAccountShape: GetAccountShape<
|
|
34
|
+
export const getAccountShape: GetAccountShape<TonAccount> = async (
|
|
35
|
+
info,
|
|
36
|
+
{ blacklistedTokenIds },
|
|
37
|
+
) => {
|
|
36
38
|
const { address, rest, currency, derivationMode, initialAccount } = info;
|
|
37
39
|
|
|
38
40
|
const publicKey = reconciliatePubkey(rest?.publicKey, initialAccount);
|
|
@@ -85,6 +87,7 @@ export const getAccountShape: GetAccountShape<Account> = async (info, { blacklis
|
|
|
85
87
|
mapJettonTxToOps(accountId, address, newTxs.address_book),
|
|
86
88
|
);
|
|
87
89
|
const operations = shouldSyncFromScratch ? newOps : mergeOps(oldOps, newOps);
|
|
90
|
+
|
|
88
91
|
const subAccounts = await getSubAccounts(
|
|
89
92
|
info,
|
|
90
93
|
accountId,
|
|
@@ -103,7 +106,7 @@ export const getAccountShape: GetAccountShape<Account> = async (info, { blacklis
|
|
|
103
106
|
blockHeight,
|
|
104
107
|
xpub: publicKey,
|
|
105
108
|
lastSyncDate: new Date(),
|
|
106
|
-
} as Partial<
|
|
109
|
+
} as Partial<TonAccount>;
|
|
107
110
|
return toReturn;
|
|
108
111
|
};
|
|
109
112
|
|
|
@@ -113,14 +116,15 @@ const getSubAccountShape = async (
|
|
|
113
116
|
token: TokenCurrency,
|
|
114
117
|
ops: TonOperation[],
|
|
115
118
|
shouldSyncFromScratch: boolean,
|
|
116
|
-
): Promise<Partial<
|
|
117
|
-
const tokenAccountId = encodeTokenAccountId(parentId, token);
|
|
119
|
+
): Promise<Partial<TonSubAccount>> => {
|
|
118
120
|
const walletsInfo = await fetchJettonWallets({
|
|
119
121
|
address: info.address,
|
|
120
122
|
jettonMaster: token.contractAddress,
|
|
121
123
|
});
|
|
124
|
+
|
|
122
125
|
if (walletsInfo.length !== 1) throw new Error("[ton] unexpected api response");
|
|
123
|
-
const { balance, address:
|
|
126
|
+
const { balance, address: jettonWallet } = walletsInfo[0];
|
|
127
|
+
const tokenAccountId = encodeTokenAccountId(parentId, token);
|
|
124
128
|
const oldOps = info.initialAccount?.subAccounts?.find(a => a.id === tokenAccountId)?.operations;
|
|
125
129
|
const operations = !oldOps || shouldSyncFromScratch ? ops : mergeOps(oldOps, ops);
|
|
126
130
|
const maybeExistingSubAccount =
|
|
@@ -132,7 +136,7 @@ const getSubAccountShape = async (
|
|
|
132
136
|
type: "TokenAccount",
|
|
133
137
|
id: tokenAccountId,
|
|
134
138
|
parentId,
|
|
135
|
-
token
|
|
139
|
+
token,
|
|
136
140
|
balance: new BigNumber(balance),
|
|
137
141
|
spendableBalance: new BigNumber(balance),
|
|
138
142
|
operations,
|
|
@@ -141,6 +145,7 @@ const getSubAccountShape = async (
|
|
|
141
145
|
creationDate: operations.length > 0 ? operations[operations.length - 1].date : new Date(),
|
|
142
146
|
balanceHistoryCache: emptyHistoryCache, // calculated in the jsHelpers
|
|
143
147
|
swapHistory: [],
|
|
148
|
+
jettonWallet, // Address of the jetton wallet contract that holds the token balance and handles transfers
|
|
144
149
|
};
|
|
145
150
|
};
|
|
146
151
|
|
|
@@ -150,7 +155,7 @@ async function getSubAccounts(
|
|
|
150
155
|
newOps: TonOperation[],
|
|
151
156
|
blacklistedTokenIds: string[] = [],
|
|
152
157
|
shouldSyncFromScratch: boolean,
|
|
153
|
-
): Promise<Partial<
|
|
158
|
+
): Promise<Partial<TonSubAccount>[]> {
|
|
154
159
|
const opsPerToken = newOps.reduce((acc, op) => {
|
|
155
160
|
const { accountId: tokenAccountId } = decodeOperationId(op.id);
|
|
156
161
|
const { token } = decodeTokenAccountId(tokenAccountId);
|
|
@@ -159,7 +164,7 @@ async function getSubAccounts(
|
|
|
159
164
|
acc.get(token)?.push(op);
|
|
160
165
|
return acc;
|
|
161
166
|
}, new Map<TokenCurrency, TonOperation[]>());
|
|
162
|
-
const subAccountsPromises: Promise<Partial<
|
|
167
|
+
const subAccountsPromises: Promise<Partial<TonSubAccount>>[] = [];
|
|
163
168
|
for (const [token, ops] of opsPerToken.entries()) {
|
|
164
169
|
subAccountsPromises.push(
|
|
165
170
|
getSubAccountShape(info, accountId, token, ops, shouldSyncFromScratch),
|
|
@@ -168,7 +173,7 @@ async function getSubAccounts(
|
|
|
168
173
|
return Promise.all(subAccountsPromises);
|
|
169
174
|
}
|
|
170
175
|
|
|
171
|
-
const postSync = (initial:
|
|
176
|
+
const postSync = (initial: TonAccount, synced: TonAccount): TonAccount => {
|
|
172
177
|
// Set of ids from the already existing subAccount from previous sync
|
|
173
178
|
const initialSubAccountsIds = new Set();
|
|
174
179
|
for (const subAccount of initial.subAccounts || []) {
|
|
@@ -206,7 +211,7 @@ const postSync = (initial: Account, synced: Account): Account => {
|
|
|
206
211
|
};
|
|
207
212
|
};
|
|
208
213
|
|
|
209
|
-
function reconciliatePubkey(publicKey?: string, initialAccount?:
|
|
214
|
+
function reconciliatePubkey(publicKey?: string, initialAccount?: TonAccount): string {
|
|
210
215
|
if (publicKey?.length === 64) return publicKey;
|
|
211
216
|
if (initialAccount) {
|
|
212
217
|
if (initialAccount.xpub?.length === 64) return initialAccount.xpub;
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
Account,
|
|
2
3
|
Operation,
|
|
4
|
+
TokenAccount,
|
|
3
5
|
TransactionCommon,
|
|
4
6
|
TransactionCommonRaw,
|
|
5
7
|
TransactionStatusCommon,
|
|
@@ -43,6 +45,10 @@ export type TonPayloadJettonTransfer = {
|
|
|
43
45
|
customPayload: TonCell | null;
|
|
44
46
|
forwardAmount: bigint;
|
|
45
47
|
forwardPayload: TonCell | null;
|
|
48
|
+
knownJetton: {
|
|
49
|
+
jettonId: number;
|
|
50
|
+
workchain: number;
|
|
51
|
+
} | null;
|
|
46
52
|
};
|
|
47
53
|
|
|
48
54
|
export type TonPayloadNftTransfer = {
|
|
@@ -60,7 +66,91 @@ export type TonPayloadComment = {
|
|
|
60
66
|
text: string;
|
|
61
67
|
};
|
|
62
68
|
|
|
63
|
-
export type
|
|
69
|
+
export type TonPayloadUnsafe = {
|
|
70
|
+
type: "unsafe";
|
|
71
|
+
message: TonCell;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export type TonPayloadJettonBurn = {
|
|
75
|
+
type: "jetton-burn";
|
|
76
|
+
queryId: bigint | null;
|
|
77
|
+
amount: bigint;
|
|
78
|
+
responseDestination: Address;
|
|
79
|
+
customPayload: TonCell | Buffer | null;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export type TonPayloadAddWhitelist = {
|
|
83
|
+
type: "add-whitelist";
|
|
84
|
+
queryId: bigint | null;
|
|
85
|
+
address: Address;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export type TonPayloadSingleNominatorWithdraw = {
|
|
89
|
+
type: "single-nominator-withdraw";
|
|
90
|
+
queryId: bigint | null;
|
|
91
|
+
amount: bigint;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export type TonPayloadSingleNominatorChangeValidator = {
|
|
95
|
+
type: "single-nominator-change-validator";
|
|
96
|
+
queryId: bigint | null;
|
|
97
|
+
address: Address;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export type TonPayloadTonStakersDeposit = {
|
|
101
|
+
type: "tonstakers-deposit";
|
|
102
|
+
queryId: bigint | null;
|
|
103
|
+
appId: bigint | null;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export type TonPayloadVoteForProposal = {
|
|
107
|
+
type: "vote-for-proposal";
|
|
108
|
+
queryId: bigint | null;
|
|
109
|
+
votingAddress: Address;
|
|
110
|
+
expirationDate: number;
|
|
111
|
+
vote: boolean;
|
|
112
|
+
needConfirmation: boolean;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export type TonPayloadChangeDnsRecord = {
|
|
116
|
+
type: "change-dns-record";
|
|
117
|
+
queryId: bigint | null;
|
|
118
|
+
record:
|
|
119
|
+
| {
|
|
120
|
+
type: "wallet";
|
|
121
|
+
value: {
|
|
122
|
+
address: Address;
|
|
123
|
+
capabilities: {
|
|
124
|
+
isWallet: boolean;
|
|
125
|
+
} | null;
|
|
126
|
+
} | null;
|
|
127
|
+
}
|
|
128
|
+
| {
|
|
129
|
+
type: "unknown";
|
|
130
|
+
key: Buffer;
|
|
131
|
+
value: TonCell | null;
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export type TonPayloadTokenBridgePaySwap = {
|
|
136
|
+
type: "token-bridge-pay-swap";
|
|
137
|
+
queryId: bigint | null;
|
|
138
|
+
swapId: Buffer;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export type TonPayloadFormat =
|
|
142
|
+
| TonPayloadComment
|
|
143
|
+
| TonPayloadJettonTransfer
|
|
144
|
+
| TonPayloadNftTransfer
|
|
145
|
+
| TonPayloadUnsafe
|
|
146
|
+
| TonPayloadJettonBurn
|
|
147
|
+
| TonPayloadAddWhitelist
|
|
148
|
+
| TonPayloadSingleNominatorWithdraw
|
|
149
|
+
| TonPayloadSingleNominatorChangeValidator
|
|
150
|
+
| TonPayloadTonStakersDeposit
|
|
151
|
+
| TonPayloadVoteForProposal
|
|
152
|
+
| TonPayloadChangeDnsRecord
|
|
153
|
+
| TonPayloadTokenBridgePaySwap;
|
|
64
154
|
|
|
65
155
|
export interface TonTransaction {
|
|
66
156
|
to: Address;
|
|
@@ -80,3 +170,15 @@ export type TonOperationExtra = {
|
|
|
80
170
|
lt: string;
|
|
81
171
|
explorerHash: string;
|
|
82
172
|
};
|
|
173
|
+
|
|
174
|
+
export type KnownJetton = {
|
|
175
|
+
symbol: string;
|
|
176
|
+
masterAddress: Address;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export type TonSubAccount = TokenAccount & {
|
|
180
|
+
jettonWallet: string;
|
|
181
|
+
};
|
|
182
|
+
export type TonAccount = Omit<Account, "subAccounts"> & {
|
|
183
|
+
subAccounts?: TonSubAccount[];
|
|
184
|
+
};
|