diff --git a/CODEOWNERS b/CODEOWNERS index 31d769dbc..badf27073 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,4 +1,5 @@ * @ledgerhq/live-blockchain-support +packages/types-devices @ledgerhq/live-devices packages/devices @ledgerhq/live-devices packages/hw-transport-* @ledgerhq/live-devices packages/react-native-* @ledgerhq/live-devices \ No newline at end of file diff --git a/packages/types-cryptoassets/README.md b/packages/types-cryptoassets/README.md new file mode 100644 index 000000000..6a9d64fc7 --- /dev/null +++ b/packages/types-cryptoassets/README.md @@ -0,0 +1,74 @@ + + +## @ledgerhq/types-cryptoassets + +Ledger types for crypto assets and tokens. + +## API + + + +#### Table of Contents + +* [Unit](#unit) + * [Properties](#properties) +* [CurrencyCommon](#currencycommon) + * [Properties](#properties-1) +* [TokenCurrency](#tokencurrency) +* [FiatCurrency](#fiatcurrency) +* [ExplorerView](#explorerview) + * [Properties](#properties-2) +* [CryptoCurrency](#cryptocurrency) +* [Currency](#currency) + +### Unit + +Type: {name: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), code: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), magnitude: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), showAllDigits: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?, prefixCode: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?} + +#### Properties + +* `name` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** +* `code` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** +* `magnitude` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** +* `showAllDigits` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** +* `prefixCode` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** + +### CurrencyCommon + +Type: {name: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), ticker: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), units: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Unit](#unit)>, symbol: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?, disableCountervalue: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?, delisted: [boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?, countervalueTicker: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?} + +#### Properties + +* `name` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** +* `ticker` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** +* `units` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Unit](#unit)>** +* `symbol` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** +* `disableCountervalue` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** +* `delisted` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** +* `countervalueTicker` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** + +### TokenCurrency + +Type: any + +### FiatCurrency + +Type: any + +### ExplorerView + +Type: {tx: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?, address: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?, token: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?} + +#### Properties + +* `tx` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** +* `address` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** +* `token` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** + +### CryptoCurrency + +Type: any + +### Currency + +Type: ([FiatCurrency](#fiatcurrency) | [CryptoCurrency](#cryptocurrency) | [TokenCurrency](#tokencurrency)) diff --git a/packages/types-cryptoassets/package.json b/packages/types-cryptoassets/package.json new file mode 100644 index 000000000..91c35c9f6 --- /dev/null +++ b/packages/types-cryptoassets/package.json @@ -0,0 +1,29 @@ +{ + "name": "@ledgerhq/types-cryptoassets", + "version": "6.21.3", + "description": "Ledger types for crypto assets and tokens", + "keywords": [ + "Ledger" + ], + "repository": { + "type": "git", + "url": "https://github.com/LedgerHQ/ledgerjs" + }, + "bugs": { + "url": "https://github.com/LedgerHQ/ledgerjs/issues" + }, + "homepage": "https://github.com/LedgerHQ/ledgerjs", + "publishConfig": { + "access": "public" + }, + "main": "lib/index.js", + "module": "lib-es/index.js", + "types": "lib/index.d.ts", + "license": "Apache-2.0", + "scripts": { + "clean": "bash ../../script/clean.sh", + "build": "bash ../../script/build.sh", + "watch": "bash ../../script/watch.sh", + "doc": "bash ../../script/doc.sh" + } +} diff --git a/packages/types-cryptoassets/src/index.ts b/packages/types-cryptoassets/src/index.ts new file mode 100644 index 000000000..f0b84356f --- /dev/null +++ b/packages/types-cryptoassets/src/index.ts @@ -0,0 +1,117 @@ +/** + * + */ +export type Unit = { + // display name of a given unit (example: satoshi) + name: string; + // string to use when formatting the unit. like 'BTC' or 'USD' + code: string; + // number of digits after the '.' + magnitude: number; + // should it always print all digits even if they are 0 (usually: true for fiats, false for cryptos) + showAllDigits?: boolean; + // true if the code should prefix amount when formatting + prefixCode?: boolean; +}; + +/** + * + */ +type CurrencyCommon = { + // display name of a currency + name: string; + // the ticker name in exchanges / countervalue apis (e.g. BTC). + ticker: string; + // all units of a currency (e.g. Bitcoin have bitcoin, mBTC, bit, satoshi) + // by convention, [0] is the default and have "highest" magnitude + units: Unit[]; + // a shorter version of code using the symbol of the currency. like Ƀ . not all cryptocurrencies have a symbol + symbol?: string; + // tells if countervalue need to be disabled (typically because colliding with other coins) + disableCountervalue?: boolean; + delisted?: boolean; + // some countervalue will have a ticker alias + countervalueTicker?: string; +}; + +/** + * + */ +export type TokenCurrency = CurrencyCommon & { + type: "TokenCurrency"; + id: string; + ledgerSignature?: string; + contractAddress: string; + // the currency it belongs to. e.g. 'ethereum' + parentCurrency: CryptoCurrency; + // the type of token in the blockchain it belongs. e.g. 'erc20' + tokenType: string; + // indicates this is a compound token and it's "parent" erc20 have this id + compoundFor?: string; +}; + +/** + * + */ +export type FiatCurrency = CurrencyCommon & { + type: "FiatCurrency"; +}; + +/** + * + */ +export type ExplorerView = { + tx?: string; + address?: string; + token?: string; +}; + +/** + * + */ +export type CryptoCurrency = CurrencyCommon & { + type: "CryptoCurrency"; + // unique internal id of a crypto currency + id: string; + // define if a crypto is a fork from another coin. helps dealing with split/unsplit + forkedFrom?: string; + // name of the app as shown in the Manager + managerAppName: string; + // coin type according to slip44. THIS IS NOT GUARANTEED UNIQUE across currencies (e.g testnets,..) + coinType: number; + // the scheme name to use when formatting an URI (without the ':') + scheme: string; + // used for UI + color: string; + family: string; + blockAvgTime?: number; + // in seconds + supportsSegwit?: boolean; + supportsNativeSegwit?: boolean; + // if defined this coin is a testnet for another crypto (id)}; + isTestnetFor?: string; + // TODO later we could express union of types with mandatory bitcoinLikeInfo for "bitcoin" family... + bitcoinLikeInfo?: { + P2PKH: number; + P2SH: number; + XPUBVersion?: number; + // FIXME optional as we miss some data to fill + hasTimestamp?: boolean; + }; + ethereumLikeInfo?: { + chainId: number; + networkId?: number; + baseChain?: string; + hardfork?: string; + }; + explorerViews: ExplorerView[]; + terminated?: { + link: string; + }; + deviceTicker?: string; +}; + +/** + * + */ +export type Currency = FiatCurrency | CryptoCurrency | TokenCurrency; diff --git a/packages/types-cryptoassets/tsconfig.json b/packages/types-cryptoassets/tsconfig.json new file mode 100644 index 000000000..0cf4676de --- /dev/null +++ b/packages/types-cryptoassets/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["src/**/*"] +} diff --git a/packages/types-devices/README.md b/packages/types-devices/README.md new file mode 100644 index 000000000..88f88c715 --- /dev/null +++ b/packages/types-devices/README.md @@ -0,0 +1,99 @@ + + +## @ledgerhq/types-devices + +Ledger types for devices and transport. + +## API + + + +#### Table of Contents + +* [DeviceModelId](#devicemodelid) +* [DeviceModel](#devicemodel) +* [BluetoothInfos](#bluetoothinfos) +* [Subscription](#subscription) + * [Properties](#properties) +* [Device](#device) +* [Observer](#observer) +* [send](#send) + * [Parameters](#parameters) +* [on](#on) +* [off](#off) +* [setExchangeTimeout](#setexchangetimeout) +* [setExchangeUnresponsiveTimeout](#setexchangeunresponsivetimeout) + +### DeviceModelId + +DeviceModelId is a unique identifier to identify the model of a Ledger hardware wallet. + +### DeviceModel + +a DeviceModel contains all the information of a specific Ledger hardware wallet model. + +### BluetoothInfos + +### Subscription + +represent an ongoing job that can be stopped with .unsubscribe() + +Type: {unsubscribe: function (): void} + +#### Properties + +* `unsubscribe` **function (): void** + +### Device + +data about the device. not yet typed + +Type: any + +### Observer + +Type: Readonly<{next: function (event: Ev): any, error: function (e: any): any, complete: function (): any}> + +### send + +wrapper on top of exchange to simplify work of the implementation. + +Type: function (cla: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), ins: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), p1: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), p2: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number), data: [Buffer](https://nodejs.org/api/buffer.html), statusList: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)>): [Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<[Buffer](https://nodejs.org/api/buffer.html)> + +#### Parameters + +* `cla` +* `ins` +* `p1` +* `p2` +* `data` +* `statusList` is a list of accepted status code (shorts). \[0x9000] by default + +Returns **any** a Promise of response buffer + +### on + +Listen to an event on an instance of transport. +Transport implementation can have specific events. Here is the common events: + +* `"disconnect"` : triggered if Transport is disconnected + +Type: function (eventName: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), cb: function (...args: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)\): any): void + +### off + +Stop listening to an event on an instance of transport. + +Type: function (eventName: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String), cb: function (...args: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)\): any): void + +### setExchangeTimeout + +Set a timeout (in milliseconds) for the exchange call. Only some transport might implement it. (e.g. U2F) + +Type: function (exchangeTimeout: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)): void + +### setExchangeUnresponsiveTimeout + +Define the delay before emitting "unresponsive" on an exchange that does not respond + +Type: function (unresponsiveTimeout: [number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)): void diff --git a/packages/types-devices/package.json b/packages/types-devices/package.json new file mode 100644 index 000000000..29e0031da --- /dev/null +++ b/packages/types-devices/package.json @@ -0,0 +1,29 @@ +{ + "name": "@ledgerhq/types-devices", + "version": "6.21.3", + "description": "Ledger types for devices and transport.", + "keywords": [ + "Ledger" + ], + "repository": { + "type": "git", + "url": "https://github.com/LedgerHQ/ledgerjs" + }, + "bugs": { + "url": "https://github.com/LedgerHQ/ledgerjs/issues" + }, + "homepage": "https://github.com/LedgerHQ/ledgerjs", + "publishConfig": { + "access": "public" + }, + "main": "lib/index.js", + "module": "lib-es/index.js", + "types": "lib/index.d.ts", + "license": "Apache-2.0", + "scripts": { + "clean": "bash ../../script/clean.sh", + "build": "bash ../../script/build.sh", + "watch": "bash ../../script/watch.sh", + "doc": "bash ../../script/doc.sh" + } +} diff --git a/packages/types-devices/src/index.ts b/packages/types-devices/src/index.ts new file mode 100644 index 000000000..5c6107285 --- /dev/null +++ b/packages/types-devices/src/index.ts @@ -0,0 +1,132 @@ +/** + * DeviceModelId is a unique identifier to identify the model of a Ledger hardware wallet. + */ +export enum DeviceModelId { + blue = "blue", + nanoS = "nanoS", + nanoSP = "nanoSP", + nanoX = "nanoX", +} +/** + * a DeviceModel contains all the information of a specific Ledger hardware wallet model. + */ +export interface DeviceModel { + id: DeviceModelId; + productName: string; + productIdMM: number; + legacyUsbProductId: number; + usbOnly: boolean; + memorySize: number; + masks: number[]; + getBlockSize: (firmwareVersion: string) => number; + bluetoothSpec?: { + serviceUuid: string; + writeUuid: string; + writeCmdUuid: string; + notifyUuid: string; + }[]; +} + +/** + * + */ +export interface BluetoothInfos { + deviceModel: DeviceModel; + serviceUuid: string; + writeUuid: string; + writeCmdUuid: string; + notifyUuid: string; +} +/** + * represent an ongoing job that can be stopped with .unsubscribe() + */ +export type Subscription = { + unsubscribe: () => void; +}; + +/** + * data about the device. not yet typed + */ +export type Device = any; // Should be a union type of all possible Device object's shape + +export interface DescriptorEvent { + type: "add" | "remove"; + descriptor: Descriptor; + deviceModel?: DeviceModel | null | undefined; + device?: Device; +} + +/** + */ +export type Observer = Readonly<{ + next: (event: Ev) => unknown; + error: (e: any) => unknown; + complete: () => unknown; +}>; + +export interface Transport { + deviceModel: DeviceModel | null | undefined; + + exchange: (apdu: Buffer) => Promise; + close: () => Promise; + setScrambleKey: (key: string) => void; + + /** + * wrapper on top of exchange to simplify work of the implementation. + * @param cla + * @param ins + * @param p1 + * @param p2 + * @param data + * @param statusList is a list of accepted status code (shorts). [0x9000] by default + * @return a Promise of response buffer + */ + send: ( + cla: number, + ins: number, + p1: number, + p2: number, + data?: Buffer, + statusList?: Array + ) => Promise; + + /** + * Listen to an event on an instance of transport. + * Transport implementation can have specific events. Here is the common events: + * * `"disconnect"` : triggered if Transport is disconnected + */ + on: (eventName: string, cb: (...args: Array) => any) => void; + + /** + * Stop listening to an event on an instance of transport. + */ + off: (eventName: string, cb: (...args: Array) => any) => void; + emit: (event: string, ...args: any) => void; + + /** + * Set a timeout (in milliseconds) for the exchange call. Only some transport might implement it. (e.g. U2F) + */ + setExchangeTimeout: (exchangeTimeout: number) => void; + + /** + * Define the delay before emitting "unresponsive" on an exchange that does not respond + */ + setExchangeUnresponsiveTimeout: (unresponsiveTimeout: number) => void; + + exchangeAtomicImpl: ( + f: () => Promise + ) => Promise; + + decorateAppAPIMethods: ( + self: Record, + methods: Array, + scrambleKey: string + ) => void; + + decorateAppAPIMethod: ( + methodName: string, + f: (...args: A) => Promise, + ctx: any, + scrambleKey: string + ) => (...args: A) => Promise; +} diff --git a/packages/types-devices/tsconfig.json b/packages/types-devices/tsconfig.json new file mode 100644 index 000000000..0cf4676de --- /dev/null +++ b/packages/types-devices/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["src/**/*"] +} diff --git a/packages/types-live/README.md b/packages/types-live/README.md new file mode 100644 index 000000000..76965270c --- /dev/null +++ b/packages/types-live/README.md @@ -0,0 +1,19 @@ + + +## @ledgerhq/types-live + +Ledger Live main types. + +## API + + + +#### Table of Contents + +* [DerivationMode](#derivationmode) + +### DerivationMode + +DerivationMode is a string identifier of a specific derivation scheme in a list defined in live-common derivation.ts + +Type: [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) diff --git a/packages/types-live/package.json b/packages/types-live/package.json new file mode 100644 index 000000000..84779fb32 --- /dev/null +++ b/packages/types-live/package.json @@ -0,0 +1,34 @@ +{ + "name": "@ledgerhq/types-live", + "version": "6.21.3", + "description": "Ledger Live main types.", + "keywords": [ + "Ledger" + ], + "repository": { + "type": "git", + "url": "https://github.com/LedgerHQ/ledgerjs" + }, + "bugs": { + "url": "https://github.com/LedgerHQ/ledgerjs/issues" + }, + "homepage": "https://github.com/LedgerHQ/ledgerjs", + "publishConfig": { + "access": "public" + }, + "main": "lib/index.js", + "module": "lib-es/index.js", + "types": "lib/index.d.ts", + "license": "Apache-2.0", + "dependencies": { + "@ledgerhq/types-cryptoassets": "6", + "rxjs": "6", + "bignumber.js": "9" + }, + "scripts": { + "clean": "bash ../../script/clean.sh", + "build": "bash ../../script/build.sh", + "watch": "bash ../../script/watch.sh", + "doc": "bash ../../script/doc.sh" + } +} diff --git a/packages/types-live/src/account.ts b/packages/types-live/src/account.ts new file mode 100644 index 000000000..b6128daf6 --- /dev/null +++ b/packages/types-live/src/account.ts @@ -0,0 +1,292 @@ +import type { BigNumber } from "bignumber.js"; +import type { + CryptoCurrency, + TokenCurrency, + Unit, +} from "@ledgerhq/types-cryptoassets"; +import type { OperationRaw, Operation } from "./operation"; +import type { DerivationMode } from "./derivation"; + +import type { + BalanceHistory, + BalanceHistoryRaw, + PortfolioRange, +} from "./portfolio"; +import type { SwapOperation, SwapOperationRaw } from "./swap"; +import type { NFT, NFTRaw } from "./nft"; +// This is the old cache and now DEPRECATED (pre v2 portfoli) +export type BalanceHistoryMap = Partial>; +export type BalanceHistoryRawMap = Record; +export type GranularityId = "HOUR" | "DAY" | "WEEK"; +// the cache is maintained for as many granularity as we need on Live. +// it's currently an in memory cache so there is no problem regarding the storage. +// in future, it could be saved and we can rethink how it's stored (independently of how it's in memory) +export type BalanceHistoryCache = Record< + GranularityId, + BalanceHistoryDataCache +>; +// the way BalanceHistoryDataCache works is: +// - a "cursor" date which is the "latestDate" representing the latest datapoint date. it's null if it never was loaded or if it's empty. +// - an array of balances. balances are stored in JSNumber even tho internally calculated with bignumbers because we want very good perf. it shouldn't impact imprecision (which happens when we accumulate values, not when presenting to user) +// there are as much value in that array as there are historical datapoint for a given account. +// each time an account will sync, it potentially update it by adding a datapoint and possibility updating the cursor in that case. +export type BalanceHistoryDataCache = { + latestDate: number | null | undefined; + balances: number[]; +}; +// A token belongs to an Account and share the parent account address +export type TokenAccount = { + type: "TokenAccount"; + id: string; + // id of the parent account this token account belongs to + parentId: string; + token: TokenCurrency; + balance: BigNumber; + spendableBalance: BigNumber; + // in case of compound, this is the associated balance for the associated ctoken + compoundBalance?: BigNumber; + creationDate: Date; + operationsCount: number; + operations: Operation[]; + pendingOperations: Operation[]; + starred: boolean; + // DEPRECATED! it will be dropped when switching to Portfolio V2 + balanceHistory?: BalanceHistoryMap; + // Cache of balance history that allows a performant portfolio calculation. + // currently there are no "raw" version of it because no need to at this stage. + // could be in future when pagination is needed. + balanceHistoryCache: BalanceHistoryCache; + // Swap operations linked to this account + swapHistory: SwapOperation[]; + approvals?: Array<{ + sender: string; + value: string; + }>; +}; +// A child account belongs to an Account but has its own address +export type ChildAccount = { + type: "ChildAccount"; + id: string; + name: string; + starred: boolean; + // id of the parent account this token account belongs to + parentId: string; + currency: CryptoCurrency; + address: string; + balance: BigNumber; + creationDate: Date; + operationsCount: number; + operations: Operation[]; + pendingOperations: Operation[]; + // DEPRECATED! it will be dropped when switching to Portfolio V2 + balanceHistory?: BalanceHistoryMap; + // Cache of balance history that allows a performant portfolio calculation. + // currently there are no "raw" version of it because no need to at this stage. + // could be in future when pagination is needed. + balanceHistoryCache: BalanceHistoryCache; + // Swap operations linked to this account + swapHistory: SwapOperation[]; +}; +export type Address = { + address: string; + derivationPath: string; +}; +export type Account = { + type: "Account"; + // unique account identifier + id: string; + // a unique way to identify a seed the account was associated with + // it MUST be different between 2 seeds + // but it is not necessarily the same between 2 accounts (if possible – not always possible) + // in BTC like accounts, we use pubKey(purpose'/coinType') + // For other accounts that don't have sub derivation, we have used the account address + seedIdentifier: string; + // account xpub if available + xpub?: string; + // Identify the derivation used. it allows us to map this to a derivation scheme. + // example of values: segwit | unsplit | segwit_unsplit | mew | eth_mew (eg for etc accounts on eth) + // the special value of '' means it's bip44 with purpose 44. + derivationMode: DerivationMode; + // the iterated number to derive the account in a given derivationMode config + // in context of bip44, it would be the account field of bip44 ( m/purpose'/cointype'/account' ) + index: number; + // next receive address. to be used to display to user. + // (deprecated - corresponds to freshAddresses[0].address) + freshAddress: string; + // The path linked to freshAddress. to be used to validate with the device if it corresponds to freshAddress. + // example: 44'/0'/0'/0/0 + // (deprecated - corresponds to freshAddresses[0].derivationPath) + freshAddressPath: string; + // an array containing all fresh addresses and paths + // may be empty if no sync has occurred + freshAddresses: Address[]; + // account name + name: string; + // starred + starred: boolean; + // says if the account essentially "exists". an account has been used in the past, but for some reason the blockchain finds it empty (no ops, no balance,..) + used: boolean; + // account balance in satoshi + balance: BigNumber; + // part of the balance that can effectively be spent + spendableBalance: BigNumber; + // date the account started "existing", essentially the date of the older tx received/done of this account + // It is equal to Date.now() for EMPTY accounts because empty account don't really "exists" + creationDate: Date; + // the last block height currently synchronized + blockHeight: number; + // ------------------------------------- Specific account fields + // currency of this account + currency: CryptoCurrency; + // user preferred unit to use. unit is coming from currency.units. You can assume currency.units.indexOf(unit) will work. (make sure to preserve reference) + unit: Unit; + // The total number of operations (operations[] can be partial) + operationsCount: number; + // lazy list of operations that exists on the blockchain. + operations: Operation[]; + // pending operations that has been broadcasted but are not yet in operations + // this is for optimistic updates UI. the Operation objects are temporary and + // might not be the real one that will arrives on operations array. + // only Operation#id needs to be guaranteed the same. + // the array resulting of pendingOperations.concat(operations) + // is guaranteed to contains unique ops (by id) at any time and also is time DESC sorted. + pendingOperations: Operation[]; + // used to know when the last sync happened + lastSyncDate: Date; + // A configuration for the endpoint to use. (usecase: Ripple node) + // FIXME drop and introduce a config{} object + endpointConfig?: string | null | undefined; + // An account can have sub accounts. + // A sub account can be either a token account or a child account in some blockchain. + // They are attached to the parent account in the related blockchain. + // CONVENTION: + // a SubAccount is living inside an Account but is not an entity on its own, + // therefore, there is no .parentAccount in it, which will means you will need to always have a tuple of (parentAccount, account) + // we will use the naming (parentAccount, account) everywhere because a sub account is not enough and you need the full context with this tuple. + // These are two valid examples: + // I'm inside a ZRX token account of Ethereum 1: { parentAccount: Ethereum 1, account: ZRX } + // I'm just inside the Ethereum 1: { account: Ethereum 1, parentAccount: undefined } + // "account" is the primary account that you use/select/view. It is a `AccountLike`. + // "parentAccount", if available, is the contextual account. It is a `?Account`. + subAccounts?: SubAccount[]; + // balance history represented the balance evolution throughout time, used by chart. + // This is to be refreshed when necessary (typically in a sync) + // this is a map PER granularity to allow a fast feedback when user switch them + // DEPRECATED! it will be dropped when switching to Portfolio V2 + balanceHistory?: BalanceHistoryMap; + // Cache of balance history that allows a performant portfolio calculation. + // currently there are no "raw" version of it because no need to at this stage. + // could be in future when pagination is needed. + balanceHistoryCache: BalanceHistoryCache; + + // FIXME how to solve this? + /* + // On some blockchain, an account can have resources (gained, delegated, ...) + bitcoinResources?: BitcoinResources; + tronResources?: TronResources; + cosmosResources?: CosmosResources; + algorandResources?: AlgorandResources; + polkadotResources?: PolkadotResources; + tezosResources?: TezosResources; + elrondResources?: ElrondResources; + cryptoOrgResources?: CryptoOrgResources; + */ + + // Swap operations linked to this account + swapHistory: SwapOperation[]; + // Hash used to discard tx history on sync + syncHash?: string; + // Array of NFTs computed by diffing NFTOperations ordered from newest to oldest + nfts?: NFT[]; +}; +export type SubAccount = TokenAccount | ChildAccount; +export type AccountLike = Account | SubAccount; +// Damn it flow. can't you support covariance. +export type AccountLikeArray = // $FlowFixMe wtf mobile + | AccountLike[] + | TokenAccount[] + | ChildAccount[] + | Account[]; +export type TokenAccountRaw = { + type: "TokenAccountRaw"; + id: string; + starred?: boolean; + parentId: string; + tokenId: string; + creationDate?: string; + operationsCount?: number; + operations: OperationRaw[]; + pendingOperations: OperationRaw[]; + balance: string; + spendableBalance?: string; + compoundBalance?: string; + balanceHistory?: BalanceHistoryRawMap; + balanceHistoryCache?: BalanceHistoryCache; + swapHistory?: SwapOperationRaw[]; + approvals?: Array<{ + sender: string; + value: string; + }>; +}; +export type ChildAccountRaw = { + type: "ChildAccountRaw"; + id: string; + name: string; + starred?: boolean; + parentId: string; + currencyId: string; + address: string; + creationDate?: string; + operationsCount?: number; + operations: OperationRaw[]; + pendingOperations: OperationRaw[]; + balance: string; + balanceHistory?: BalanceHistoryRawMap; + balanceHistoryCache?: BalanceHistoryCache; + swapHistory?: SwapOperationRaw[]; +}; +export type AccountRaw = { + id: string; + seedIdentifier: string; + xpub?: string; + derivationMode: DerivationMode; + index: number; + freshAddress: string; + freshAddressPath: string; + freshAddresses: Address[]; + name: string; + starred?: boolean; + used?: boolean; + balance: string; + spendableBalance?: string; + blockHeight: number; + creationDate?: string; + operationsCount?: number; + // this is optional for backward compat + // ------------------------------------- Specific raw fields + currencyId: string; + operations: OperationRaw[]; + pendingOperations: OperationRaw[]; + unitMagnitude: number; + lastSyncDate: string; + endpointConfig?: string | null | undefined; + subAccounts?: SubAccountRaw[]; + balanceHistory?: BalanceHistoryRawMap; + balanceHistoryCache?: BalanceHistoryCache; + // FIXME + /* + bitcoinResources?: BitcoinResourcesRaw; + tronResources?: TronResourcesRaw; + cosmosResources?: CosmosResourcesRaw; + algorandResources?: AlgorandResourcesRaw; + polkadotResources?: PolkadotResourcesRaw; + elrondResources?: ElrondResourcesRaw; + tezosResources?: TezosResourcesRaw; + cryptoOrgResources?: CryptoOrgResourcesRaw; + */ + swapHistory?: SwapOperationRaw[]; + syncHash?: string; + nfts?: NFTRaw[]; +}; +export type SubAccountRaw = TokenAccountRaw | ChildAccountRaw; +export type AccountRawLike = AccountRaw | SubAccountRaw; diff --git a/packages/types-live/src/bridge.ts b/packages/types-live/src/bridge.ts new file mode 100644 index 000000000..7a751cb2e --- /dev/null +++ b/packages/types-live/src/bridge.ts @@ -0,0 +1,123 @@ +// NB this new "bridge" is a re-take of live-desktop bridge ideas +// with a focus to eventually make it shared across both projects. +// a WalletBridge is implemented on renderer side. +// this is an abstraction on top of underlying blockchains api (libcore / ethereumjs / ripple js / ...) +// that would directly be called from UI needs. +import { BigNumber } from "bignumber.js"; +import type { Observable } from "rxjs"; +import type { CryptoCurrency } from "@ledgerhq/types-cryptoassets"; +import type { AccountLike, Account, AccountRaw } from "./account"; +import type { + TransactionStatus, + SignOperationEvent, + SignedOperation, +} from "./transaction"; +import type { Operation } from "./operation"; +import type { DerivationMode } from "./derivation"; +import type { SyncConfig } from "./pagination"; + +export type ScanAccountEvent = { + type: "discovered"; + account: Account; +}; +// more events will come in the future +export type ScanAccountEventRaw = { + type: "discovered"; + account: AccountRaw; +}; +// unique identifier of a device. it will depends on the underlying implementation. +export type DeviceId = string; +export type PreloadStrategy = Partial<{ + preloadMaxAge: number; +}>; + +export type BroadcastArg0 = { + account: Account; + signedOperation: SignedOperation; +}; +export type SignOperationArg0 = { + account: Account; + transaction: T; + deviceId: DeviceId; +}; +export type SignOperationFnSignature = ( + arg0: SignOperationArg0 +) => Observable; +export type BroadcastFnSignature = (arg0: BroadcastArg0) => Promise; +// Abstraction related to a currency +export interface CurrencyBridge { + // Preload data required for the bridges to work. (e.g. tokens, delegators,...) + // Assume to call it at every load time but as lazy as possible (if user have such account already AND/OR if user is about to scanAccounts) + // returned value is a serializable object + // fail if data was not able to load. + preload(currency: CryptoCurrency): Promise>; + // reinject the preloaded data (typically if it was cached) + // method need to treat the data object as unsafe and validate all fields / be backward compatible. + hydrate(data: unknown, currency: CryptoCurrency): void; + // Scan all available accounts with a device + scanAccounts(arg0: { + currency: CryptoCurrency; + deviceId: DeviceId; + scheme?: DerivationMode | null | undefined; + syncConfig: SyncConfig; + preferredNewAccountScheme?: DerivationMode; + }): Observable; + getPreloadStrategy?: (currency: CryptoCurrency) => PreloadStrategy; +} +// Abstraction related to an account +export interface AccountBridge { + // synchronizes an account continuously to update with latest blochchains state. + // The function emits updater functions each time there are data changes (e.g. blockchains updates) + // an update function is just a Account => Account that perform the changes (to avoid race condition issues) + // initialAccount parameter is used to point which account is the synchronization on, but it should not be used in the emitted values. + // the sync can be stopped at any time using Observable's subscription.unsubscribe() + sync( + initialAccount: Account, + syncConfig: SyncConfig + ): Observable<(arg0: Account) => Account>; + receive( + account: Account, + arg1: { + verify?: boolean; + deviceId: string; + subAccountId?: string; + freshAddressIndex?: number; + } + ): Observable<{ + address: string; + path: string; + }>; + // a Transaction object is created on UI side as a black box to put all temporary information to build the transaction at the end. + // There are a bunch of edit and get functions to edit and extract information out ot this black box. + // it needs to be a serializable JS object + createTransaction(account: Account): T; + updateTransaction(t: T, patch: Partial): T; + // prepare the remaining missing part of a transaction typically from network (e.g. fees) + // and fulfill it in a new transaction object that is returned (async) + // It can fails if the the network is down. + prepareTransaction(account: Account, transaction: T): Promise; + // calculate derived state of the Transaction, useful to display summary / errors / warnings. tells if the transaction is ready. + getTransactionStatus( + account: Account, + transaction: T + ): Promise; + // heuristic that provides the estimated max amount that can be set to a send. + // this is usually the balance minus the fees, but it really depends between coins (reserve, burn, frozen part of the balance,...). + // it is a heuristic in that this is not necessarily correct and it can be +-delta (so the info can exceed the spendable or leave some dust). + // it's used as informative UI and also used for "dry run" approaches, but it shouldn't be used to determine the final SEND MAX amount. + // it returns an amount in the account unit + // if a transaction is provided, it can be used to precise the information + // if it not provided, you can assume to take the worst-case scenario (like sending all UTXOs to a legacy address has higher fees resulting in a lower max spendable) + estimateMaxSpendable(arg0: { + account: AccountLike; + parentAccount?: Account | null | undefined; + transaction?: T | null | undefined; + }): Promise; + // finalizing a transaction by signing it with the ledger device + // This results of a "signed" event with a signedOperation + // than can be locally saved and later broadcasted + signOperation: SignOperationFnSignature; + // broadcasting a signed transaction to network + // returns an optimistic Operation that this transaction is likely to create in the future + broadcast: BroadcastFnSignature; +} diff --git a/packages/types-live/src/derivation.ts b/packages/types-live/src/derivation.ts new file mode 100644 index 000000000..cbb70274e --- /dev/null +++ b/packages/types-live/src/derivation.ts @@ -0,0 +1,4 @@ +/** + * DerivationMode is a string identifier of a specific derivation scheme in a list defined in live-common derivation.ts + */ +export type DerivationMode = string; diff --git a/packages/types-live/src/index.ts b/packages/types-live/src/index.ts new file mode 100644 index 000000000..35d5ebeaf --- /dev/null +++ b/packages/types-live/src/index.ts @@ -0,0 +1,8 @@ +export * from "./derivation"; +export * from "./account"; +export * from "./operation"; +export * from "./portfolio"; +export * from "./transaction"; +export * from "./bridge"; +export * from "./pagination"; +export * from "./nft"; diff --git a/packages/types-live/src/nft.ts b/packages/types-live/src/nft.ts new file mode 100644 index 000000000..c782ffacc --- /dev/null +++ b/packages/types-live/src/nft.ts @@ -0,0 +1,38 @@ +import type BigNumber from "bignumber.js"; + +export type NFTStandards = "ERC721" | "ERC1155"; + +export type NFT = { + // id crafted by live + id: string; + // id on chain + tokenId: string; + amount: BigNumber; + collection: { + // contract address. Careful 1 contract address != 1 collection as some collections are off-chain + // So 1 contract address from OpenSea for example can reprensent an infinity of collections + contract: string; + // Carefull to non spec compliant NFTs (cryptopunks, cryptokitties, ethrock, and others?) + standard: NFTStandards | string; + }; +}; + +export type NFTRaw = Omit & { + amount: string; +}; + +export type NFTMetadataLinksProviders = "opensea" | "rarible" | "etherscan"; + +export type NFTMetadataResponse = { + status: 200 | 404 | 500; + result?: { + contract: string; + tokenId: string; + tokenName: string | null; + nftName: string | null; + media: string | null; + description: string | null; + properties: Array>; + links: Record; + } | null; +}; diff --git a/packages/types-live/src/operation.ts b/packages/types-live/src/operation.ts new file mode 100644 index 000000000..8c2e77856 --- /dev/null +++ b/packages/types-live/src/operation.ts @@ -0,0 +1,119 @@ +import type { BigNumber } from "bignumber.js"; +import { NFTStandards } from "./nft"; + +export type OperationType = + | "IN" + | "OUT" + | "NONE" + | "CREATE" + | "REVEAL" + // COSMOS + | "DELEGATE" + | "UNDELEGATE" + | "REDELEGATE" + | "REWARD" + // TRON + | "FEES" + | "FREEZE" + | "UNFREEZE" + // POLKADOT + | "VOTE" + | "REWARD_PAYOUT" + | "BOND" + | "UNBOND" + | "WITHDRAW_UNBONDED" + | "SET_CONTROLLER" + | "SLASH" + | "NOMINATE" + | "CHILL" + // COMPOUND TYPE OPERATIONS + | "SUPPLY" + | "REDEEM" + | "APPROVE" + // ALGORAND + | "OPT_IN" + | "OPT_OUT" + // NFT + | "NFT_IN" + | "NFT_OUT"; +export type Operation = { + // unique identifier (usually hash) + id: string; + // transaction hash + hash: string; + // the direction of the operation + // IN when funds was received (means the related account is in the recipients) + // OUT when funds was sent (means the related account is in the senders) + // NONE means this is not an operation related to the account but exists because there is likely an internal transaction + type: OperationType; + // this is the atomic value of the operation. it is always positive (later will be a BigInt) + // in "OUT" case, it includes the fees. in "IN" case, it excludes them. + value: BigNumber; + // fee of the transaction (in satoshi value) + fee: BigNumber; + // senders & recipients addresses + senders: string[]; + recipients: string[]; + // if block* are null, the operation is not yet on the blockchain + // the height of the block on the blockchain (number) + blockHeight: number | null | undefined; + // the hash of the block the operation is in + blockHash: string | null | undefined; + // if available, this is the sequence number of the transaction in blockchains (aka "nonce" in Ethereum) + transactionSequenceNumber?: number; + // the account id. available for convenient reason + accountId: string; + // --------------------------------------------- properties related to NFTs + // the specification used for the transaction's event + standard?: NFTStandards | string; + // address of an account/contract that is approved to make the transfer + operator?: string; + // address of the contract/collection containing an NFT (tokenId) + contract?: string; + // Id of an NFT inside its collection/contract + tokenId?: string; + // --------------------------------------------- specific operation raw fields + // transaction date + date: Date; + // Extra crypto specific fields + extra: Record; + // Has the transaction actually failed? (some blockchain like ethereum will have failed tx appearing) + hasFailed?: boolean; + // in context of accounts that can have tokens, an operation can contains itself operations + // these are not in raw at all because they are meant to be rebuilt from the references + subOperations?: Operation[]; + // in context of accounts that have internal transactions that belong to a parent transaction + // we have internal operations. Those are not included in the top level operations but can be presented to UI at that same level + internalOperations?: Operation[]; + // Operations related to ERC721 | ERC1155 tokens + nftOperations?: Operation[]; +}; +export type OperationRaw = { + id: string; + hash: string; + type: OperationType; + value: string; + fee: string; + senders: string[]; + recipients: string[]; + blockHeight: number | null | undefined; + blockHash: string | null | undefined; + transactionSequenceNumber?: number; + accountId: string; + hasFailed?: boolean; + // --------------------------------------------- properties related to NFTs + standard?: NFTStandards | string; + operator?: string; + contract?: string; + tokenId?: string; + // --------------------------------------------- specific operation raw fields + date: string; + extra: Record; + // would be a serializable version of the extra + subOperations?: OperationRaw[]; + // in context of accounts that have internal transactions that belong to a parent transaction + // we have internal operations. Those are not included in the top level operations but can be presented to UI at that same level + internalOperations?: OperationRaw[]; + // Operations related to ERC721 | ERC1155 tokens + nftOperations?: OperationRaw[]; +}; diff --git a/packages/types-live/src/pagination.ts b/packages/types-live/src/pagination.ts new file mode 100644 index 000000000..ffc17b3dd --- /dev/null +++ b/packages/types-live/src/pagination.ts @@ -0,0 +1,19 @@ +// A pagination config holds the user's pagination state +// this is a state that usually should leave during the app lifecycle, but is not persisted +// it drives the number of operations to poll in accounts +// when a user paginate more, the number should accordingly be incremented +// The UI should manage scrolling ahead of time (e.g. if 30 ops is displayed and UI have pages of 20 ops, the UI can already request to poll 70 ops so it have 2 pages in advance) +// The UI must always do max() to keep the increasing the counter and not going back to lower value: that optim the sync to not recompute things too much +export type PaginationConfig = { + // operations to pull for each account + operationsPerAccountId?: Record; + // if define and there is no specific account in operationsPerAccountId, + // this will be the operations count used + operations?: number; +}; +export type SyncConfig = { + paginationConfig: PaginationConfig; + // allows to disable the synchronization part – typically to only paginate more + withoutSynchronize?: boolean; + blacklistedTokenIds?: string[]; +}; diff --git a/packages/types-live/src/portfolio.ts b/packages/types-live/src/portfolio.ts new file mode 100644 index 000000000..237dcb7ef --- /dev/null +++ b/packages/types-live/src/portfolio.ts @@ -0,0 +1,77 @@ +import type { BigNumber } from "bignumber.js"; +import type { AccountLike, AccountLikeArray } from "./account"; +import type { + CryptoCurrency, + TokenCurrency, +} from "@ledgerhq/types-cryptoassets"; + +export type BalanceHistoryData = { + date: Date; + value: BigNumber; +}; +export type BalanceHistory = BalanceHistoryData[]; +export type BalanceHistoryRaw = Array<[string, string]>; +export type BalanceHistoryWithCountervalue = Array<{ + date: Date; + value: BigNumber; + countervalue: BigNumber; +}>; +export type ValueChange = { + percentage: BigNumber | null | undefined; + // value from 0 to 1. not defined if not meaningful + value: BigNumber; // delta of change +}; +export type AccountPortfolio = { + history: BalanceHistoryWithCountervalue; + countervalueAvailable: boolean; + countervalueReceiveSum: BigNumber; + countervalueSendSum: BigNumber; + cryptoChange: ValueChange; + // how much the account changes. value is in the account currency + countervalueChange: ValueChange; // calculates the ROI. value in the countervalue unit. +}; +export type CurrencyPortfolio = { + history: BalanceHistoryWithCountervalue; + countervalueAvailable: boolean; + histories: BalanceHistoryWithCountervalue[]; + accounts: AccountLikeArray; + cryptoChange: ValueChange; + // how much the account changes. value is in the account currency + countervalueChange: ValueChange; // calculates the ROI. value in the countervalue unit. +}; +export type Portfolio = { + balanceHistory: BalanceHistory; + balanceAvailable: boolean; + availableAccounts: AccountLike[]; + unavailableCurrencies: (CryptoCurrency | TokenCurrency)[]; + accounts: AccountLike[]; + range: PortfolioRange; + histories: BalanceHistoryWithCountervalue[]; + countervalueReceiveSum: BigNumber; + countervalueSendSum: BigNumber; + countervalueChange: ValueChange; // calculates the ROI. value in the countervalue unit. +}; +export type PortfolioRangeConfig = { + count: number; + granularityId: "HOUR" | "DAY" | "WEEK"; + // only supported here atm + startOf: (arg0: Date) => Date; + increment: number; // FIXME it should be a Date=>Date +}; +export type PortfolioRange = "year" | "month" | "week" | "day"; +export type AssetsDistribution = { + // false if no distribution can be done (sum is zero) + isAvailable: boolean; + // a sorted list of assets with data + list: Array<{ + currency: CryptoCurrency | TokenCurrency; + distribution: number; + // % of the total (normalized in 0-1) + amount: BigNumber; + countervalue: BigNumber; // countervalue of the amount that was calculated based of the rate provided + }>; + // number of accounts to show first (before the see all) + showFirst: number; + // sum of all countervalues + sum: BigNumber; +}; diff --git a/packages/types-live/src/swap.ts b/packages/types-live/src/swap.ts new file mode 100644 index 000000000..26621c9d3 --- /dev/null +++ b/packages/types-live/src/swap.ts @@ -0,0 +1,23 @@ +import { BigNumber } from "bignumber.js"; + +export type SwapOperation = { + provider: string; + swapId: string; + status: string; + receiverAccountId: string; + tokenId?: string; + operationId: string; + fromAmount: BigNumber; + toAmount: BigNumber; +}; + +export type SwapOperationRaw = { + provider: string; + swapId: string; + status: string; + receiverAccountId: string; + tokenId?: string; + operationId: string; + fromAmount: string; + toAmount: string; +}; diff --git a/packages/types-live/src/transaction.ts b/packages/types-live/src/transaction.ts new file mode 100644 index 000000000..dd04f322b --- /dev/null +++ b/packages/types-live/src/transaction.ts @@ -0,0 +1,144 @@ +import type { BigNumber } from "bignumber.js"; +import type { Operation, OperationRaw } from "./operation"; +import type { Unit } from "@ledgerhq/types-cryptoassets"; + +export type BitcoinInput = { + address: string | null | undefined; + value: BigNumber | null | undefined; + previousTxHash: string | null | undefined; + previousOutputIndex: number; +}; +export type BitcoinInputRaw = [ + string | null | undefined, + string | null | undefined, + string | null | undefined, + number +]; +export type BitcoinOutput = { + hash: string; + outputIndex: number; + blockHeight: number | null | undefined; + address: string | null | undefined; + path: string | null | undefined; // DEPRECATED - used only by legacy libcore implementation + value: BigNumber; + rbf: boolean; + isChange: boolean; +}; +export type BitcoinOutputRaw = [ + string, + number, + number | null | undefined, + string | null | undefined, + string | null | undefined, + string, + number, // rbf 0/1 for compression + number +]; + +export type SignedOperation = { + // prepared version of Operation before it's even broadcasted + // .id/.hash is potentially not settled yet + operation: Operation; + // usually the device signature hex OR anything that is needed to broadcast (can be an inline JSON) + signature: string; + // sometimes a coin needs the raw object (it must be serializable) + signatureRaw?: Record; + // date calculated as expiring + expirationDate: Date | null | undefined; +}; +export type SignedOperationRaw = { + operation: OperationRaw; + signature: string; + signatureRaw?: Record; + expirationDate: string | null | undefined; +}; +export type SignOperationEvent = // Used when lot of exchange is needed with the device to visually express a progress + // It can be used before and/or after the signature + // only used if it can takes >1s to show a visual progress to user (typically UTXO streaming) + | { + type: "device-streaming"; + progress: number; + index: number; + total: number; + } // optional + // REQUIRED Indicates that a signature is now appearing and awaited on the device to confirm + | { + type: "device-signature-requested"; + } // REQUIRED Indicates user have confirmed the transaction + | { + type: "device-signature-granted"; + } // REQUIRED payload of the resulting signed operation + | { + type: "signed"; + signedOperation: SignedOperation; + }; +export type SignOperationEventRaw = + | { + type: "device-streaming"; + progress: number; + index: number; + total: number; + } + | { + type: "device-signature-requested"; + } + | { + type: "device-signature-granted"; + } + | { + type: "signed"; + signedOperation: SignedOperationRaw; + }; +// Transaction is a generic object that holds all state for all transactions +// there are generic fields and coin specific fields. That's why almost all fields are optionals +export type TransactionCommon = { + amount: BigNumber; + recipient: string; + useAllAmount?: boolean; + subAccountId?: string | null | undefined; + feesStrategy?: "slow" | "medium" | "fast" | "custom" | null; +}; +export type TransactionCommonRaw = { + amount: string; + recipient: string; + useAllAmount?: boolean; + subAccountId?: string | null | undefined; + feesStrategy?: "slow" | "medium" | "fast" | "custom" | null; +}; +// User can have 3 differents choice for their fee +// Most of the time mid is low * 1.25 and high is low * 1.5 +// They are some exception as eth that got his own meter +export type FeeStrategy = { + amount: BigNumber; + displayedAmount?: BigNumber; + label: string; + unit?: Unit; +}; +// TransactionStatus is a view of Transaction with general info to be used on the UI and status info. +export type TransactionStatus = { + // potential error for each (user) field of the transaction + errors: Record; + // potential warning for each (user) field for a transaction + warnings: Record; + // estimated total fees the tx is going to cost. (in the mainAccount currency) + estimatedFees: BigNumber; + // actual amount that the recipient will receive (in account currency) + amount: BigNumber; + // total amount that the sender will spend (in account currency) + totalSpent: BigNumber; + // should the recipient be non editable + recipientIsReadOnly?: boolean; + txInputs?: BitcoinInput[]; + txOutputs?: BitcoinOutput[]; +}; +export type TransactionStatusRaw = { + errors: Record; + warnings: Record; + estimatedFees: string; + amount: string; + totalSpent: string; + useAllAmount?: boolean; + recipientIsReadOnly?: boolean; + txInputs?: BitcoinInputRaw[]; + txOutputs?: BitcoinOutputRaw[]; +}; diff --git a/packages/types-live/tsconfig.json b/packages/types-live/tsconfig.json new file mode 100644 index 000000000..0cf4676de --- /dev/null +++ b/packages/types-live/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "lib" + }, + "include": ["src/**/*"] +} diff --git a/yarn.lock b/yarn.lock index bb7fc7d71..686c4d2a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2711,7 +2711,7 @@ before-after-hook@^2.0.0: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A== -bignumber.js@^9.0.2: +bignumber.js@9, bignumber.js@^9.0.2: version "9.0.2" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.2.tgz#71c6c6bed38de64e24a65ebe16cfcf23ae693673" integrity sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==