You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
5.5 KiB
116 lines
5.5 KiB
// @flow
|
|
|
|
import type { Observable } from 'rxjs'
|
|
import type { BigNumber } from 'bignumber.js'
|
|
import type { Account, Operation, Currency } from '@ledgerhq/live-common/lib/types'
|
|
|
|
// a WalletBridge is implemented on renderer side.
|
|
// this is an abstraction on top of libcore / ethereumjs / ripple js / ...
|
|
// that would directly be called from UI needs.
|
|
|
|
export type DeviceId = string // for now it's just usb path
|
|
|
|
export type Observer<T> = {
|
|
next: T => void,
|
|
complete: () => void,
|
|
error: (?Error) => void,
|
|
}
|
|
|
|
export type Subscription = {
|
|
+unsubscribe: () => void,
|
|
}
|
|
|
|
export type EditProps<Transaction> = {
|
|
account: Account,
|
|
value: Transaction,
|
|
onChange: Transaction => void,
|
|
}
|
|
|
|
export interface WalletBridge<Transaction> {
|
|
// in "import"/"recover" step, we need a way to scan all accounts from the device
|
|
// for a given currency.
|
|
// deviceId currently is the device path.
|
|
// observer is an Observer of Account object. Account are expected to be `archived` by default because we want to import all and opt-in on what account to use.
|
|
// the scan can stop once all accounts are discovered.
|
|
// the function returns a Subscription and you MUST stop everything if it is unsubscribed.
|
|
// TODO return Observable
|
|
scanAccountsOnDevice(currency: Currency, deviceId: DeviceId): Observable<Account>;
|
|
|
|
// synchronize an account. meaning updating the account object with latest state.
|
|
// function receives the initialAccount object so you can actually know what the user side currently have
|
|
// then you must emit one or more updater functions to inform data changes.
|
|
// an update function is just a Account => Account that perform the changes (to avoid race condition issues)
|
|
// this can emit new version of the account. typically these field can change over time:
|
|
// operations if there are new ones (prepended), balance, blockHeight, ...
|
|
// the synchronize can stop once everything is up to date. it is the user side responsability to start it again.
|
|
// we should be able to interrupt the Subscription but we'll leave this usecase for later. if you don't support interruption, please `console.warn`
|
|
synchronize(initialAccount: Account): Observable<(Account) => Account>;
|
|
|
|
// for a given account, UI wants to load more operations in the account.operations
|
|
// if you can't do it or there is no more things to load, just return account,
|
|
// otherwise return (asynchronously) an account updater that add operations in account.operations
|
|
// count is user's desired number of ops to pull (but implementation can decide to ignore it or not)
|
|
pullMoreOperations(initialAccount: Account, count: number): Promise<(Account) => Account>;
|
|
|
|
isRecipientValid(currency: Currency, recipient: string): Promise<boolean>;
|
|
getRecipientWarning(currency: Currency, recipient: string): Promise<?Error>;
|
|
|
|
// Related to send funds:
|
|
|
|
// a Transaction object is a black box that can be improved by the following methods & components...
|
|
// IMPORTANT: this is only a temporary object on UI side! not on libcore side
|
|
// underlying implementation can have the same concept too, the point is we need sync api for the UI
|
|
// if you have async api under the hood, you will have to cache things and return tmp values..
|
|
|
|
createTransaction(account: Account): Transaction;
|
|
|
|
editTransactionAmount(account: Account, transaction: Transaction, amount: BigNumber): Transaction;
|
|
|
|
getTransactionAmount(account: Account, transaction: Transaction): BigNumber;
|
|
|
|
editTransactionRecipient(
|
|
account: Account,
|
|
transaction: Transaction,
|
|
recipient: string,
|
|
): Transaction;
|
|
|
|
getTransactionRecipient(account: Account, transaction: Transaction): string;
|
|
|
|
// render the whole Fees section of the form
|
|
EditFees?: *; // React$ComponentType<EditProps<Transaction>>;
|
|
|
|
// render the whole advanced part of the form
|
|
EditAdvancedOptions?: *; // React$ComponentType<EditProps<Transaction>>;
|
|
|
|
// validate the transaction and all currency specific validations here, we can return false
|
|
// to disable the button without throwing an error if we are handling the error on a different
|
|
// input or throw an error that will highlight the issue on the amount field
|
|
checkValidTransaction(account: Account, transaction: Transaction): Promise<boolean>;
|
|
|
|
getTotalSpent(account: Account, transaction: Transaction): Promise<BigNumber>;
|
|
|
|
// NB this is not used yet but we'll use it when we have MAX
|
|
getMaxAmount(account: Account, transaction: Transaction): Promise<BigNumber>;
|
|
|
|
/**
|
|
* finalize the transaction by
|
|
* - signing it with the ledger device
|
|
* - broadcasting it to network
|
|
* - retrieve and return the optimistic Operation that this transaction is likely to create in the future
|
|
*
|
|
* NOTE: in future, when transaction balance is close to account.balance, we could wipe it all at this level...
|
|
* to implement that, we might want to have special logic `account.balance-transaction.amount < dust` but not sure where this should leave (i would say on UI side because we need to inform user visually).
|
|
*/
|
|
signAndBroadcast(
|
|
account: Account,
|
|
transaction: Transaction,
|
|
deviceId: DeviceId,
|
|
): Observable<{ type: 'signed' } | { type: 'broadcasted', operation: Operation }>;
|
|
|
|
// Implement an optimistic response for signAndBroadcast.
|
|
// you likely should add the operation in account.pendingOperations but maybe you want to clean it (because maybe some are replaced / cancelled by this one?)
|
|
addPendingOperation?: (account: Account, optimisticOperation: Operation) => Account;
|
|
|
|
getDefaultEndpointConfig?: () => string;
|
|
validateEndpointConfig?: (endpointConfig: string) => Promise<void>;
|
|
}
|
|
|