UNPKG

@vechain/sdk-network

Version:

This module serves as the standard interface connecting decentralized applications (dApps) and users to the VeChainThor blockchain

405 lines (357 loc) 12.7 kB
import { type Revision, type TransactionClause } from '@vechain/sdk-core'; import type { TypedDataDomain as viemTypedDataDomain, TypedDataParameter as viemTypedDataParameter } from 'viem'; import { type HardhatVeChainProvider, type VeChainProvider } from '../../provider'; /** * Available types for the VeChainProvider's * * @NOTE: We use our supported providers instead of ethers providers. * If you create a new provider, you need to add it here. */ type AvailableVeChainProviders = VeChainProvider | HardhatVeChainProvider; /** * EIP-712 types in case we change the provider (viem as of now) */ type TypedDataDomain = Omit<viemTypedDataDomain, 'chainId'> & { chainId?: number | bigint | string; }; type TypedDataParameter = viemTypedDataParameter; /** * Type for transaction input * * @note Types of the properties can differ WRT ethers.TransactionRequest */ interface TransactionRequestInput { /** * The target of the transaction. */ to?: null | string; /** * The sender of the transaction. */ from?: null | string; /** * Nonce value for various purposes. * Basic is to prevent replay attack by make transaction unique. * Every transaction with same chainTag, blockRef, ... must have different nonce. */ nonce?: string | number; /** * Transaction gas. */ gas?: string | number; /** * The maximum amount of gas to allow this transaction to consume. */ gasLimit?: string; /** * The gas price to use for legacy transactions or transactions on * legacy networks. * * Most of the time the ``max*FeePerGas`` is preferred. */ gasPrice?: string; /** * Coefficient used to calculate the gas price for the transaction. * Value must be between 0 and 255. */ gasPriceCoef?: number; /** * The transaction data. */ data?: string; /** * The transaction value (in wei). */ value?: string | number; /** * When using ``call`` or ``estimateGas``, this allows a specific * block to be queried. Many backends do not support this and when * unsupported errors are silently squelched and ``"latest"`` is used. */ blockTag?: string; /** * Add clauses to ethers.TransactionRequest */ clauses?: TransactionClause[]; /** * The ID of the transaction that this transaction depends on. */ dependsOn?: string; /** * The expiration time of the transaction. * The transaction will expire after the number of blocks specified by this value. */ expiration?: number; /** * 8 bytes prefix of some block's ID */ blockRef?: string; /** * Last byte of genesis block ID */ chainTag?: number; /** * A reserved field intended for features use. * * In standard EVM transactions, this reserved field typically is not present. * However, it's been designed to cater to VIP-191, which deals with fee delegation. * * If the `features` within the `reserved` field is set as `1111...111`, it indicates that the transaction has been delegated. * The method to check if the transaction is delegated is: * * ```typescript * reserved.features & 1 === 1 * ``` * * @example * * 1. * ```typescript * feature = 111101; * isDelegated = (111101 & 111111) === 111101; // false (not delegated) * ``` * * 2. * ```typescript * feature = 111111; * isDelegated = (111111 & 111111) === 111111; // true (delegated) * ``` * * @remarks * For more information on the subject, refer to {@link https://github.com/vechain/VIPs/blob/master/vips/VIP-191.md | VIP-191}. */ reserved?: { /** * Tx feature bits */ features?: number; /** * Unused */ unused?: Uint8Array[]; }; /** * The VeChainThor blockchain allows for transaction-level proof of work (PoW) and converts the proved work into extra gas price that will be used by * the system to generate more reward to the block generator, the Authority Masternode, that validates the transaction. * In other words, users can utilize their local computational power to make their transactions more likely to be included in a new block. * * @link [VeChainThor Proof of Work](https://docs.vechain.org/core-concepts/transactions/transaction-calculation#proof-of-work) */ provedWork?: string; /** * The address that pays for the gas fee of the transaction simulation. * If different from the caller, then a delegated transaction is simulated. */ gasPayer?: string; /** * The delegation URL to use to sponsor the transaction. */ delegationUrl?: string; /** * A comment describing the transaction request. */ comment?: string; // START: NOT SUPPORTED FIELDS in VeChain BUT added to take compatibility with ethers /** * The chain ID for the network this transaction is valid on. */ chainId?: string; /** * The [[link-eip-2930]] access list. Storage slots included in the access * list are //warmed// by preloading them, so their initial cost to * fetch is guaranteed, but then each additional access is cheaper. */ // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents accessList?: null | AccessListish; /** * A custom object, which can be passed along for network-specific * values. */ customData?: unknown; /** * The [[link-eip-1559]] maximum priority fee to pay per gas. */ maxPriorityFeePerGas?: string | number; /** * The [[link-eip-1559]] maximum total fee to pay per gas. The actual * value used is protocol enforced to be the block's base fee. */ maxFeePerGas?: string | number; /** * The transaction type. */ type?: null | number; /** * When using ``call``, this enables CCIP-read, which permits the * provider to be redirected to web-based content during execution, * which is then further validated by the contract. * * There are potential security implications allowing CCIP-read, as * it could be used to expose the IP address or user activity during * the fetch to unexpected parties. */ enableCcipRead?: boolean; // END: NOT SUPPORTED FIELDS in VeChain BUT added to take compatibility with ethers } /** * Options for signing typed data * * @NOTE: To enhance compatibility with extension and mobile and to allow account switching when signing typed data, we define this interface. */ interface SignTypedDataOptions { signer?: string; } /** * A signer for VeChain, adding specific methods for VeChain to the ethers signer * * @NOTE: Su support completely our providers (that already support ethers provider format) * We use our supported providers instead of ethers providers */ interface VeChainSigner { /** * The provider attached to this Signer (if any). */ provider?: AvailableVeChainProviders; /** * Returns a new instance of this Signer connected to //provider// or detached * from any Provider if undefined. * * @param provider - The provider to connect to * @returns a new instance of this Signer connected to //provider// or detached */ connect: (provider: AvailableVeChainProviders) => this; /** * Get the address of the Signer. * * @returns the address of the signer */ getAddress: () => Promise<string>; /** * Gets the next nonce required for this Signer to send a transaction. * * @param blockTag - The blocktag to base the transaction count on, keep in mind * many nodes do not honour this value and silently ignore it [default: ``"latest"``] * * @NOTE: This method generates a random number as nonce. It is because the nonce in VeChain is a 6-byte number. */ getNonce: (blockTag?: string) => Promise<string>; /** * Prepares a {@link TransactionRequestInput} for calling: * - resolves ``to`` and ``from`` addresses * - if ``from`` is specified, check that it matches this Signer * * @note: Here the base support of multi-clause transaction is added. * So, if clauses are provided in the transaction, it will be used as it is. * Otherwise, standard transaction will be prepared. * * @param transactionToPopulate - The call to prepare * @returns the prepared call transaction */ populateCall: ( transactionToPopulate: TransactionRequestInput ) => Promise<TransactionRequestInput>; /** * Prepares a {@link TransactionRequestInput} for sending to the network by * populating any missing properties: * - resolves ``to`` and ``from`` addresses * - if ``from`` is specified , check that it matches this Signer * - populates ``nonce`` via ``signer.getNonce("pending")`` * - populates gas parameters via ``signer.estimateGas(tx)`` * - ... and other necessary properties * * @param transactionToPopulate - The call to prepare * @returns the prepared transaction */ populateTransaction: ( transactionToPopulate: TransactionRequestInput ) => Promise<TransactionBody>; /** * Estimates the required gas required to execute //tx// on the Blockchain. This * will be the expected amount a transaction will require * to successfully run all the necessary computations and store the needed state * that the transaction intends. * * @param transactionToEstimate - The transaction to estimate gas for * @returns the total estimated gas required */ estimateGas: ( transactionToEstimate: TransactionRequestInput ) => Promise<number>; /** * Evaluates the //tx// by running it against the current Blockchain state. This * cannot change state and has no cost, as it is effectively simulating * execution. * * This can be used to have the Blockchain perform computations based on its state * (e.g. running a Contract's getters) or to simulate the effect of a transaction * before actually performing an operation. * * @param transactionToEvaluate - The transaction to evaluate * @param revision - The revision to evaluate the transaction against * @returns the result of the evaluation */ call: ( transactionToEvaluate: TransactionRequestInput, revision?: Revision ) => Promise<string>; /** * Signs %%transactionToSign%%, returning the fully signed transaction. This does not * populate any additional properties within the transaction. * * @param transactionToSign - The transaction to sign * @returns The fully signed transaction */ signTransaction: ( transactionToSign: TransactionRequestInput ) => Promise<string>; /** * Sends %%transactionToSend%% to the Network. The ``signer.populateTransaction(transactionToSend)`` * is called first to ensure all necessary properties for the * transaction to be valid have been populated first. * * @param transactionToSend - The transaction to send * @returns The transaction response */ sendTransaction: ( transactionToSend: TransactionRequestInput ) => Promise<string>; /** * Signs an [[link-eip-191]] prefixed a personal message. * * If the %%message%% is a string, it is signed as UTF-8 encoded bytes. It is **not** * interpreted as a [[BytesLike]]; so the string ``"0x1234"`` is signed as six * characters, **not** two bytes. * * To sign that example as two bytes, the Uint8Array should be used * (i.e. ``new Uint8Array([ 0x12, 0x34 ])``). */ signMessage: (message: string | Uint8Array) => Promise<string>; /** * Signs the [[link-eip-712]] typed data. */ signTypedData: ( domain: TypedDataDomain, types: Record<string, TypedDataParameter[]>, message: Record<string, unknown>, primaryType?: string, options?: SignTypedDataOptions ) => Promise<string>; /** * Resolves an VNS Name to an address. */ resolveName: (vnsName: string) => Promise<null | string>; } export { type AvailableVeChainProviders, type TypedDataDomain, type TypedDataParameter, type SignTypedDataOptions, type TransactionRequestInput, type VeChainSigner };