viem
Version:
1,744 lines (1,658 loc) • 135 kB
text/typescript
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