UNPKG

raiden-ts

Version:

Raiden Light Client Typescript/Javascript SDK

618 lines (617 loc) 29 kB
/// <reference types="pouchdb-core" /> /// <reference types="lodash" /> import './polyfills'; import type { Signer } from '@ethersproject/abstract-signer'; import type { BigNumberish } from '@ethersproject/bignumber'; import { BigNumber } from '@ethersproject/bignumber'; import type { Network } from '@ethersproject/networks'; import type { ExternalProvider } from '@ethersproject/providers'; import { JsonRpcProvider } from '@ethersproject/providers'; import logging from 'loglevel'; import type { Observable } from 'rxjs'; import type { RaidenAction, RaidenEvent, raidenSynced } from './actions'; import type { RaidenChannels } from './channels/state'; import type { RaidenConfig } from './config'; import { PartialRaidenConfig } from './config'; import type { Paths, RaidenPFS, SuggestedPartner } from './services/types'; import { InputPaths, PFS } from './services/types'; import type { RaidenState } from './state'; import type { RaidenTransfer } from './transfers/state'; import type { ContractsInfo, OnChange, RaidenEpicDeps } from './types'; import { EventTypes } from './types'; import type { Decodable } from './utils/types'; import { Address, Hash, UInt } from './utils/types'; export declare class Raiden { private readonly deps; private readonly epic; /** * action$ exposes the internal events pipeline. It's intended for debugging, and its interface * must not be relied on, as its actions interfaces and structures can change without warning. */ readonly action$: Observable<RaidenAction>; /** * state$ is exposed only so user can listen to state changes and persist them somewhere else. * Format/content of the emitted objects are subject to changes and not part of the public API */ readonly state$: Observable<RaidenState>; /** * channels$ is public interface, exposing a view of the currently known channels * Its format is expected to be kept backwards-compatible, and may be relied on */ readonly channels$: Observable<RaidenChannels>; /** * A subset ot RaidenActions exposed as public events. * The interface of the objects emitted by this Observable are expected not to change internally, * but more/new events may be added over time. */ readonly events$: Observable<RaidenEvent>; /** * Observable of completed and pending transfers * Every time a transfer state is updated, it's emitted here. 'key' property is unique and * may be used as identifier to know which transfer got updated. */ readonly transfers$: Observable<RaidenTransfer>; /** RaidenConfig object */ config: RaidenConfig; /** RaidenConfig observable (for reactive use) */ config$: Observable<RaidenConfig>; /** Observable of latest average (10) block times */ blockTime$: Observable<number>; /** When started, is set to a promise which resolves when node finishes syncing */ synced: Promise<raidenSynced['payload'] | undefined>; /** * Get constant token details from token contract, caches it. * Rejects only if 'token' contract doesn't define totalSupply and decimals methods. * name and symbol may be undefined, as they aren't actually part of ERC20 standard, although * very common and defined on most token contracts. * * @param token - address to fetch info from * @returns token info */ getTokenInfo: (token: string) => Promise<{ totalSupply: BigNumber; decimals: number; name?: string | undefined; symbol?: string | undefined; }>; private readonly store; /** Expose ether's Provider.resolveName for ENS support */ readonly resolveName: (name: string) => Promise<Address>; /** The address of the token that is used to pay the services (SVT/RDN). */ userDepositTokenAddress: () => Promise<Address>; private epicMiddleware?; /** * Constructs a Raiden instance from state machine parameters * * It expects ready Redux and Epics params, with some async members already resolved and set in * place, therefore this constructor is expected to be used only for tests and advancecd usage * where finer control is needed to tweak how some of these members are initialized; * Most users should usually prefer the [[create]] async factory, which already takes care of * these async initialization steps and accepts more common parameters. * * @param state - Validated and decoded initial/rehydrated RaidenState * @param deps - Constructed epics dependencies object, including signer, provider, fetched * network and contracts information. * @param epic - State machine root epic * @param reducer - State machine root reducer */ constructor(state: RaidenState, deps: RaidenEpicDeps, epic?: (action$: Observable<RaidenAction>, state$: Observable<RaidenState>, deps: RaidenEpicDeps) => Observable<RaidenAction>, reducer?: (state: RaidenState | undefined, action: RaidenAction) => RaidenState); /** * Async helper factory to make a Raiden instance from more common parameters. * * An async factory is needed so we can do the needed async requests to construct the required * parameters ahead of construction time, and avoid partial initialization then * * @param this - Raiden class or subclass * @param connection - A URL or provider to connect to, one of: * <ul> * <li>JsonRpcProvider instance,</li> * <li>a Metamask's web3.currentProvider object or,</li> * <li>a hostname or remote json-rpc connection string</li> * </ul> * @param account - An account to use as main account, one of: * <ul> * <li>Signer instance (e.g. Wallet) loaded with account/private key or</li> * <li>hex-encoded string address of a remote account in provider or</li> * <li>hex-encoded string local private key or</li> * <li>number index of a remote account loaded in provider * (e.g. 0 for Metamask's loaded account)</li> * </ul> * @param storage - diverse storage related parameters to load from and save to * @param storage.state - State uploaded by user; should be decodable by RaidenState; * it is auto-migrated * @param storage.adapter - PouchDB adapter; default to 'indexeddb' on browsers and 'leveldb' on * node. If you provide a custom one, ensure you call PouchDB.plugin on it. * @param storage.prefix - Database name prefix; use to set a directory to store leveldown db; * @param contractsOrUDCAddress - Contracts deployment info, or UserDeposit contract address * @param config - Raiden configuration * @param subkey - Whether to use a derived subkey or not * @param subkeyOriginUrl - URL of origin to generate a subkey for (defaults * to global context) * @returns Promise to Raiden SDK client instance */ static create<R extends typeof Raiden>(this: R, connection: JsonRpcProvider | ExternalProvider | string, account: Signer | string | number, storage?: { state?: any; adapter?: any; prefix?: string; }, contractsOrUDCAddress?: ContractsInfo | string, config?: Decodable<PartialRaidenConfig>, subkey?: true, subkeyOriginUrl?: string): Promise<InstanceType<R>>; /** * Starts redux/observables by subscribing to all epics and emitting initial state and action * * No event should be emitted before start is called */ start(): Promise<void>; /** * Gets the running state of the instance * * @returns undefined if not yet started, true if running, false if already stopped */ get started(): boolean | undefined; /** * Triggers all epics to be unsubscribed */ stop(): Promise<void>; /** * Instance's Logger, compatible with console's API * * @returns Logger object */ get log(): logging.Logger; /** * Get current RaidenState object. Can be serialized safely with [[encodeRaidenState]] * * @returns Current Raiden state */ get state(): RaidenState; /** * Current provider getter * * @returns ether's provider instance */ get provider(): JsonRpcProvider; /** * Get current account address (subkey's address, if subkey is being used) * * @returns Instance address */ get address(): Address; /** * Get main account address (if subkey is being used, undefined otherwise) * * @returns Main account address */ get mainAddress(): Address | undefined; /** * Get current network from provider * * @returns Network object containing blockchain's name & chainId */ get network(): Network; /** * Returns a promise to current block number, as seen in provider and state * * @returns Promise to current block number */ getBlockNumber(): Promise<number>; /** * Returns the currently used SDK version. * * @returns SDK version */ static get version(): string; /** * Returns the version of the used Smart Contracts. * * @returns Smart Contract version */ static get contractVersion(): string; /** * Returns the Smart Contracts addresses and deployment blocks * * @returns Smart Contracts info */ get contractsInfo(): ContractsInfo; /** * Update Raiden Config with a partial (shallow) object * * @param config - Partial object containing keys and values to update in config */ updateConfig(config: PartialRaidenConfig): void; /** * Dumps database content for backup * * @yields Rows of objects */ dumpDatabase(): AsyncGenerator<import("./db/types").RaidenDatabaseMeta | import("lodash").Omit<PouchDB.Core.ExistingDocument<PouchDB.Core.AllDocsMeta>, "_rev">, void, undefined>; /** * Get ETH balance for given address or self * * @param address - Optional target address. If omitted, gets own balance * @returns BigNumber of ETH balance */ getBalance(address?: string): Promise<BigNumber>; /** * Get token balance and token decimals for given address or self * * @param token - Token address to fetch balance. Must be one of the monitored tokens. * @param address - Optional target address. If omitted, gets own balance * @returns BigNumber containing address's token balance */ getTokenBalance(token: string, address?: string): Promise<BigNumber>; /** * Returns a list of all token addresses registered as token networks in registry * * @param rescan - Whether to rescan events from scratch * @returns Promise to list of token addresses */ getTokenList(rescan?: boolean): Promise<Address[]>; /** * Scans initially and start monitoring a token for channels with us, returning its Tokennetwork * address * * Throws an exception if token isn't registered in current registry * * @param token - token address to monitor, must be registered in current token network registry * @returns Address of TokenNetwork contract */ monitorToken(token: string): Promise<Address>; /** * Open a channel on the tokenNetwork for given token address with partner * * If token isn't yet monitored, starts monitoring it * * @param token - Token address on currently configured token network registry * @param partner - Partner address * @param options - (optional) option parameter * @param options.deposit - Deposit to perform in parallel with channel opening * @param options.confirmConfirmation - Whether to wait `confirmationBlocks` after last * transaction confirmation; default=true if confirmationBlocks * @param onChange - Optional callback for status change notification * @returns txHash of channelOpen call, iff it succeeded */ openChannel(token: string, partner: string, options?: { deposit?: BigNumberish; confirmConfirmation?: boolean; }, onChange?: OnChange<EventTypes, { txHash: string; }>): Promise<Hash>; /** * Deposit tokens on channel between us and partner on tokenNetwork for token * * @param token - Token address on currently configured token network registry * @param partner - Partner address * @param amount - Number of tokens to deposit on channel * @param options - tx options * @param options.confirmConfirmation - Whether to wait `confirmationBlocks` after last * transaction confirmation; default=true if config.confirmationBlocks * @returns txHash of setTotalDeposit call, iff it succeeded */ depositChannel(token: string, partner: string, amount: BigNumberish, { confirmConfirmation, }?: { confirmConfirmation?: boolean; }): Promise<Hash>; /** * Close channel between us and partner on tokenNetwork for token * This method will fail if called on a channel not in 'opened' or 'closing' state. * When calling this method on an 'opened' channel, its state becomes 'closing', and from there * on, no payments can be performed on the channel. If for any reason the closeChannel * transaction fails, channel's state stays as 'closing', and this method can be called again * to retry sending 'closeChannel' transaction. After it's successful, channel becomes 'closed', * and can be settled after 'settleTimeout' seconds (when it then becomes 'settleable'). * * @param token - Token address on currently configured token network registry * @param partner - Partner address * @returns txHash of closeChannel call, iff it succeeded */ closeChannel(token: string, partner: string): Promise<Hash>; /** * Settle channel between us and partner on tokenNetwork for token * This method will fail if called on a channel not in 'settleable' or 'settling' state. * Channel becomes 'settleable' settleTimeout seconds after closed (detected automatically * while Raiden Light Client is running or later on restart). When calling it, channel state * becomes 'settling'. If for any reason transaction fails, it'll stay on this state, and this * method can be called again to re-send a settleChannel transaction. * * @param token - Token address on currently configured token network registry * @param partner - Partner address * @returns txHash of settleChannel call, iff it succeeded */ settleChannel(token: string, partner: string): Promise<Hash>; /** * Returns object describing address's users availability on transport * After calling this method, any further presence update to valid transport peers of this * address will trigger a corresponding MatrixPresenceUpdateAction on events$ * * @param address - checksummed address to be monitored * @returns Promise to object describing availability and last event timestamp */ getAvailability(address: string): Promise<{ userId: string; available: boolean; ts: number; }>; /** * Get list of past and pending transfers * * @param filter - Filter options * @param filter.pending - true: only pending; false: only completed; undefined: all * @param filter.token - filter by token address * @param filter.partner - filter by partner address * @param filter.end - filter by initiator or target address * @param options - PouchDB.ChangesOptions object * @param options.offset - Offset to skip entries * @param options.limit - Limit number of entries * @param options.desc - Set to true to get newer transfers first * @returns promise to array of all transfers */ getTransfers(filter?: { pending?: boolean; token?: string; partner?: string; end?: string; }, options?: { offset?: number; limit?: number; desc?: boolean; }): Promise<RaidenTransfer[]>; /** * Send a Locked Transfer! * This will reject if LockedTransfer signature prompt is canceled/signature fails, or be * resolved to the transfer unique identifier (secrethash) otherwise, and transfer status can be * queried with this id on this.transfers$ observable, which will just have emitted the 'pending' * transfer. Any following transfer state change will be notified through this observable. * * @param token - Token address on currently configured token network registry * @param target - Target address * @param value - Amount to try to transfer * @param options - Optional parameters for transfer: * @param options.paymentId - payment identifier, a random one will be generated if missing * @param options.secret - Secret to register, a random one will be generated if missing * @param options.secrethash - Must match secret, if both provided, or else, secret must be * informed to target by other means, and reveal can't be performed * @param options.paths - Used to specify possible routes & fees instead of querying PFS. * Should receive a decodable super-set of the public RaidenPaths interface * @param options.pfs - Use this PFS instead of configured or automatically choosen ones. * Is ignored if paths were already provided. If neither are set and config.pfs is not * disabled (null), use it if set or if undefined (auto mode), fetches the best * PFS from ServiceRegistry and automatically fetch routes from it. * @param options.lockTimeout - Specify a lock timeout for transfer; * default is expiryFactor * revealTimeout * @param options.encryptSecret - Whether to force encrypting the secret or not, * if target supports it * @returns A promise to transfer's unique key (id) when it's accepted */ transfer(token: string, target: string, value: BigNumberish, options?: { paymentId?: BigNumberish; secret?: string; secrethash?: string; paths?: Decodable<InputPaths>; pfs?: RaidenPFS; lockTimeout?: number; encryptSecret?: boolean; }): Promise<string>; /** * Waits for the transfer identified by a secrethash to fail or complete * The returned promise will resolve with the final transfer state, or reject if anything fails * * @param transferKey - Transfer identifier as returned by [[transfer]] * @returns Promise to final RaidenTransfer */ waitTransfer(transferKey: string): Promise<RaidenTransfer>; /** * Request a path from PFS * * If a direct route is possible, it'll be returned. Else if PFS is set up, a request will be * performed and the cleaned/validated path results will be resolved. * Else, if no route can be found, promise is rejected with respective error. * * @param token - Token address on currently configured token network registry * @param target - Target address * @param value - Minimum capacity required on routes * @param options - Optional parameters * @param options.pfs - Use this PFS instead of configured or automatically choosen ones * @returns A promise to returned routes/paths result */ findRoutes(token: string, target: string, value: BigNumberish, options?: { pfs?: RaidenPFS; }): Promise<Paths>; /** * Checks if a direct transfer of token to target could be performed and returns it on a * single-element array of Paths * * @param token - Token address on currently configured token network registry * @param target - Target address * @param value - Minimum capacity required on route * @returns Promise to a [Raiden]Paths array containing the single, direct route, or undefined */ directRoute(token: string, target: string, value: BigNumberish): Promise<Paths | undefined>; /** * Returns a sorted array of info of available PFS * * It uses data polled from ServiceRegistry, which is available only when config.pfs is * undefined, instead of set or disabled (null), and will reject if not. * It can reject if the validated list is empty, meaning we can be out-of-sync (we're outdated or * they are) with PFSs deployment, or no PFS is available on this TokenNetwork/blockchain. * * @returns Promise to array of PFS, which is the interface which describes a PFS */ findPFS(): Promise<PFS[]>; /** * Mints the amount of tokens of the provided token address. * Throws an error, if * <ol> * <li>Executed on main net</li> * <li>`token` or `options.to` is not a valid address</li> * <li>Token could not be minted</li> * </ol> * * @param token - Address of the token to be minted * @param amount - Amount to be minted * @param options - tx options * @param options.to - Beneficiary, defaults to mainAddress or address * @returns transaction */ mint(token: string, amount: BigNumberish, { to }?: { to?: string; }): Promise<Hash>; /** * Registers and creates a new token network for the provided token address. * Throws an error, if * <ol> * <li>Executed on main net</li> * <li>`token` is not a valid address</li> * <li>Token is already registered</li> * <li>Token could not be registered</li> * </ol> * * @param token - Address of the token to be registered * @param channelParticipantDepositLimit - The deposit limit per channel participant * @param tokenNetworkDepositLimit - The deposit limit of the whole token network * @returns Address of new token network */ registerToken(token: string, channelParticipantDepositLimit?: BigNumberish, tokenNetworkDepositLimit?: BigNumberish): Promise<Address>; /** * Fetches balance of UserDeposit Contract for SDK's account minus cached spent IOUs * * @returns Promise to UDC remaining capacity */ getUDCCapacity(): Promise<BigNumber>; /** * Fetches total_deposit of UserDeposit Contract for SDK's account * * The usable part of the deposit should be fetched with [[getUDCCapacity]], but this function * is useful when trying to deposit based on the absolute value of totalDeposit. * * @returns Promise to UDC total deposit */ getUDCTotalDeposit(): Promise<BigNumber>; /** * Deposits the amount to the UserDeposit contract with the target/signer as a beneficiary. * The deposited amount can be used as a collateral in order to sign valid IOUs that will * be accepted by the Services. * * Throws an error, in the following cases: * <ol> * <li>The amount specified equals to zero</li> * <li>The target has an insufficient token balance</li> * <li>The "approve" transaction fails with an error</li> * <li>The "deposit" transaction fails with an error</li> * </ol> * * @param amount - The amount to deposit on behalf of the target/beneficiary. * @param onChange - callback providing notifications about state changes * @returns transaction hash */ depositToUDC(amount: BigNumberish, onChange?: OnChange<EventTypes, { txHash: string; }>): Promise<Hash>; /** * Transfer value ETH on-chain to address. * If subkey is being used, use main account by default, or subkey account if 'subkey' is true * Example: * // transfer 0.1 ETH from main account to subkey account, when subkey is used * await raiden.transferOnchainBalance(raiden.address, parseEther('0.1')); * // transfer entire balance from subkey account back to main account * await raiden.transferOnchainBalance(raiden.mainAddress, undefined, { subkey: true }); * * @param to - Recipient address * @param value - Amount of ETH (in Wei) to transfer. Use ethers/utils::parseEther if needed * Defaults to a very big number, which will cause all entire balance to be transfered * @param options - tx options * @param options.subkey - By default, if using subkey, main account is used to send transactions * Set this to true if one wants to force sending the transaction with the subkey * @param options.gasPrice - Set to force a specific gasPrice; used to calculate transferable * amount when transfering entire balance. If left unset, uses average network gasPrice * @returns transaction hash */ transferOnchainBalance(to: string, value?: BigNumberish, { subkey, gasPrice: price }?: { subkey?: boolean; gasPrice?: BigNumberish; }): Promise<Hash>; /** * Transfer value tokens on-chain to address. * If subkey is being used, use main account by default, or subkey account if 'subkey' is true * * @param token - Token address * @param to - Recipient address * @param value - Amount of tokens (in Wei) to transfer. Use ethers/utils::parseUnits if needed * Defaults to a very big number, which will cause all entire balance to be transfered * @param options - tx options * @param options.subkey - By default, if using subkey, main account is used to send transactions * Set this to true if one wants to force sending the transaction with the subkey * @returns transaction hash */ transferOnchainTokens(token: string, to: string, value?: BigNumberish, { subkey }?: { subkey?: boolean; }): Promise<Hash>; /** * Fetches our current UDC withdraw plan * * @returns Promise to object containing maximum 'amount' planned for withdraw and * 'withdrawableAfter' second at which withdraw will become available, * and 'ready' after it can be withdrawn with [[withdrawFromUDC]]; * resolves to undefined if there's no current plan */ getUDCWithdrawPlan(): Promise<{ amount: UInt<32>; withdrawableAfter: number; ready: boolean; } | undefined>; /** * Records a UDC withdraw plan for our UDC deposit, capped at whole balance. * * @param value - Maximum value which we may try to withdraw. * @returns Promise to hash of plan transaction, if it succeeds. */ planUDCWithdraw(value?: BigNumberish): Promise<Hash>; /** * Complete a planned UDC withdraw and get the deposit to account. * * Maximum 'value' is the one from current plan, attempting to withdraw a larger value will throw * an error, but a smaller value is valid. This method may only be called after plan is 'ready' * * @param value - Maximum value which we may try to withdraw. An error will be thrown if this * value is larger than [[getUDCCapacity]]+[[getUDCWithdrawPlan]].amount * @param options - options object * @param options.subkey - if true, force withdrawing to subkey instead of the main account as * beneficiary * @returns Promise to hash of plan transaction, if it succeeds. */ withdrawFromUDC(value?: BigNumberish, options?: { subkey?: boolean; }): Promise<Hash>; /** * Requests to withdraw from channel * * The requested amount defaults to the maximum withdrawable amount, which is exposed in * [[channels$]] observable as the [[RaidenChannel.ownWithdrawable]] member. * This involves requesting partner a signature which confirms they agree that we have the right * for this amount of tokens, then a transaction is sent on-chain to withdraw tokens to the * effective account. * If this process fails, the amount remains locked until it can be expired later (defaults to * config.expiryFactory * config.revealTimeout seconds). * * @param token - Token address on currently configured token network registry * @param partner - Partner address * @param amount - Amount of tokens (in wei) to withdraw, must be between 1 and ownWithdrawable * @returns Promise to the hash of the mined withdraw transaction */ withdrawChannel(token: string, partner: string, amount?: BigNumberish): Promise<Hash>; /** * Fetches an ordered list of suggested partners from provided, configured or first found PFS * * @param token - Token address to get partners for * @param options - Request options * @param options.pfs - PFS to use, instead of configured or automatic * @returns Ordered array of suggested partners, with address and scoring values according to PFS */ suggestPartners(token: string, options?: { pfs?: RaidenPFS; }): Promise<SuggestedPartner[]>; /** * Fetches contract's settleTimeout * * @returns settleTimeout constant value from contracts */ get settleTimeout(): number; } export default Raiden;