-
Notifications
You must be signed in to change notification settings - Fork 2
/
lipabusinesslib.udl
313 lines (273 loc) · 11.4 KB
/
lipabusinesslib.udl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
// The Lipa Business Library (LBL)
//
// The main goal of this library is to provide all the required cryptographic
// and Bitcoin protocol functionality for the 'Lipa Wallet for business'.
// Use "Bitcoin" for production code (= runs on the Bitcoin mainnet)
// Testnet and Signet are test *networks*, while Regtest enables an entirely local test environment
enum Network {
"Bitcoin",
"Testnet",
"Signet",
"Regtest",
};
enum LogLevel {
"Error",
"Warn",
"Info",
"Debug",
"Trace",
};
// A code that specifies an LBL RuntimeError that ocurred
enum WalletRuntimeErrorCode {
"ElectrumServiceUnavailable", // The electrum service is unavailable. Could there be a loss of internet connection?
"NotEnoughFunds", // There are not enough funds to create the tx that was requested
"RemoteServiceUnavailable", // A remote service is unavailable. Could there be a loss of internet connection?
"SendToOurselves", // Trying to send funds to an address belonging to the wallet
"GenericError", // A generic error for unexpected/unknown runtime errors
};
[Error]
interface WalletError {
// Invalid input.
// Consider fixing the input and retrying the request.
InvalidInput(string msg);
// Recoverable problem (e.g. network issue, problem with en external service).
// Consider retrying the request.
RuntimeError(WalletRuntimeErrorCode code, string msg);
// Unrecoverable problem (e.g. internal invariant broken).
// Consider suggesting the user to report the issue to the developers.
PermanentFailure(string msg);
};
// A code that specifies an Auth RuntimeError that ocurred
enum AuthRuntimeErrorCode {
"AuthServiceError", // An error occurred with the authentication process. Please try again.
"AccessExpired", // Access to the backed services has expired
"NetworkError", // Failed to get a response from a remote service. Could there be a loss of internet connection?
"RemoteServiceUnavailable", // The remote service returned a 502 HTTP status
"GenericError", // A generic error for unexpected/unknown runtime errors
// Due to some design flows in wild libraries the following values must be declared here,
// but are not actually possible.
"CorruptData",
"ObjectNotFound",
};
[Error]
interface AuthError {
// Invalid input.
// Consider fixing the input and retrying the request.
InvalidInput(string msg);
// Recoverable problem (e.g. network issue, problem with en external service).
// Consider retrying the request.
RuntimeError(AuthRuntimeErrorCode code, string msg);
// Unrecoverable problem (e.g. internal invariant broken).
// Consider suggesting the user to report the issue to the developers.
PermanentFailure(string msg);
};
// A key pair with both keys encoded as a hex string.
dictionary KeyPair {
string secret_key;
string public_key;
};
// A pair of descriptors. The watch_descriptor doesn't include private keys and is appropriate to instantiate
// a Wallet object. To be able to spend, the spend_descriptor will be required. The spend_descriptor includes
// private keys and as such should be obtained from secure storage only when strictly necessary.
dictionary Descriptors {
string spend_descriptor;
string watch_descriptor;
};
// A structure that holds all useful keys that can be derived from the mnemonic using derive_keys()
dictionary WalletKeys {
KeyPair wallet_keypair; // Used for authentication with the Lipa backend
Descriptors wallet_descriptors; // Used for instantiating a local on-chain wallet
};
// An object that holds all configuration needed to instantiate a Wallet object
//
// Fields:
// * electrum_url - url of the electrum backend used to access the Bitcoin blockchain
// Suggested values:
// - "ssl://electrum.blockstream.info:50002" for Mainnet (PROD)
// - "ssl://electrum.blockstream.info:60002" for Testnet
// * wallet_db_path - a path on the mobile device's filesystem where the wallet db will be created
// * network - the Bitcoin Network the node should run on (see enum above)
// * watch_descriptor - the watch descriptor that can be obtained from WalletKeys
dictionary Config {
string electrum_url;
string wallet_db_path;
Network network;
string watch_descriptor;
};
// Detailed balance information that can be obtained using Wallet.sync_balance();
//
// Fields:
// * confirmed - confirmed balance
// * trusted_pending - pending balance that only the local wallet can double-spend
// * untrusted_pending - pending balance that could be double-spent by others
// * immature - immature coinbase outputs. Can be ignored as it's not expected that miners
// will be mining towards this wallet
dictionary Balance {
u64 confirmed;
u64 trusted_pending;
u64 untrusted_pending;
u64 immature;
};
// Lists possible errors of parsing an on-chain address.
[Error]
interface AddressParsingError {
InvalidNetwork(Network expected, Network address);
Other();
};
interface Wallet {
// Create a new Wallet instance.
[Throws=WalletError]
constructor(Config config);
// Syncs the local database with Electrum
[Throws=WalletError]
void sync();
// Get the current balance of the wallet.
//
// The balance is obtained from the local database. To have the balance be up-to-date, the method `sync()` should be
// called beforehand.
[Throws=WalletError]
Balance get_balance();
// Get an unused P2WPKH address from the local wallet
[Throws=WalletError]
string get_addr();
// Validates that an address is valid and the local wallet can send funds to it.
// Returns a normalized representation of the address.
[Throws=AddressParsingError]
string parse_address(string address);
// Constructs a tx that completely drains (sends all funds available) the wallet.
// The tx is not actually broadcast here.
//
// Parameters:
// * addr - the layer 1 address to send to.
// * confirm_in_blocks - the target number of blocks used to estimate the on-chain fee.
// The lower this number, the higher the fee will be. Must be in the interval [1; 25].
[Throws=WalletError]
Tx prepare_drain_tx(string addr, u32 confirm_in_blocks);
// Signs and broadcasts a provided tx. Requires a spend descriptor to be used to sign the transaction.
[Throws=WalletError]
TxDetails sign_and_broadcast_tx(bytes tx_blob, string spend_descriptor);
// Returns the status of a tx given its tx id.
//
// The status is obtained from the local database. To have the status be up-to-date, the method `sync()` should be
// called beforehand.
[Throws=WalletError]
TxStatus get_tx_status(string txid);
// Returns a list of all txs that have been sent out from the local wallet.
// The list is sorted from newest (unconfirmed) txs to txs with higher number of confirmations,
// and by tx id if number of confirmations is the same.
//
// The list is obtained from the local database. To have the list be up-to-date, the method `sync()` should be
// called beforehand.
[Throws=WalletError]
sequence<TxDetails> get_spending_txs();
// Provides an estimation of the local wallet having enough funds for prepare_drain_tx() to be successful.
// Returns true if prepare_drain_tx() is likely to succeed, false otherwise.
//
// Parameters:
// * confirm_in_blocks - the target number of blocks used to estimate the on-chain fee. The value that will be
// provided later to prepare_drain_tx() should be the same.
[Throws=WalletError]
boolean is_drain_tx_affordable(u32 confirm_in_blocks);
};
// A Bitcoin tx
//
// Fields:
// * id - the txid
// * blob - the serialized tx (PSBT)
// * on_chain_fee_sat - on-chain fees included in the tx (denominated in sats)
// * output_sat - amount of bitcoin to be transferred (denominated in sats)
//
// the new local balance after this tx will be:
// new_balance = old_balance - (output_sat + on_chain_fee_sat)
dictionary Tx {
string id;
bytes blob;
u64 on_chain_fee_sat;
u64 output_sat;
};
// Status of a tx
//
// Variants:
// * NotInMempool - the tx is neither confirmed nor in the mempool. Probably the on-chain fee was set too low
// and the tx got evicted from the mempool. This situation is unlikely given that the local wallet will
// avoid using low fees.
// * InMempool - the tx has 0 confirmations
// * Confirmed - the tx has at least 1 confirmation. The exact number of confirmations is provided (number_of_blocks)
// and it's commonly accepted that 6 confirmations isn't reversible. The timestamp (confirmed_at) of confirmation
// is also provided.
[Enum]
interface TxStatus {
NotInMempool();
InMempool();
Confirmed(u32 number_of_blocks, timestamp confirmed_at);
};
// Details about a tx
//
// Fields:
// * id - the txid
// * output_address - the address to which funds have been/will be transferred
// * output_sat - amount of bitcoin to be transferred (denominated in sats)
// * on_chain_fee_sat - on-chain fees included in the tx (denominated in sats)
// * status - the TxStatus of the tx
dictionary TxDetails {
string id;
string output_address;
u64 output_sat;
u64 on_chain_fee_sat;
TxStatus status;
};
// An authorization level
//
// Owner and Employee levels include the Pseudonymous level privileges
enum AuthLevel {
"Pseudonymous",
"Owner",
"Employee",
};
interface Auth {
// Creates a new Auth instance
//
// Parameters:
// * backend_url: The URL of the backend instance to authenticate on.
// * auth_level: The authorization level to which authentication will be done.
// * wallet_keypair: The local wallet keypair
// * auth_keypair: A random keypair
//
// This method does not access the internet
[Throws=AuthError]
constructor(string backend_url, AuthLevel auth_level, KeyPair wallet_keypair, KeyPair auth_keypair);
// Get a hot access token
//
// Internally, this handles getting a valid access token by one of the following ways:
// * Returning a cached token if it hasn't expired
// * Refreshing the access token using a refresh token if it hasn't expired
// * Restarting the auth process
// As such, the execution time of this method can vary.
[Throws=AuthError]
string query_token();
// Get the wallet UUID v5 from the wallet pubkey
//
// Returns an optional value. If `query_token()` has never succeeded in this Auth instance, the wallet UUID v5
// is unknown and None is returned. Otherwise, this method will always return the wallet UUID v5.
//
// This method does not access the internet
string? get_wallet_pubkey_id();
};
namespace lipabusinesslib {
// Initiate the logger and set the log level.
void init_native_logger_once(LogLevel min_level);
// Generate a new mnemonic.
[Throws=WalletError]
sequence<string> generate_mnemonic();
// Derives WalletKeys from a mnemonic.
[Throws=WalletError]
WalletKeys derive_keys(Network network, sequence<string> mnemonic_string);
// Signs a message with the provided private_key. Used for authenticating with the backend.
[Throws=WalletError]
string sign(string message, string private_key);
// Generate a new keypair. Used for authentication with the backend.
KeyPair generate_keypair();
// Return a list of valid BIP-39 English words starting with the prefix.
// Calling this function with empty prefix will return the full list of BIP-39 words.
sequence<string> words_by_prefix(string prefix);
};