UNPKG

viem

Version:

TypeScript Interface for Ethereum

1,744 lines (1,658 loc) • 135 kB
import type { Address } from 'abitype' import * as Hex from 'ox/Hex' import { TokenId, TokenRole } from 'ox/tempo' import type { Account } from '../../accounts/types.js' import { parseAccount } from '../../accounts/utils/parseAccount.js' import { estimateContractGas } from '../../actions/public/estimateContractGas.js' import { multicall } from '../../actions/public/multicall.js' import type { ReadContractReturnType } from '../../actions/public/readContract.js' import { readContract } from '../../actions/public/readContract.js' import { type SimulateContractReturnType, simulateContract, } from '../../actions/public/simulateContract.js' import type { WatchContractEventParameters, WatchContractEventReturnType, } from '../../actions/public/watchContractEvent.js' import { watchContractEvent } from '../../actions/public/watchContractEvent.js' import * as internal_Token from '../../actions/token/internal.js' import { sendTransaction } from '../../actions/wallet/sendTransaction.js' import { type SendTransactionSyncParameters, sendTransactionSync, } from '../../actions/wallet/sendTransactionSync.js' import type { WriteContractReturnType } from '../../actions/wallet/writeContract.js' import { writeContract } from '../../actions/wallet/writeContract.js' import { writeContractSync } from '../../actions/wallet/writeContractSync.js' import type { Client } from '../../clients/createClient.js' import type { Transport } from '../../clients/transports/createTransport.js' import { AccountNotFoundError } from '../../errors/account.js' import type { BaseErrorType } from '../../errors/base.js' import type { Chain } from '../../types/chain.js' import type { ExtractAbiItem, GetEventArgs } from '../../types/contract.js' import type { Log, Log as viem_Log } from '../../types/log.js' import type { Compute, OneOf, UnionOmit } from '../../types/utils.js' import { encodeFunctionData } from '../../utils/abi/encodeFunctionData.js' import { parseEventLogs } from '../../utils/abi/parseEventLogs.js' import { formatUnits } from '../../utils/unit/formatUnits.js' import * as Abis from '../Abis.js' import * as Addresses from '../Addresses.js' import type { GetAccountParameter, ReadParameters, TokenParameter, TokenParameters, WriteParameters, } from '../internal/types.js' import { type CallParameters, defineCall, findDeclaredToken, pickWriteParameters, resolveCallParameters, resolveToken, resolveTokenWithDecimals, } from '../internal/utils.js' import type { TransactionReceipt } from '../Transaction.js' /** * Approves a spender to transfer TIP20 tokens on behalf of the caller. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * import { privateKeyToAccount } from 'viem/accounts' * * const client = createClient({ * account: privateKeyToAccount('0x...'), * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const result = await Actions.token.approve(client, { * spender: '0x...', * amount: 100n, * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The transaction hash. */ export async function approve< chain extends Chain | undefined, account extends Account | undefined, >( client: Client<Transport, chain, account>, parameters: approve.Parameters<chain, account>, ): Promise<approve.ReturnValue> { return approve.inner(writeContract, client, parameters) } export namespace approve { export type Args = { /** Amount of tokens to approve, in base units or formatted decimal form. */ amount: internal_Token.AmountInput /** Address of the spender. */ spender: Address } & TokenParameter export type Parameters< chain extends Chain | undefined = Chain | undefined, account extends Account | undefined = Account | undefined, > = WriteParameters<chain, account> & Args export type ReturnValue = WriteContractReturnType // TODO: exhaustive error type export type ErrorType = BaseErrorType /** @internal */ export async function inner< action extends typeof writeContract | typeof writeContractSync, chain extends Chain | undefined, account extends Account | undefined, >( action: action, client: Client<Transport, chain, account>, parameters: approve.Parameters<chain, account>, ): Promise<ReturnType<action>> { return (await action(client, { ...parameters, ...approve.call(client, parameters as never), } as never)) as never } /** * Defines a call to the `approve` function. * * Can be passed as a parameter to `estimateContractGas`, `simulateContract`, * `sendCalls`, `sendTransaction` (`calls`), or `multicall`. The token is * selected by `token`, which is either a TIP20 token id or a contract * `address`; `amount.decimals` is inferred from the client's declared * `tokens` when omitted. * * @param parameters - Client (optional), followed by the call arguments. * @returns The call. */ export function call<chain extends Chain | undefined>( ...parameters: CallParameters<Args, Client<Transport, chain>> ) { const [client, args] = resolveCallParameters(parameters) const { amount, spender, token } = args const { address, decimals } = resolveToken(client, { token }) return defineCall({ address, abi: Abis.tip20, functionName: 'approve', args: [spender, internal_Token.toBaseUnits(amount, decimals)], }) } /** * Estimates the gas required to approve a spender. `amount.decimals` is * inferred from the client's declared `tokens` when omitted. * * @param client - Client. * @param parameters - Parameters. * @returns The gas estimate. */ export async function estimateGas< chain extends Chain | undefined, account extends Account | undefined, >( client: Client<Transport, chain, account>, parameters: approve.Parameters<chain, account>, ): Promise<bigint> { return estimateContractGas(client, { ...pickWriteParameters(parameters as never), ...approve.call(client, parameters as never), } as never) } /** * Simulates an approval of a spender. `amount.decimals` is inferred from * the client's declared `tokens` when omitted. * * @param client - Client. * @param parameters - Parameters. * @returns The simulation result and write request. */ export async function simulate< chain extends Chain | undefined, account extends Account | undefined, >( client: Client<Transport, chain, account>, parameters: approve.Parameters<chain, account>, ): Promise<SimulateContractReturnType<typeof Abis.tip20, 'approve'>> { return simulateContract(client, { ...pickWriteParameters(parameters as never), ...approve.call(client, parameters as never), } as never) as never } /** * Extracts the `Approval` event from logs. * * @param logs - The logs. * @returns The `Approval` event. */ export function extractEvent(logs: Log[]) { const [log] = parseEventLogs({ abi: Abis.tip20, logs, eventName: 'Approval', }) if (!log) throw new Error('`Approval` event not found.') return log } } /** * Approves a spender to transfer TIP20 tokens on behalf of the caller. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * import { privateKeyToAccount } from 'viem/accounts' * * const client = createClient({ * account: privateKeyToAccount('0x...'), * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const result = await Actions.token.approveSync(client, { * spender: '0x...', * amount: 100n, * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The transaction receipt and event data. */ export async function approveSync< chain extends Chain | undefined, account extends Account | undefined, >( client: Client<Transport, chain, account>, parameters: approveSync.Parameters<chain, account>, ): Promise<approveSync.ReturnValue> { const { amount, token, throwOnReceiptRevert = true } = parameters const { decimals } = resolveToken(client, { token }) const resolved = internal_Token.resolveAmountDecimals(amount, decimals) const receipt = await approve.inner(writeContractSync, client, { ...parameters, throwOnReceiptRevert, } as never) const { args } = approve.extractEvent(receipt.logs) return { ...args, ...(resolved === undefined ? {} : { decimals: resolved, formatted: formatUnits(args.amount, resolved) }), receipt, } as never } export namespace approveSync { export type Args = approve.Args export type Parameters< chain extends Chain | undefined = Chain | undefined, account extends Account | undefined = Account | undefined, > = approve.Parameters<chain, account> export type ReturnValue = Compute< GetEventArgs< typeof Abis.tip20, 'Approval', { IndexedOnly: false Required: true } > & { /** Token decimals used to derive `formatted`, if known. */ decimals?: number | undefined /** Approved amount formatted with the token's `decimals`, if known. */ formatted?: string | undefined /** Transaction receipt. */ receipt: TransactionReceipt } > // TODO: exhaustive error type export type ErrorType = BaseErrorType } /** * Burns TIP20 tokens from a blocked address. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * import { privateKeyToAccount } from 'viem/accounts' * * const client = createClient({ * account: privateKeyToAccount('0x...'), * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const result = await Actions.token.burnBlocked(client, { * from: '0x...', * amount: 100n, * token: '0x...', * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The transaction hash. */ export async function burnBlocked< chain extends Chain | undefined, account extends Account | undefined, >( client: Client<Transport, chain, account>, parameters: burnBlocked.Parameters<chain, account>, ): Promise<burnBlocked.ReturnValue> { return burnBlocked.inner(writeContract, client, parameters) } export namespace burnBlocked { export type Args = { /** Amount of tokens to burn, in base units or formatted decimal form. */ amount: internal_Token.AmountInput /** Address to burn tokens from. */ from: Address } & TokenParameter export type Parameters< chain extends Chain | undefined = Chain | undefined, account extends Account | undefined = Account | undefined, > = WriteParameters<chain, account> & Args export type ReturnValue = WriteContractReturnType // TODO: exhaustive error type export type ErrorType = BaseErrorType /** @internal */ export async function inner< action extends typeof writeContract | typeof writeContractSync, chain extends Chain | undefined, account extends Account | undefined, >( action: action, client: Client<Transport, chain, account>, parameters: burnBlocked.Parameters<chain, account>, ): Promise<ReturnType<action>> { const { amount, from, token, ...rest } = parameters const call = burnBlocked.call(client, { amount, from, token } as never) return (await action(client, { ...rest, ...call, } as never)) as never } /** * Defines a call to the `burnBlocked` function. * * Can be passed as a parameter to: * - [`estimateContractGas`](https://viem.sh/docs/contract/estimateContractGas): estimate the gas cost of the call * - [`simulateContract`](https://viem.sh/docs/contract/simulateContract): simulate the call * - [`sendCalls`](https://viem.sh/docs/actions/wallet/sendCalls): send multiple calls * * @example * ```ts * import { createClient, http, walletActions } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * * const client = createClient({ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }).extend(walletActions) * * const { result } = await client.sendCalls({ * calls: [ * actions.token.burnBlocked.call(client, { * from: '0x20c0...beef', * amount: 100n, * token: '0x20c0...babe', * }), * ] * }) * ``` * * `amount.decimals` is inferred from the client's declared `tokens` when omitted. * * @param parameters - Client (optional), followed by the call arguments. * @returns The call. */ export function call<chain extends Chain | undefined>( ...parameters: CallParameters<Args, Client<Transport, chain>> ) { const [client, args] = resolveCallParameters(parameters) const { from, amount, token } = args const { address, decimals } = resolveToken(client, { token }) return defineCall({ address, abi: Abis.tip20, functionName: 'burnBlocked', args: [from, internal_Token.toBaseUnits(amount, decimals)], }) } /** * Extracts the event from the logs. * * @param logs - Logs. * @returns The event. */ export function extractEvent(logs: Log[]) { const [log] = parseEventLogs({ abi: Abis.tip20, logs, eventName: 'BurnBlocked', }) if (!log) throw new Error('`BurnBlocked` event not found.') return log } } /** * Burns TIP20 tokens from a blocked address. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * import { privateKeyToAccount } from 'viem/accounts' * * const client = createClient({ * account: privateKeyToAccount('0x...'), * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const result = await Actions.token.burnBlockedSync(client, { * from: '0x...', * amount: 100n, * token: '0x...', * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The transaction receipt and event data. */ export async function burnBlockedSync< chain extends Chain | undefined, account extends Account | undefined, >( client: Client<Transport, chain, account>, parameters: burnBlockedSync.Parameters<chain, account>, ): Promise<burnBlockedSync.ReturnValue> { const { throwOnReceiptRevert = true, ...rest } = parameters const receipt = await burnBlocked.inner(writeContractSync, client, { ...rest, throwOnReceiptRevert, } as never) const { args } = burnBlocked.extractEvent(receipt.logs) return { ...args, receipt, } as never } export namespace burnBlockedSync { export type Parameters< chain extends Chain | undefined = Chain | undefined, account extends Account | undefined = Account | undefined, > = burnBlocked.Parameters<chain, account> export type Args = burnBlocked.Args export type ReturnValue = Compute< GetEventArgs< typeof Abis.tip20, 'BurnBlocked', { IndexedOnly: false Required: true } > & { /** Transaction receipt. */ receipt: TransactionReceipt } > // TODO: exhaustive error type export type ErrorType = BaseErrorType } /** * Burns TIP20 tokens from the caller's balance. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * import { privateKeyToAccount } from 'viem/accounts' * * const client = createClient({ * account: privateKeyToAccount('0x...'), * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const result = await Actions.token.burn(client, { * amount: 100n, * token: '0x...', * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The transaction hash. */ export async function burn< chain extends Chain | undefined, account extends Account | undefined, >( client: Client<Transport, chain, account>, parameters: burn.Parameters<chain, account>, ): Promise<burn.ReturnValue> { return burn.inner(writeContract, client, parameters) } export namespace burn { export type Args = { /** Amount of tokens to burn, in base units or formatted decimal form. */ amount: internal_Token.AmountInput /** Memo to include in the transfer. */ memo?: Hex.Hex | undefined } & TokenParameter export type Parameters< chain extends Chain | undefined = Chain | undefined, account extends Account | undefined = Account | undefined, > = WriteParameters<chain, account> & Args export type ReturnValue = WriteContractReturnType // TODO: exhaustive error type export type ErrorType = BaseErrorType /** @internal */ export async function inner< action extends typeof writeContract | typeof writeContractSync, chain extends Chain | undefined, account extends Account | undefined, >( action: action, client: Client<Transport, chain, account>, parameters: burn.Parameters<chain, account>, ): Promise<ReturnType<action>> { const { amount, memo, token, ...rest } = parameters const call = burn.call(client, { amount, memo, token } as never) return (await action(client, { ...rest, ...call, } as never)) as never } /** * Defines a call to the `burn` or `burnWithMemo` function. * * Can be passed as a parameter to: * - [`estimateContractGas`](https://viem.sh/docs/contract/estimateContractGas): estimate the gas cost of the call * - [`simulateContract`](https://viem.sh/docs/contract/simulateContract): simulate the call * - [`sendCalls`](https://viem.sh/docs/actions/wallet/sendCalls): send multiple calls * * @example * ```ts * import { createClient, http, walletActions } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * * const client = createClient({ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }).extend(walletActions) * * const { result } = await client.sendCalls({ * calls: [ * actions.token.burn.call(client, { * amount: 100n, * token: '0x20c0...babe', * }), * ] * }) * ``` * * `amount.decimals` is inferred from the client's declared `tokens` when omitted. * * @param parameters - Client (optional), followed by the call arguments. * @returns The call. */ export function call<chain extends Chain | undefined>( ...parameters: CallParameters<Args, Client<Transport, chain>> ) { const [client, args] = resolveCallParameters(parameters) const { amount, memo, token } = args const { address, decimals } = resolveToken(client, { token }) const value = internal_Token.toBaseUnits(amount, decimals) const callArgs = memo ? ({ functionName: 'burnWithMemo', args: [value, Hex.padLeft(memo, 32)], } as const) : ({ functionName: 'burn', args: [value], } as const) return defineCall({ address, abi: Abis.tip20, ...callArgs, }) } /** * Extracts the event from the logs. * * @param logs - Logs. * @returns The event. */ export function extractEvent(logs: Log[]) { const [log] = parseEventLogs({ abi: Abis.tip20, logs, eventName: 'Burn', }) if (!log) throw new Error('`Burn` event not found.') return log } } /** * Burns TIP20 tokens from the caller's balance. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * import { privateKeyToAccount } from 'viem/accounts' * * const client = createClient({ * account: privateKeyToAccount('0x...'), * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const result = await Actions.token.burnSync(client, { * amount: 100n, * token: '0x...', * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The transaction receipt and event data. */ export async function burnSync< chain extends Chain | undefined, account extends Account | undefined, >( client: Client<Transport, chain, account>, parameters: burnSync.Parameters<chain, account>, ): Promise<burnSync.ReturnValue> { const { throwOnReceiptRevert = true, ...rest } = parameters const receipt = await burn.inner(writeContractSync, client, { ...rest, throwOnReceiptRevert, } as never) const { args } = burn.extractEvent(receipt.logs) return { ...args, receipt, } as never } export namespace burnSync { export type Parameters< chain extends Chain | undefined = Chain | undefined, account extends Account | undefined = Account | undefined, > = burn.Parameters<chain, account> export type Args = burn.Args export type ReturnValue = Compute< GetEventArgs< typeof Abis.tip20, 'Burn', { IndexedOnly: false Required: true } > & { receipt: TransactionReceipt } > // TODO: exhaustive error type export type ErrorType = BaseErrorType } /** * Changes the transfer policy ID for a TIP20 token. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * import { privateKeyToAccount } from 'viem/accounts' * * const client = createClient({ * account: privateKeyToAccount('0x...'), * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const result = await Actions.token.changeTransferPolicy(client, { * token: '0x...', * policyId: 1n, * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The transaction hash. */ export async function changeTransferPolicy< chain extends Chain | undefined, account extends Account | undefined, >( client: Client<Transport, chain, account>, parameters: changeTransferPolicy.Parameters<chain, account>, ): Promise<changeTransferPolicy.ReturnValue> { return changeTransferPolicy.inner(writeContract, client, parameters) } export namespace changeTransferPolicy { export type Parameters< chain extends Chain | undefined = Chain | undefined, account extends Account | undefined = Account | undefined, > = WriteParameters<chain, account> & Args export type Args = { /** New transfer policy ID. */ policyId: bigint /** Address or ID of the TIP20 token. */ token: TokenId.TokenIdOrAddress } export type ReturnValue = WriteContractReturnType // TODO: exhaustive error type export type ErrorType = BaseErrorType /** @internal */ export async function inner< action extends typeof writeContract | typeof writeContractSync, chain extends Chain | undefined, account extends Account | undefined, >( action: action, client: Client<Transport, chain, account>, parameters: changeTransferPolicy.Parameters<chain, account>, ): Promise<ReturnType<action>> { const { policyId, token, ...rest } = parameters const call = changeTransferPolicy.call(client, { policyId, token }) return (await action(client, { ...rest, ...call, } as never)) as never } /** * Defines a call to the `changeTransferPolicyId` function. * * Can be passed as a parameter to: * - [`estimateContractGas`](https://viem.sh/docs/contract/estimateContractGas): estimate the gas cost of the call * - [`simulateContract`](https://viem.sh/docs/contract/simulateContract): simulate the call * - [`sendCalls`](https://viem.sh/docs/actions/wallet/sendCalls): send multiple calls * * @example * ```ts * import { createClient, http, walletActions } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * * const client = createClient({ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }).extend(walletActions) * * const { result } = await client.sendCalls({ * calls: [ * actions.token.changeTransferPolicy.call(client, { * token: '0x20c0...babe', * policyId: 1n, * }), * ] * }) * ``` * * @param parameters - Client (optional), followed by the call arguments. * @returns The call. */ export function call<chain extends Chain | undefined>( ...parameters: CallParameters<Args, Client<Transport, chain>> ) { const [client, args] = resolveCallParameters(parameters) const { token, policyId } = args return defineCall({ address: resolveToken(client, { token }).address, abi: Abis.tip20, functionName: 'changeTransferPolicyId', args: [policyId], }) } /** * Extracts the event from the logs. * * @param logs - Logs. * @returns The event. */ export function extractEvent(logs: Log[]) { const [log] = parseEventLogs({ abi: Abis.tip20, logs, eventName: 'TransferPolicyUpdate', }) if (!log) throw new Error('`TransferPolicyUpdate` event not found.') return log } } /** * Changes the transfer policy ID for a TIP20 token. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * import { privateKeyToAccount } from 'viem/accounts' * * const client = createClient({ * account: privateKeyToAccount('0x...'), * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const result = await Actions.token.changeTransferPolicySync(client, { * token: '0x...', * policyId: 1n, * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The transaction receipt and event data. */ export async function changeTransferPolicySync< chain extends Chain | undefined, account extends Account | undefined, >( client: Client<Transport, chain, account>, parameters: changeTransferPolicySync.Parameters<chain, account>, ): Promise<changeTransferPolicySync.ReturnValue> { const { throwOnReceiptRevert = true, ...rest } = parameters const receipt = await changeTransferPolicy.inner(writeContractSync, client, { ...rest, throwOnReceiptRevert, } as never) const { args } = changeTransferPolicy.extractEvent(receipt.logs) return { ...args, receipt, } as never } export namespace changeTransferPolicySync { export type Parameters< chain extends Chain | undefined = Chain | undefined, account extends Account | undefined = Account | undefined, > = changeTransferPolicy.Parameters<chain, account> export type Args = changeTransferPolicy.Args export type ReturnValue = Compute< GetEventArgs< typeof Abis.tip20, 'TransferPolicyUpdate', { IndexedOnly: false Required: true } > & { receipt: TransactionReceipt } > // TODO: exhaustive error type export type ErrorType = BaseErrorType } /** * Creates a new TIP20 token. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * import { privateKeyToAccount } from 'viem/accounts' * * const client = createClient({ * account: privateKeyToAccount('0x...'), * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const result = await Actions.token.create(client, { * name: 'My Token', * symbol: 'MTK', * currency: 'USD', * logoURI: 'https://example.com/token.svg', * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The transaction hash. */ export async function create< chain extends Chain | undefined, account extends Account | undefined, >( client: Client<Transport, chain, account>, parameters: create.Parameters<chain, account>, ): Promise<create.ReturnValue> { return create.inner(writeContract, client, parameters) } export namespace create { export type Parameters< chain extends Chain | undefined = Chain | undefined, account extends Account | undefined = Account | undefined, > = WriteParameters<chain, account> & Omit<Args, 'admin'> & (account extends Account ? { admin?: Account | Address | undefined } : { admin: Account | Address }) export type Args = { /** Admin address. */ admin: Address /** Currency (e.g. "USD"). */ currency: string /** Token name. */ name: string /** Logo URI. Requires a T5-enabled Tempo chain. */ logoURI?: string | undefined /** Quote token. */ quoteToken?: TokenId.TokenIdOrAddress | undefined /** Unique salt. @default Hex.random(32) */ salt?: Hex.Hex | undefined /** Token symbol. */ symbol: string } export type ReturnValue = WriteContractReturnType // TODO: exhaustive error type export type ErrorType = BaseErrorType /** @internal */ export async function inner< action extends typeof writeContract | typeof writeContractSync, chain extends Chain | undefined, account extends Account | undefined, >( action: action, client: Client<Transport, chain, account>, parameters: any, ): Promise<ReturnType<action>> { const { account = client.account, admin: admin_ = client.account, chain = client.chain, ...rest } = parameters const admin = admin_ ? parseAccount(admin_) : undefined if (!admin) throw new Error('admin is required.') const call = create.call(client, { ...rest, admin: admin.address }) return (await action( client as never, { ...parameters, account, chain, ...call, } as never, )) as never } /** * Defines a call to the `createToken` function. * * Can be passed as a parameter to: * - [`estimateContractGas`](https://viem.sh/docs/contract/estimateContractGas): estimate the gas cost of the call * - [`simulateContract`](https://viem.sh/docs/contract/simulateContract): simulate the call * - [`sendCalls`](https://viem.sh/docs/actions/wallet/sendCalls): send multiple calls * * @example * ```ts * import { createClient, http, walletActions } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * * const client = createClient({ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }).extend(walletActions) * * const { result } = await client.sendCalls({ * calls: [ * actions.token.create.call(client, { * name: 'My Token', * symbol: 'MTK', * currency: 'USD', * logoURI: 'https://example.com/token.svg', * admin: '0xfeed...fede', * }), * ] * }) * ``` * * @param parameters - Client (optional), followed by the call arguments. * @returns The call. */ export function call<chain extends Chain | undefined>( ...parameters: CallParameters<Args, Client<Transport, chain>> ) { const [client, args] = resolveCallParameters(parameters) const { name, symbol, currency, logoURI, quoteToken = Addresses.pathUsd, admin, salt = Hex.random(32), } = args return defineCall({ address: Addresses.tip20Factory, abi: Abis.tip20Factory, args: typeof logoURI === 'string' ? [ name, symbol, currency, resolveToken(client, { token: quoteToken }).address, admin, salt, logoURI, ] : [ name, symbol, currency, resolveToken(client, { token: quoteToken }).address, admin, salt, ], functionName: 'createToken', }) } /** * Extracts the `TokenCreated` event from logs. * * @param logs - The logs. * @returns The `TokenCreated` event. */ export function extractEvent(logs: Log[]) { const [log] = parseEventLogs({ abi: Abis.tip20Factory, logs, eventName: 'TokenCreated', strict: true, }) if (!log) throw new Error('`TokenCreated` event not found.') return log } } /** * Creates a new TIP20 token. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * import { privateKeyToAccount } from 'viem/accounts' * * const client = createClient({ * account: privateKeyToAccount('0x...'), * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const result = await Actions.token.createSync(client, { * name: 'My Token', * symbol: 'MTK', * currency: 'USD', * logoURI: 'https://example.com/token.svg', * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The transaction receipt and event data. */ export async function createSync< chain extends Chain | undefined, account extends Account | undefined, >( client: Client<Transport, chain, account>, parameters: createSync.Parameters<chain, account>, ): Promise<createSync.ReturnValue> { const { throwOnReceiptRevert = true, ...rest } = parameters const receipt = await create.inner(writeContractSync, client, { ...rest, throwOnReceiptRevert, } as never) const { args } = create.extractEvent(receipt.logs) const tokenId = TokenId.fromAddress(args.token) return { ...args, receipt, tokenId, } as never } export namespace createSync { export type Parameters< chain extends Chain | undefined = Chain | undefined, account extends Account | undefined = Account | undefined, > = create.Parameters<chain, account> export type Args = create.Args export type ReturnValue = Compute< GetEventArgs< typeof Abis.tip20Factory, 'TokenCreated', { IndexedOnly: false; Required: true } > & { /** Token ID. */ tokenId: TokenId.TokenId /** Transaction receipt. */ receipt: TransactionReceipt } > // TODO: exhaustive error type export type ErrorType = BaseErrorType } /** * Gets TIP20 token allowance. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * import { privateKeyToAccount } from 'viem/accounts' * * const client = createClient({ * account: privateKeyToAccount('0x...'), * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const allowance = await Actions.token.getAllowance(client, { * account: '0x...', * spender: '0x...', * token: '0x...', * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The token allowance, in base units and human-readable form. */ export async function getAllowance<chain extends Chain | undefined>( client: Client<Transport, chain>, parameters: getAllowance.Parameters, ): Promise<getAllowance.ReturnValue> { const { account, decimals, spender, token, ...rest } = parameters const [amount, { decimals: resolved }] = await Promise.all([ readContract(client, { ...rest, ...getAllowance.call(client, { account, spender, token } as never), }), resolveTokenWithDecimals(client, { decimals, token, }), ]) return internal_Token.toAmount(amount, resolved) } export namespace getAllowance { export type Args = { /** Account that owns the tokens. */ account: Address /** Spender of the tokens. */ spender: Address } & TokenParameters export type Parameters = ReadParameters & Args export type ReturnValue = internal_Token.Amount /** * Defines a call to the `allowance` function. * * Can be passed as a parameter to `multicall`, `simulateContract`, or any * other action that accepts a contract call. The token is selected by `token`, * which is either a TIP20 token id or a contract address. * * @param parameters - Client (optional), followed by the call arguments. * @returns The call. */ export function call<chain extends Chain | undefined>( ...parameters: CallParameters<Args, Client<Transport, chain>> ) { const [client, args] = resolveCallParameters(parameters) return defineCall({ address: resolveToken(client, args).address, abi: Abis.tip20, functionName: 'allowance', args: [args.account, args.spender], }) } } /** * Gets TIP20 token balance for an address. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * import { privateKeyToAccount } from 'viem/accounts' * * const client = createClient({ * account: privateKeyToAccount('0x...'), * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const balance = await Actions.token.getBalance(client, { * account: '0x...', * token: '0x...', * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The token balance, in base units and human-readable form. */ export async function getBalance< chain extends Chain | undefined, account extends Account | undefined, >( client: Client<Transport, chain, account>, parameters: getBalance.Parameters<account>, ): Promise<getBalance.ReturnValue> { const { account: account_ = client.account, decimals, token, ...rest } = parameters if (!account_) throw new AccountNotFoundError() const account = parseAccount(account_).address const [amount, { decimals: resolved }] = await Promise.all([ readContract(client, { ...rest, ...getBalance.call(client, { account, token } as never), }), resolveTokenWithDecimals(client, { decimals, token, }), ]) return internal_Token.toAmount(amount, resolved) } export namespace getBalance { export type Args<account extends Account | undefined = Account | undefined> = GetAccountParameter<account, Account | Address> & TokenParameters export type Parameters< account extends Account | undefined = Account | undefined, > = Omit<ReadParameters, 'account'> & Args<account> export type ReturnValue = internal_Token.Amount /** * Defines a call to the `balanceOf` function. * * Can be passed as a parameter to `multicall`, `simulateContract`, or any * other action that accepts a contract call. The token is selected by `token`, * which is either a TIP20 token id or a contract address. * * @param parameters - Client (optional), followed by the call arguments. * @returns The call. */ export function call< chain extends Chain | undefined, account extends Account | undefined, >( ...parameters: CallParameters< Args<account>, Client<Transport, chain, account> > ) { const [client, args] = resolveCallParameters(parameters) const account_ = args.account ?? client?.account if (!account_) throw new AccountNotFoundError() const account = parseAccount(account_).address return defineCall({ address: resolveToken(client, args).address, abi: Abis.tip20, functionName: 'balanceOf', args: [account], }) } } /** * Gets TIP20 token metadata including name, symbol, logo URI, currency, decimals, and total supply. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * import { privateKeyToAccount } from 'viem/accounts' * * const client = createClient({ * account: privateKeyToAccount('0x...'), * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const metadata = await Actions.token.getMetadata(client, { * token: '0x...', * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The token metadata. */ export async function getMetadata<chain extends Chain | undefined>( client: Client<Transport, chain>, parameters: getMetadata.Parameters, ): Promise<getMetadata.ReturnValue> { const { token, ...rest } = parameters const { address } = resolveToken(client, { token }) const abi = Abis.tip20 const declared = findDeclaredToken(client, token) const overrides = { ...(declared?.decimals != null ? { decimals: declared.decimals } : {}), ...(declared?.name != null ? { name: declared.name } : {}), ...(declared?.symbol != null ? { symbol: declared.symbol } : {}), } if (TokenId.fromAddress(address) === TokenId.fromAddress(Addresses.pathUsd)) return multicall(client, { ...rest, contracts: [ { address, abi, functionName: 'currency', }, { address, abi, functionName: 'decimals', }, { address, abi, functionName: 'logoURI', }, { address, abi, functionName: 'name', }, { address, abi, functionName: 'symbol', }, { address, abi, functionName: 'totalSupply', }, ] as const, allowFailure: true, deployless: true, }).then(([currency, decimals, logoURI, name, symbol, totalSupply]) => ({ name: unwrapMulticallResult(name), symbol: unwrapMulticallResult(symbol), currency: unwrapMulticallResult(currency), decimals: unwrapMulticallResult(decimals), logoURI: unwrapMulticallResult(logoURI, ''), totalSupply: unwrapMulticallResult(totalSupply), ...overrides, })) return multicall(client, { ...rest, contracts: [ { address, abi, functionName: 'currency', }, { address, abi, functionName: 'decimals', }, { address, abi, functionName: 'logoURI', }, { address, abi, functionName: 'quoteToken', }, { address, abi, functionName: 'name', }, { address, abi, functionName: 'paused', }, { address, abi, functionName: 'supplyCap', }, { address, abi, functionName: 'symbol', }, { address, abi, functionName: 'totalSupply', }, { address, abi, functionName: 'transferPolicyId', }, ] as const, allowFailure: true, deployless: true, }).then( ([ currency, decimals, logoURI, quoteToken, name, paused, supplyCap, symbol, totalSupply, transferPolicyId, ]) => ({ name: unwrapMulticallResult(name), symbol: unwrapMulticallResult(symbol), currency: unwrapMulticallResult(currency), decimals: unwrapMulticallResult(decimals), logoURI: unwrapMulticallResult(logoURI, ''), quoteToken: unwrapMulticallResult(quoteToken), totalSupply: unwrapMulticallResult(totalSupply), paused: unwrapMulticallResult(paused), supplyCap: unwrapMulticallResult(supplyCap), transferPolicyId: unwrapMulticallResult(transferPolicyId), ...overrides, }), ) } function unwrapMulticallResult<result>( response: | { result: result; status: 'success' } | { error: unknown; status: 'failure' }, ): result function unwrapMulticallResult<result>( response: | { result: result; status: 'success' } | { error: unknown; status: 'failure' }, fallback: result, ): result function unwrapMulticallResult<result>( response: | { result: result; status: 'success' } | { error: unknown; status: 'failure' }, ...fallback: [] | [result] ) { if (response.status === 'failure') { if (fallback.length > 0) return fallback[0] throw response.error } return response.result } export declare namespace getMetadata { export type Parameters = Omit<ReadParameters, 'account'> & TokenParameter export type ReturnValue = Compute<{ /** * Currency (e.g. "USD"). */ currency: string /** * Decimals of the token. */ decimals: number /** * Logo URI of the token. Returns an empty string if unset or unsupported * by the active Tempo hardfork. */ logoURI: string /** * Quote token. * * Returns `undefined` for the default quote token (`0x20c...0000`). */ quoteToken?: Address | undefined /** * Name of the token. */ name: string /** * Whether the token is paused. * * Returns `undefined` for the default quote token (`0x20c...0000`). */ paused?: boolean | undefined /** * Supply cap. * * Returns `undefined` for the default quote token (`0x20c...0000`). */ supplyCap?: bigint | undefined /** * Symbol of the token. */ symbol: string /** * Total supply of the token. */ totalSupply: bigint /** * Transfer policy ID. * 0="always-reject", 1="always-allow", >2=custom policy * * Returns `undefined` for the default quote token (`0x20c...0000`). */ transferPolicyId?: bigint | undefined }> } /** * Gets the total supply of a TIP20 token. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * * const client = createClient({ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const totalSupply = await Actions.token.getTotalSupply(client, { * token: '0x...', * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The token total supply, in base units and human-readable form. */ export async function getTotalSupply<chain extends Chain | undefined>( client: Client<Transport, chain>, parameters: getTotalSupply.Parameters, ): Promise<getTotalSupply.ReturnValue> { const { decimals, token, ...rest } = parameters const [amount, { decimals: resolved }] = await Promise.all([ readContract(client, { ...rest, ...getTotalSupply.call(client, { token } as never), }), resolveTokenWithDecimals(client, { decimals, token, }), ]) return internal_Token.toAmount(amount, resolved) } export namespace getTotalSupply { export type Args = TokenParameters export type Parameters = Omit<ReadParameters, 'account'> & Args export type ReturnValue = internal_Token.Amount /** * Defines a call to the `totalSupply` function. * * Can be passed as a parameter to `multicall`, `simulateContract`, or any * other action that accepts a contract call. The token is selected by `token`, * which is either a TIP20 token id or a contract address. * * @param parameters - Client (optional), followed by the call arguments. * @returns The call. */ export function call<chain extends Chain | undefined>( ...parameters: CallParameters<Args, Client<Transport, chain>> ) { const [client, args] = resolveCallParameters(parameters) return defineCall({ address: resolveToken(client, args).address, abi: Abis.tip20, args: [], functionName: 'totalSupply', }) } } /** * Gets the admin role for a specific role in a TIP20 token. * * @example * ```ts * import { createClient, http } from 'viem' * import { tempo } from 'viem/chains' * import { Actions } from 'viem/tempo' * * const client = createClient({ * chain: tempo.extend({ feeToken: '0x20c0000000000000000000000000000000000001' }) * transport: http(), * }) * * const adminRole = await Actions.token.getRoleAdmin(client, { * role: 'issuer', * token: '0x...', * }) * ``` * * @param client - Client. * @param parameters - Parameters. * @returns The admin role hash. */ export async function getRoleAdmin<chain extends Chain | undefined>( client: Client<Transport, chain>, parameters: getRoleAdmin.Parameters, ): Promise<getRoleAdmin.ReturnValue> { return readContract(client, { ...parameters, ...getRoleAdmin.call(client, parameters), }) } export namespace getRoleAdmin { export type Parameters = ReadParameters & Args export type Args = { /** Role to get admin for. */ role: TokenRole.TokenRole /** Address or ID of the TIP20 token. */ token: TokenId.TokenIdOrAddress } export type ReturnValue = ReadContractReturnType< typeof Abis.tip20, 'getRoleAdmin', never > /** * Defines a call to the `getRoleAdmin` function. * * @param parameters - Client (optional), followed by the call arguments. * @returns The call. */ export function call<chain extends Chain | undefined>( ...parameters: CallParameters<Args, Client<Transport, chain>> ) { const [client, args] = resolveCallParameters(parameters) const { role, token } = args return defineCall({ address: resolveToken