@ledgerhq/coin-xrp 0.2.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/.eslintrc.js +20 -0
- package/.turbo/turbo-build.log +4 -0
- package/.unimportedrc.json +27 -0
- package/CHANGELOG.md +19 -0
- package/LICENSE.txt +21 -0
- package/jest.config.js +6 -0
- package/lib/api/index.d.ts +12 -0
- package/lib/api/index.d.ts.map +1 -0
- package/lib/api/index.js +117 -0
- package/lib/api/index.js.map +1 -0
- package/lib/api/types.d.ts +188 -0
- package/lib/api/types.d.ts.map +1 -0
- package/lib/api/types.js +3 -0
- package/lib/api/types.js.map +1 -0
- package/lib/bridge/js.d.ts +10 -0
- package/lib/bridge/js.d.ts.map +1 -0
- package/lib/bridge/js.js +47 -0
- package/lib/bridge/js.js.map +1 -0
- package/lib/broadcast.d.ts +4 -0
- package/lib/broadcast.d.ts.map +1 -0
- package/lib/broadcast.js +25 -0
- package/lib/broadcast.js.map +1 -0
- package/lib/cli-transaction.d.ts +26 -0
- package/lib/cli-transaction.d.ts.map +1 -0
- package/lib/cli-transaction.js +32 -0
- package/lib/cli-transaction.js.map +1 -0
- package/lib/config.d.ts +9 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +16 -0
- package/lib/config.js.map +1 -0
- package/lib/createTransaction.d.ts +4 -0
- package/lib/createTransaction.d.ts.map +1 -0
- package/lib/createTransaction.js +18 -0
- package/lib/createTransaction.js.map +1 -0
- package/lib/datasets/dataset-1.d.ts +5 -0
- package/lib/datasets/dataset-1.d.ts.map +1 -0
- package/lib/datasets/dataset-1.js +154 -0
- package/lib/datasets/dataset-1.js.map +1 -0
- package/lib/deviceTransactionConfig.d.ts +11 -0
- package/lib/deviceTransactionConfig.d.ts.map +1 -0
- package/lib/deviceTransactionConfig.js +27 -0
- package/lib/deviceTransactionConfig.js.map +1 -0
- package/lib/estimateMaxSpendable.d.ts +4 -0
- package/lib/estimateMaxSpendable.d.ts.map +1 -0
- package/lib/estimateMaxSpendable.js +31 -0
- package/lib/estimateMaxSpendable.js.map +1 -0
- package/lib/getTransactionStatus.d.ts +4 -0
- package/lib/getTransactionStatus.d.ts.map +1 -0
- package/lib/getTransactionStatus.js +82 -0
- package/lib/getTransactionStatus.js.map +1 -0
- package/lib/hw-getAddress.d.ts +6 -0
- package/lib/hw-getAddress.d.ts.map +1 -0
- package/lib/hw-getAddress.js +23 -0
- package/lib/hw-getAddress.js.map +1 -0
- package/lib/logic.d.ts +11 -0
- package/lib/logic.d.ts.map +1 -0
- package/lib/logic.js +93 -0
- package/lib/logic.js.map +1 -0
- package/lib/prepareTransaction.d.ts +4 -0
- package/lib/prepareTransaction.d.ts.map +1 -0
- package/lib/prepareTransaction.js +53 -0
- package/lib/prepareTransaction.js.map +1 -0
- package/lib/signOperation.d.ts +6 -0
- package/lib/signOperation.d.ts.map +1 -0
- package/lib/signOperation.js +99 -0
- package/lib/signOperation.js.map +1 -0
- package/lib/signer.d.ts +11 -0
- package/lib/signer.d.ts.map +1 -0
- package/lib/signer.js +3 -0
- package/lib/signer.js.map +1 -0
- package/lib/specs.d.ts +7 -0
- package/lib/specs.d.ts.map +1 -0
- package/lib/specs.js +66 -0
- package/lib/specs.js.map +1 -0
- package/lib/speculos-deviceActions.d.ts +4 -0
- package/lib/speculos-deviceActions.d.ts.map +1 -0
- package/lib/speculos-deviceActions.js +49 -0
- package/lib/speculos-deviceActions.js.map +1 -0
- package/lib/synchronization.d.ts +3 -0
- package/lib/synchronization.d.ts.map +1 -0
- package/lib/synchronization.js +74 -0
- package/lib/synchronization.js.map +1 -0
- package/lib/transaction.d.ts +15 -0
- package/lib/transaction.d.ts.map +1 -0
- package/lib/transaction.js +56 -0
- package/lib/transaction.js.map +1 -0
- package/lib/types.d.ts +30 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/lib-es/api/index.d.ts +12 -0
- package/lib-es/api/index.d.ts.map +1 -0
- package/lib-es/api/index.js +105 -0
- package/lib-es/api/index.js.map +1 -0
- package/lib-es/api/types.d.ts +188 -0
- package/lib-es/api/types.d.ts.map +1 -0
- package/lib-es/api/types.js +2 -0
- package/lib-es/api/types.js.map +1 -0
- package/lib-es/bridge/js.d.ts +10 -0
- package/lib-es/bridge/js.d.ts.map +1 -0
- package/lib-es/bridge/js.js +40 -0
- package/lib-es/bridge/js.js.map +1 -0
- package/lib-es/broadcast.d.ts +4 -0
- package/lib-es/broadcast.d.ts.map +1 -0
- package/lib-es/broadcast.js +21 -0
- package/lib-es/broadcast.js.map +1 -0
- package/lib-es/cli-transaction.d.ts +26 -0
- package/lib-es/cli-transaction.d.ts.map +1 -0
- package/lib-es/cli-transaction.js +26 -0
- package/lib-es/cli-transaction.js.map +1 -0
- package/lib-es/config.d.ts +9 -0
- package/lib-es/config.d.ts.map +1 -0
- package/lib-es/config.js +11 -0
- package/lib-es/config.js.map +1 -0
- package/lib-es/createTransaction.d.ts +4 -0
- package/lib-es/createTransaction.d.ts.map +1 -0
- package/lib-es/createTransaction.js +11 -0
- package/lib-es/createTransaction.js.map +1 -0
- package/lib-es/datasets/dataset-1.d.ts +5 -0
- package/lib-es/datasets/dataset-1.d.ts.map +1 -0
- package/lib-es/datasets/dataset-1.js +148 -0
- package/lib-es/datasets/dataset-1.js.map +1 -0
- package/lib-es/deviceTransactionConfig.d.ts +11 -0
- package/lib-es/deviceTransactionConfig.d.ts.map +1 -0
- package/lib-es/deviceTransactionConfig.js +25 -0
- package/lib-es/deviceTransactionConfig.js.map +1 -0
- package/lib-es/estimateMaxSpendable.d.ts +4 -0
- package/lib-es/estimateMaxSpendable.d.ts.map +1 -0
- package/lib-es/estimateMaxSpendable.js +24 -0
- package/lib-es/estimateMaxSpendable.js.map +1 -0
- package/lib-es/getTransactionStatus.d.ts +4 -0
- package/lib-es/getTransactionStatus.d.ts.map +1 -0
- package/lib-es/getTransactionStatus.js +75 -0
- package/lib-es/getTransactionStatus.js.map +1 -0
- package/lib-es/hw-getAddress.d.ts +6 -0
- package/lib-es/hw-getAddress.d.ts.map +1 -0
- package/lib-es/hw-getAddress.js +21 -0
- package/lib-es/hw-getAddress.js.map +1 -0
- package/lib-es/logic.d.ts +11 -0
- package/lib-es/logic.d.ts.map +1 -0
- package/lib-es/logic.js +82 -0
- package/lib-es/logic.js.map +1 -0
- package/lib-es/prepareTransaction.d.ts +4 -0
- package/lib-es/prepareTransaction.d.ts.map +1 -0
- package/lib-es/prepareTransaction.js +46 -0
- package/lib-es/prepareTransaction.js.map +1 -0
- package/lib-es/signOperation.d.ts +6 -0
- package/lib-es/signOperation.d.ts.map +1 -0
- package/lib-es/signOperation.js +92 -0
- package/lib-es/signOperation.js.map +1 -0
- package/lib-es/signer.d.ts +11 -0
- package/lib-es/signer.d.ts.map +1 -0
- package/lib-es/signer.js +2 -0
- package/lib-es/signer.js.map +1 -0
- package/lib-es/specs.d.ts +7 -0
- package/lib-es/specs.d.ts.map +1 -0
- package/lib-es/specs.js +61 -0
- package/lib-es/specs.js.map +1 -0
- package/lib-es/speculos-deviceActions.d.ts +4 -0
- package/lib-es/speculos-deviceActions.d.ts.map +1 -0
- package/lib-es/speculos-deviceActions.js +46 -0
- package/lib-es/speculos-deviceActions.js.map +1 -0
- package/lib-es/synchronization.d.ts +3 -0
- package/lib-es/synchronization.d.ts.map +1 -0
- package/lib-es/synchronization.js +67 -0
- package/lib-es/synchronization.js.map +1 -0
- package/lib-es/transaction.d.ts +15 -0
- package/lib-es/transaction.d.ts.map +1 -0
- package/lib-es/transaction.js +50 -0
- package/lib-es/transaction.js.map +1 -0
- package/lib-es/types.d.ts +30 -0
- package/lib-es/types.d.ts.map +1 -0
- package/lib-es/types.js +2 -0
- package/lib-es/types.js.map +1 -0
- package/package.json +81 -0
- package/please-add-coverage.test.ts +3 -0
- package/src/api/index.ts +138 -0
- package/src/api/types.ts +191 -0
- package/src/bridge/js.ts +56 -0
- package/src/broadcast.ts +20 -0
- package/src/cli-transaction.ts +44 -0
- package/src/config.ts +19 -0
- package/src/createTransaction.ts +13 -0
- package/src/datasets/dataset-1.ts +153 -0
- package/src/deviceTransactionConfig.ts +41 -0
- package/src/estimateMaxSpendable.ts +25 -0
- package/src/getTransactionStatus.ts +86 -0
- package/src/hw-getAddress.ts +20 -0
- package/src/logic.ts +101 -0
- package/src/prepareTransaction.ts +48 -0
- package/src/signOperation.ts +129 -0
- package/src/signer.ts +17 -0
- package/src/specs.ts +73 -0
- package/src/speculos-deviceActions.ts +53 -0
- package/src/synchronization.ts +73 -0
- package/src/transaction.ts +79 -0
- package/src/types.ts +39 -0
- package/tsconfig.json +13 -0
package/src/api/index.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { BigNumber } from "bignumber.js";
|
|
2
|
+
import network from "@ledgerhq/live-network/network";
|
|
3
|
+
import { parseCurrencyUnit } from "@ledgerhq/coin-framework/currencies";
|
|
4
|
+
import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies";
|
|
5
|
+
import { NEW_ACCOUNT_ERROR_MESSAGE } from "../logic";
|
|
6
|
+
import { getCoinConfig } from "../config";
|
|
7
|
+
import {
|
|
8
|
+
AccountInfoResponse,
|
|
9
|
+
AccountTxResponse,
|
|
10
|
+
LedgerResponse,
|
|
11
|
+
ServerInfoResponse,
|
|
12
|
+
SubmitReponse,
|
|
13
|
+
} from "./types";
|
|
14
|
+
|
|
15
|
+
const rippleUnit = getCryptoCurrencyById("ripple").units[0];
|
|
16
|
+
|
|
17
|
+
export const parseAPIValue = (value: string): BigNumber => parseCurrencyUnit(rippleUnit, value);
|
|
18
|
+
|
|
19
|
+
export const submit = async (signature: string): Promise<SubmitReponse> => {
|
|
20
|
+
const {
|
|
21
|
+
data: { result },
|
|
22
|
+
} = await network<{ result: SubmitReponse }>({
|
|
23
|
+
method: "POST",
|
|
24
|
+
url: getCoinConfig().node,
|
|
25
|
+
data: {
|
|
26
|
+
method: "submit",
|
|
27
|
+
params: [
|
|
28
|
+
{
|
|
29
|
+
tx_blob: signature,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const getAccountInfo = async (
|
|
38
|
+
recipient: string,
|
|
39
|
+
current?: boolean,
|
|
40
|
+
): Promise<AccountInfoResponse> => {
|
|
41
|
+
const {
|
|
42
|
+
data: { result },
|
|
43
|
+
} = await network<{ result: AccountInfoResponse }>({
|
|
44
|
+
method: "POST",
|
|
45
|
+
url: getCoinConfig().node,
|
|
46
|
+
data: {
|
|
47
|
+
method: "account_info",
|
|
48
|
+
params: [
|
|
49
|
+
{
|
|
50
|
+
account: recipient,
|
|
51
|
+
ledger_index: current ? "current" : "validated",
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
if (result.status !== "success" && result.error !== NEW_ACCOUNT_ERROR_MESSAGE) {
|
|
58
|
+
throw new Error(`couldn't fetch account info ${recipient}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return result;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const getServerInfos = async (
|
|
65
|
+
endpointConfig?: string | null | undefined,
|
|
66
|
+
): Promise<ServerInfoResponse> => {
|
|
67
|
+
const {
|
|
68
|
+
data: { result },
|
|
69
|
+
} = await network<{ result: ServerInfoResponse }>({
|
|
70
|
+
method: "POST",
|
|
71
|
+
url: endpointConfig ?? getCoinConfig().node,
|
|
72
|
+
data: {
|
|
73
|
+
method: "server_info",
|
|
74
|
+
params: [
|
|
75
|
+
{
|
|
76
|
+
ledger_index: "validated",
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (result.status !== "success") {
|
|
83
|
+
throw new Error(`couldn't fetch server info`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return result;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const getTransactions = async (
|
|
90
|
+
address: string,
|
|
91
|
+
options: { ledger_index_min?: number; ledger_index_max?: number } | undefined,
|
|
92
|
+
): Promise<AccountTxResponse["transactions"]> => {
|
|
93
|
+
const {
|
|
94
|
+
data: { result },
|
|
95
|
+
} = await network<{ result: AccountTxResponse }>({
|
|
96
|
+
method: "POST",
|
|
97
|
+
url: getCoinConfig().node,
|
|
98
|
+
data: {
|
|
99
|
+
method: "account_tx",
|
|
100
|
+
params: [
|
|
101
|
+
{
|
|
102
|
+
account: address,
|
|
103
|
+
ledger_index: "validated",
|
|
104
|
+
...options,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
if (result.status !== "success") {
|
|
111
|
+
throw new Error(`couldn't getTransactions for ${address}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return result.transactions;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export async function getLedgerIndex(): Promise<number> {
|
|
118
|
+
const {
|
|
119
|
+
data: { result },
|
|
120
|
+
} = await network<{ result: LedgerResponse }>({
|
|
121
|
+
method: "POST",
|
|
122
|
+
url: getCoinConfig().node,
|
|
123
|
+
data: {
|
|
124
|
+
method: "ledger",
|
|
125
|
+
params: [
|
|
126
|
+
{
|
|
127
|
+
ledger_index: "validated",
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if (result.status !== "success") {
|
|
134
|
+
throw new Error(`couldn't fetch getLedgerIndex`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return result.ledger_index;
|
|
138
|
+
}
|
package/src/api/types.ts
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
export type XrplOperation = {
|
|
2
|
+
meta: {
|
|
3
|
+
AffectedNodes: {
|
|
4
|
+
ModifiedNode: {
|
|
5
|
+
FinalFields: {
|
|
6
|
+
Account: string;
|
|
7
|
+
Balance: string;
|
|
8
|
+
Flags: number;
|
|
9
|
+
OwnerCount: number;
|
|
10
|
+
Sequence: number;
|
|
11
|
+
};
|
|
12
|
+
LedgerEntryType: string;
|
|
13
|
+
LedgerIndex: string;
|
|
14
|
+
PreviousFields: {
|
|
15
|
+
Balance: string;
|
|
16
|
+
};
|
|
17
|
+
PreviousTxnID: string;
|
|
18
|
+
PreviousTxnLgrSeq: number;
|
|
19
|
+
};
|
|
20
|
+
}[];
|
|
21
|
+
TransactionIndex: number;
|
|
22
|
+
TransactionResult: string;
|
|
23
|
+
delivered_amount: string;
|
|
24
|
+
};
|
|
25
|
+
tx: {
|
|
26
|
+
Account: string;
|
|
27
|
+
Amount: string;
|
|
28
|
+
DeliverMax: string;
|
|
29
|
+
Destination: string;
|
|
30
|
+
DestinationTag: number;
|
|
31
|
+
Fee: string;
|
|
32
|
+
Flags: number;
|
|
33
|
+
LastLedgerSequence: number;
|
|
34
|
+
Memos: {
|
|
35
|
+
Memo: {
|
|
36
|
+
MemoData: string;
|
|
37
|
+
};
|
|
38
|
+
}[];
|
|
39
|
+
Sequence: number;
|
|
40
|
+
SigningPubKey: string;
|
|
41
|
+
TransactionType: string;
|
|
42
|
+
TxnSignature: string;
|
|
43
|
+
date: number;
|
|
44
|
+
hash: string;
|
|
45
|
+
inLedger: number;
|
|
46
|
+
ledger_index: number;
|
|
47
|
+
};
|
|
48
|
+
validated: boolean;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
type ResponseStatus =
|
|
52
|
+
| { status: string; error?: never }
|
|
53
|
+
| {
|
|
54
|
+
status?: never;
|
|
55
|
+
error: string;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export type AccountInfoResponse = {
|
|
59
|
+
account_data: {
|
|
60
|
+
Account: string;
|
|
61
|
+
Balance: string;
|
|
62
|
+
Flags: number;
|
|
63
|
+
LedgerEntryType: string;
|
|
64
|
+
OwnerCount: number;
|
|
65
|
+
PreviousTxnID: string;
|
|
66
|
+
PreviousTxnLgrSeq: number;
|
|
67
|
+
Sequence: number;
|
|
68
|
+
index: string;
|
|
69
|
+
};
|
|
70
|
+
account_flags: {
|
|
71
|
+
allowTrustLineClawback: boolean;
|
|
72
|
+
defaultRipple: boolean;
|
|
73
|
+
depositAuth: boolean;
|
|
74
|
+
disableMasterKey: boolean;
|
|
75
|
+
disallowIncomingCheck: boolean;
|
|
76
|
+
disallowIncomingNFTokenOffer: boolean;
|
|
77
|
+
disallowIncomingPayChan: boolean;
|
|
78
|
+
disallowIncomingTrustline: boolean;
|
|
79
|
+
disallowIncomingXRP: boolean;
|
|
80
|
+
globalFreeze: boolean;
|
|
81
|
+
noFreeze: boolean;
|
|
82
|
+
passwordSpent: boolean;
|
|
83
|
+
requireAuthorization: boolean;
|
|
84
|
+
requireDestinationTag: boolean;
|
|
85
|
+
};
|
|
86
|
+
ledger_hash: string;
|
|
87
|
+
ledger_index: number;
|
|
88
|
+
validated: boolean;
|
|
89
|
+
} & ResponseStatus;
|
|
90
|
+
|
|
91
|
+
export type SubmitReponse = {
|
|
92
|
+
accepted: boolean;
|
|
93
|
+
account_sequence_available: number;
|
|
94
|
+
account_sequence_next: number;
|
|
95
|
+
applied: boolean;
|
|
96
|
+
broadcast: boolean;
|
|
97
|
+
engine_result: string;
|
|
98
|
+
engine_result_code: 0;
|
|
99
|
+
engine_result_message: string;
|
|
100
|
+
kept: boolean;
|
|
101
|
+
open_ledger_cost: string;
|
|
102
|
+
queued: false;
|
|
103
|
+
status: string;
|
|
104
|
+
tx_blob: string;
|
|
105
|
+
tx_json: {
|
|
106
|
+
Account: string;
|
|
107
|
+
Amount: string;
|
|
108
|
+
Destination: string;
|
|
109
|
+
Fee: string;
|
|
110
|
+
Flags: number;
|
|
111
|
+
LastLedgerSequence: number;
|
|
112
|
+
Sequence: number;
|
|
113
|
+
SigningPubKey: string;
|
|
114
|
+
TransactionType: string;
|
|
115
|
+
TxnSignature: string;
|
|
116
|
+
hash: string;
|
|
117
|
+
};
|
|
118
|
+
validated_ledger_index: number;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export type ServerInfoResponse = {
|
|
122
|
+
info: {
|
|
123
|
+
build_version: string;
|
|
124
|
+
complete_ledgers: string;
|
|
125
|
+
hostid: string;
|
|
126
|
+
initial_sync_duration_us: string;
|
|
127
|
+
io_latency_ms: number;
|
|
128
|
+
jq_trans_overflow: string;
|
|
129
|
+
last_close: {
|
|
130
|
+
converge_time_s: number;
|
|
131
|
+
proposers: number;
|
|
132
|
+
};
|
|
133
|
+
load_factor: number;
|
|
134
|
+
network_id: number;
|
|
135
|
+
peer_disconnects: string;
|
|
136
|
+
peer_disconnects_resources: string;
|
|
137
|
+
peers: number;
|
|
138
|
+
ports: { port: string; protocol: ["ws" | "http" | "peer"] }[];
|
|
139
|
+
pubkey_node: string;
|
|
140
|
+
server_state: string;
|
|
141
|
+
server_state_duration_us: string;
|
|
142
|
+
state_accounting: Record<
|
|
143
|
+
"connected" | "disconnected" | "full" | "syncing" | "tracking",
|
|
144
|
+
{
|
|
145
|
+
duration_us: string;
|
|
146
|
+
transitions: string;
|
|
147
|
+
}
|
|
148
|
+
>;
|
|
149
|
+
time: string;
|
|
150
|
+
uptime: number;
|
|
151
|
+
validated_ledger: {
|
|
152
|
+
age: number;
|
|
153
|
+
base_fee_xrp: number;
|
|
154
|
+
hash: string;
|
|
155
|
+
reserve_base_xrp: number;
|
|
156
|
+
reserve_inc_xrp: number;
|
|
157
|
+
seq: number;
|
|
158
|
+
};
|
|
159
|
+
validation_quorum: number;
|
|
160
|
+
};
|
|
161
|
+
} & ResponseStatus;
|
|
162
|
+
|
|
163
|
+
export type AccountTxResponse = {
|
|
164
|
+
account: string;
|
|
165
|
+
ledger_index_max: number;
|
|
166
|
+
ledger_index_min: number;
|
|
167
|
+
limit: number;
|
|
168
|
+
transactions: XrplOperation[];
|
|
169
|
+
validated: boolean;
|
|
170
|
+
} & ResponseStatus;
|
|
171
|
+
|
|
172
|
+
export type LedgerResponse = {
|
|
173
|
+
ledger: {
|
|
174
|
+
account_hash: string;
|
|
175
|
+
close_flags: number;
|
|
176
|
+
close_time: number;
|
|
177
|
+
close_time_human: string;
|
|
178
|
+
close_time_iso: string;
|
|
179
|
+
close_time_resolution: number;
|
|
180
|
+
closed: boolean;
|
|
181
|
+
ledger_hash: string;
|
|
182
|
+
ledger_index: string;
|
|
183
|
+
parent_close_time: number;
|
|
184
|
+
parent_hash: string;
|
|
185
|
+
total_coins: string;
|
|
186
|
+
transaction_hash: string;
|
|
187
|
+
};
|
|
188
|
+
ledger_hash: string;
|
|
189
|
+
ledger_index: number;
|
|
190
|
+
validated: boolean;
|
|
191
|
+
} & ResponseStatus;
|
package/src/bridge/js.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
makeAccountBridgeReceive,
|
|
3
|
+
defaultUpdateTransaction,
|
|
4
|
+
makeScanAccounts,
|
|
5
|
+
makeSync,
|
|
6
|
+
} from "@ledgerhq/coin-framework/bridge/jsHelpers";
|
|
7
|
+
import { SignerContext } from "@ledgerhq/coin-framework/signer";
|
|
8
|
+
import getAddressWrapper from "@ledgerhq/coin-framework/bridge/getAddressWrapper";
|
|
9
|
+
import type { AccountBridge, CurrencyBridge } from "@ledgerhq/types-live";
|
|
10
|
+
import { getTransactionStatus } from "../getTransactionStatus";
|
|
11
|
+
import { estimateMaxSpendable } from "../estimateMaxSpendable";
|
|
12
|
+
import { prepareTransaction } from "../prepareTransaction";
|
|
13
|
+
import { createTransaction } from "../createTransaction";
|
|
14
|
+
import { getAccountShape } from "../synchronization";
|
|
15
|
+
import { buildSignOperation } from "../signOperation";
|
|
16
|
+
import { XrpConfig, setCoinConfig } from "../config";
|
|
17
|
+
import type { Transaction } from "../types";
|
|
18
|
+
import { broadcast } from "../broadcast";
|
|
19
|
+
import resolver from "../hw-getAddress";
|
|
20
|
+
import { XrpSigner } from "../signer";
|
|
21
|
+
|
|
22
|
+
export function createBridges(
|
|
23
|
+
signerContext: SignerContext<XrpSigner>,
|
|
24
|
+
coinConfig: () => XrpConfig,
|
|
25
|
+
) {
|
|
26
|
+
setCoinConfig(coinConfig);
|
|
27
|
+
|
|
28
|
+
const getAddress = resolver(signerContext);
|
|
29
|
+
|
|
30
|
+
const scanAccounts = makeScanAccounts({ getAccountShape, getAddressFn: getAddress });
|
|
31
|
+
const currencyBridge: CurrencyBridge = {
|
|
32
|
+
preload: () => Promise.resolve({}),
|
|
33
|
+
hydrate: () => {},
|
|
34
|
+
scanAccounts,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const receive = makeAccountBridgeReceive(getAddressWrapper(getAddress));
|
|
38
|
+
const signOperation = buildSignOperation(signerContext);
|
|
39
|
+
const sync = makeSync({ getAccountShape });
|
|
40
|
+
const accountBridge: AccountBridge<Transaction> = {
|
|
41
|
+
createTransaction,
|
|
42
|
+
updateTransaction: defaultUpdateTransaction<Transaction>,
|
|
43
|
+
prepareTransaction,
|
|
44
|
+
getTransactionStatus,
|
|
45
|
+
estimateMaxSpendable,
|
|
46
|
+
sync,
|
|
47
|
+
receive,
|
|
48
|
+
signOperation,
|
|
49
|
+
broadcast,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
currencyBridge,
|
|
54
|
+
accountBridge,
|
|
55
|
+
};
|
|
56
|
+
}
|
package/src/broadcast.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AccountBridge } from "@ledgerhq/types-live";
|
|
2
|
+
import { patchOperationWithHash } from "@ledgerhq/coin-framework/operation";
|
|
3
|
+
import { Transaction } from "./types";
|
|
4
|
+
import { submit } from "./api";
|
|
5
|
+
|
|
6
|
+
export const broadcast: AccountBridge<Transaction>["broadcast"] = async ({
|
|
7
|
+
signedOperation: { signature, operation },
|
|
8
|
+
}) => {
|
|
9
|
+
const submittedPayment = await submit(signature);
|
|
10
|
+
|
|
11
|
+
if (
|
|
12
|
+
submittedPayment.engine_result !== "tesSUCCESS" &&
|
|
13
|
+
submittedPayment.engine_result !== "terQUEUED"
|
|
14
|
+
) {
|
|
15
|
+
throw new Error(submittedPayment.engine_result_message);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const { hash } = submittedPayment.tx_json;
|
|
19
|
+
return patchOperationWithHash(operation, hash);
|
|
20
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import invariant from "invariant";
|
|
2
|
+
import type { AccountLike } from "@ledgerhq/types-live";
|
|
3
|
+
import type { Transaction } from "./types";
|
|
4
|
+
import BigNumber from "bignumber.js";
|
|
5
|
+
|
|
6
|
+
const options = [
|
|
7
|
+
{
|
|
8
|
+
name: "fee",
|
|
9
|
+
type: String,
|
|
10
|
+
desc: "how much fee",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: "tag",
|
|
14
|
+
type: Number,
|
|
15
|
+
desc: "ripple tag",
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
function inferTransactions(
|
|
20
|
+
transactions: Array<{
|
|
21
|
+
account: AccountLike;
|
|
22
|
+
transaction: Transaction;
|
|
23
|
+
}>,
|
|
24
|
+
opts: { tag?: number | null | undefined; fee?: string },
|
|
25
|
+
{
|
|
26
|
+
inferAmount,
|
|
27
|
+
}: { inferAmount: (account: AccountLike, fee?: string) => BigNumber | null | undefined },
|
|
28
|
+
): Transaction[] {
|
|
29
|
+
return transactions.flatMap(({ transaction, account }) => {
|
|
30
|
+
invariant(transaction.family === "xrp", "XRP family");
|
|
31
|
+
return {
|
|
32
|
+
...transaction,
|
|
33
|
+
fee: inferAmount(account, opts.fee || "0.001xrp"),
|
|
34
|
+
tag: opts.tag,
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export default function makeCliTools() {
|
|
40
|
+
return {
|
|
41
|
+
options,
|
|
42
|
+
inferTransactions,
|
|
43
|
+
};
|
|
44
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CurrencyConfig } from "@ledgerhq/coin-framework/config";
|
|
2
|
+
|
|
3
|
+
export type XrpConfig = CurrencyConfig & {
|
|
4
|
+
node: string;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
let coinConfig: () => XrpConfig | undefined;
|
|
8
|
+
|
|
9
|
+
export const setCoinConfig = (config: typeof coinConfig): void => {
|
|
10
|
+
coinConfig = config;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const getCoinConfig = (): XrpConfig => {
|
|
14
|
+
if (!coinConfig?.()) {
|
|
15
|
+
throw new Error("Xrp module config not set");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return coinConfig()!;
|
|
19
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import BigNumber from "bignumber.js";
|
|
2
|
+
import { Transaction } from "./types";
|
|
3
|
+
import { AccountBridge } from "@ledgerhq/types-live";
|
|
4
|
+
|
|
5
|
+
export const createTransaction: AccountBridge<Transaction>["createTransaction"] = () => ({
|
|
6
|
+
family: "xrp",
|
|
7
|
+
amount: new BigNumber(0),
|
|
8
|
+
recipient: "",
|
|
9
|
+
fee: null,
|
|
10
|
+
tag: undefined,
|
|
11
|
+
networkInfo: null,
|
|
12
|
+
feeCustomUnit: null,
|
|
13
|
+
});
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import BigNumber from "bignumber.js";
|
|
2
|
+
import { DatasetTest } from "@ledgerhq/types-live";
|
|
3
|
+
import { InvalidAddressBecauseDestinationIsAlsoSource } from "@ledgerhq/errors";
|
|
4
|
+
import { fromTransactionRaw } from "../transaction";
|
|
5
|
+
import { Transaction } from "../types";
|
|
6
|
+
|
|
7
|
+
export const newAddress1 = "rZvBc5e2YR1A9otS3r9DyGh3NDP8XLLp4";
|
|
8
|
+
|
|
9
|
+
export const dataset: DatasetTest<Transaction> = {
|
|
10
|
+
implementations: ["mock", "ripplejs"],
|
|
11
|
+
currencies: {
|
|
12
|
+
ripple: {
|
|
13
|
+
scanAccounts: [
|
|
14
|
+
{
|
|
15
|
+
name: "ripple seed 1",
|
|
16
|
+
unstableAccounts: true,
|
|
17
|
+
// our account is getting spammed...
|
|
18
|
+
apdus: `
|
|
19
|
+
=> e00200400d038000002c8000009080000000
|
|
20
|
+
<= 2103c73f64083463fa923e1530af6f558204853873c6a45cbfb1f2f1e2ac2a5d989c2272734a4675764165634c333153513750594864504b6b3335625a456f78446d5231789000
|
|
21
|
+
=> e002004015058000002c80000090800000000000000000000000
|
|
22
|
+
<= 2103d1adcff3e0cf1232b1416a75cd6f23b49dd6a25c69bc291a1f6783ec6825ec062272616765584842365134566276765764547a4b414e776a65435434485846434b58379000
|
|
23
|
+
=> e002004015058000002c80000090800000010000000000000000
|
|
24
|
+
<= 21036da109ee84825eab0f55fb57bcf9ef0b05621e71fb0400266fb42d6f68f9487c2272425065393169766d67384347573450414e6f657555555173756d337470786a55469000
|
|
25
|
+
=> e002004015058000002c80000090800000020000000000000000
|
|
26
|
+
<= 2102df9a55b79fb3668dac70fee7372806195841cd713ab8da9fba82240f9db8a23921725a76426335653259523141396f745333723944794768334e445038584c4c70349000
|
|
27
|
+
`,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
accounts: [
|
|
31
|
+
{
|
|
32
|
+
transactions: [
|
|
33
|
+
// FIXME
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
{
|
|
37
|
+
name: "not enough spendable balance with base reserve",
|
|
38
|
+
transaction: fromTransactionRaw({
|
|
39
|
+
family: "xrp",
|
|
40
|
+
recipient: "rB6pwovsyrFWhPYUsjj9V3CHck985QjiXi",
|
|
41
|
+
amount: "15000000",
|
|
42
|
+
tag: null,
|
|
43
|
+
fee: "1",
|
|
44
|
+
feeCustomUnit: null,
|
|
45
|
+
networkInfo: null,
|
|
46
|
+
}),
|
|
47
|
+
expectedStatus: {
|
|
48
|
+
amount: BigNumber("15000000"),
|
|
49
|
+
estimatedFees: BigNumber("1"),
|
|
50
|
+
errors: {
|
|
51
|
+
amount: new NotEnoughSpendableBalance(null, {
|
|
52
|
+
minimumAmount: formatCurrencyUnit(
|
|
53
|
+
rippleUnit,
|
|
54
|
+
BigNumber("20"),
|
|
55
|
+
{
|
|
56
|
+
disableRounding: true,
|
|
57
|
+
useGrouping: false,
|
|
58
|
+
showCode: true,
|
|
59
|
+
}
|
|
60
|
+
),
|
|
61
|
+
}),
|
|
62
|
+
},
|
|
63
|
+
warnings: {},
|
|
64
|
+
totalSpent: BigNumber("15000001"),
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
*/
|
|
68
|
+
// FIXME
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
{
|
|
72
|
+
name: "operation amount to low to create the recipient account",
|
|
73
|
+
transaction: fromTransactionRaw({
|
|
74
|
+
family: "xrp",
|
|
75
|
+
recipient: newAddress1,
|
|
76
|
+
amount: "10000000",
|
|
77
|
+
tag: null,
|
|
78
|
+
fee: "1",
|
|
79
|
+
feeCustomUnit: null,
|
|
80
|
+
networkInfo: null
|
|
81
|
+
}),
|
|
82
|
+
expectedStatus: {
|
|
83
|
+
amount: BigNumber("10000000"),
|
|
84
|
+
estimatedFees: BigNumber("1"),
|
|
85
|
+
errors: {
|
|
86
|
+
amount: new NotEnoughBalanceBecauseDestinationNotCreated()
|
|
87
|
+
},
|
|
88
|
+
warnings: {},
|
|
89
|
+
totalSpent: BigNumber("10000001")
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
*/
|
|
93
|
+
{
|
|
94
|
+
name: "recipient and sender must not be the same",
|
|
95
|
+
transaction: fromTransactionRaw({
|
|
96
|
+
family: "xrp",
|
|
97
|
+
recipient: "rageXHB6Q4VbvvWdTzKANwjeCT4HXFCKX7",
|
|
98
|
+
amount: "10000000",
|
|
99
|
+
tag: null,
|
|
100
|
+
fee: "1",
|
|
101
|
+
feeCustomUnit: null,
|
|
102
|
+
networkInfo: null,
|
|
103
|
+
}),
|
|
104
|
+
expectedStatus: {
|
|
105
|
+
amount: new BigNumber("10000000"),
|
|
106
|
+
estimatedFees: new BigNumber("1"),
|
|
107
|
+
errors: {
|
|
108
|
+
recipient: new InvalidAddressBecauseDestinationIsAlsoSource(),
|
|
109
|
+
},
|
|
110
|
+
warnings: {},
|
|
111
|
+
totalSpent: new BigNumber("10000001"),
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: "Operation with tag succeed",
|
|
116
|
+
transaction: fromTransactionRaw({
|
|
117
|
+
family: "xrp",
|
|
118
|
+
recipient: "rB6pwovsyrFWhPYUsjj9V3CHck985QjiXi",
|
|
119
|
+
amount: "10000000",
|
|
120
|
+
tag: 12345,
|
|
121
|
+
fee: "1",
|
|
122
|
+
feeCustomUnit: null,
|
|
123
|
+
networkInfo: null,
|
|
124
|
+
}),
|
|
125
|
+
expectedStatus: {
|
|
126
|
+
amount: new BigNumber("10000000"),
|
|
127
|
+
estimatedFees: new BigNumber("1"),
|
|
128
|
+
errors: {},
|
|
129
|
+
warnings: {},
|
|
130
|
+
totalSpent: new BigNumber("10000001"),
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
raw: {
|
|
135
|
+
id: "ripplejs:2:ripple:rageXHB6Q4VbvvWdTzKANwjeCT4HXFCKX7:",
|
|
136
|
+
seedIdentifier: "rageXHB6Q4VbvvWdTzKANwjeCT4HXFCKX7",
|
|
137
|
+
name: "XRP 1",
|
|
138
|
+
derivationMode: "",
|
|
139
|
+
index: 0,
|
|
140
|
+
freshAddress: "rageXHB6Q4VbvvWdTzKANwjeCT4HXFCKX7",
|
|
141
|
+
freshAddressPath: "44'/144'/0'/0/0",
|
|
142
|
+
blockHeight: 0,
|
|
143
|
+
operations: [],
|
|
144
|
+
pendingOperations: [],
|
|
145
|
+
currencyId: "ripple",
|
|
146
|
+
lastSyncDate: "",
|
|
147
|
+
balance: "21000310",
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AccountLike, Account } from "@ledgerhq/types-live";
|
|
2
|
+
import type { Transaction, TransactionStatus } from "./types";
|
|
3
|
+
import type { CommonDeviceTransactionField } from "@ledgerhq/coin-framework/transaction/common";
|
|
4
|
+
|
|
5
|
+
function getDeviceTransactionConfig({
|
|
6
|
+
transaction: { tag },
|
|
7
|
+
status: { amount, estimatedFees },
|
|
8
|
+
}: {
|
|
9
|
+
account: AccountLike;
|
|
10
|
+
parentAccount: Account | null | undefined;
|
|
11
|
+
transaction: Transaction;
|
|
12
|
+
status: TransactionStatus;
|
|
13
|
+
}): Array<CommonDeviceTransactionField> {
|
|
14
|
+
const fields: Array<CommonDeviceTransactionField> = [];
|
|
15
|
+
|
|
16
|
+
if (!amount.isZero()) {
|
|
17
|
+
fields.push({
|
|
18
|
+
type: "amount",
|
|
19
|
+
label: "Amount",
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!estimatedFees.isZero()) {
|
|
24
|
+
fields.push({
|
|
25
|
+
type: "fees",
|
|
26
|
+
label: "Fees",
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (tag) {
|
|
31
|
+
fields.push({
|
|
32
|
+
type: "text",
|
|
33
|
+
label: "Tag",
|
|
34
|
+
value: tag ? String(tag) : "",
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return fields;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export default getDeviceTransactionConfig;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import BigNumber from "bignumber.js";
|
|
2
|
+
import { AccountBridge } from "@ledgerhq/types-live";
|
|
3
|
+
import { getMainAccount } from "@ledgerhq/coin-framework/account/index";
|
|
4
|
+
import { getAbandonSeedAddress } from "@ledgerhq/cryptoassets/abandonseed";
|
|
5
|
+
import { getTransactionStatus } from "./getTransactionStatus";
|
|
6
|
+
import { prepareTransaction } from "./prepareTransaction";
|
|
7
|
+
import { createTransaction } from "./createTransaction";
|
|
8
|
+
import { Transaction } from "./types";
|
|
9
|
+
|
|
10
|
+
export const estimateMaxSpendable: AccountBridge<Transaction>["estimateMaxSpendable"] = async ({
|
|
11
|
+
account,
|
|
12
|
+
parentAccount,
|
|
13
|
+
transaction,
|
|
14
|
+
}) => {
|
|
15
|
+
const mainAccount = getMainAccount(account, parentAccount);
|
|
16
|
+
const newTransaction = await prepareTransaction(mainAccount, {
|
|
17
|
+
...createTransaction(account),
|
|
18
|
+
...transaction,
|
|
19
|
+
recipient: transaction?.recipient || getAbandonSeedAddress("ripple"),
|
|
20
|
+
// public testing seed abandonx11,about
|
|
21
|
+
amount: new BigNumber(0),
|
|
22
|
+
});
|
|
23
|
+
const status = await getTransactionStatus(mainAccount, newTransaction);
|
|
24
|
+
return BigNumber.max(0, account.spendableBalance.minus(status.estimatedFees));
|
|
25
|
+
};
|