Status: Published
Version: 1.1.0
This document describes the standard interface for tokenized asset SmartWeave Contracts. The SmartWeave Token Spec refers to a SmartWeave Contract that can grant ownership properties to any arweave asset when it is deployed, effectively turning it into a fungible token. However, it's important to note that the fundamental characteristics of an atomic token alone do not allow for unrestricted trading without the presence of an interop protocol, such as the Foreign Call Protocol.
The Permaweb community requires a transparent and straightforward approach to establish clear semantics for tradable contracts. The SmartWeave Token serves as the designated specification, which has already been adopted as the standard practice within the ecosystem for a considerable period of time. This document aims to formalize and document this practice to ensure clarity and transparency.
The contract specification consists of state properties and contract functions. The three primary state properties are name, ticker, and balances. The contract functions include balance and transfer. The choice between a fungible or non-fungible token is left to the creator's discretion. While the contract must include these elements, it may also incorporate additional state properties or functions as desired. It is frequently observed that the SWT is often combined with the Foreign Call Protocol spec for enhanced functionality.
balanceOf(target: Address) => { target: Address, balance: number }
- Returns the current balance of a
target
address
transfer(target: Address, qty: number) => void
- Transfers
qty
of tokens totarget
address - SHOULD THROW if the caller does not have enough balance to transfer.
name() => string | undefined
- Returns the name of the SmartWeave Token
- MAY be ommitted if the contract state includes a property
name
of typestring | undefined
.
ticker() => string | undefined
- Returns the ticker of the SmartWeave Token
- MAY be ommitted if the contract state includes a property
ticker
of typestring | undefined
.
decimals() => number
- Returns the number of decimal places the token amount should display.
- MUST return an integer
- MAY be ommitted if the contract state includes a property
decimals
of typenumber
and is an integer.
type Address = string
interface State {
name: string
ticker: string
decimals: number // Integer
balances: Record<Address, number>
}
interface BalanceOf {
target: Address
}
interface Transfer {
qty: number
target: Address
}
Name | Type | Description |
---|---|---|
name |
string |
The name of the token |
ticker |
string |
The ticker symbol of the token |
decimals |
number |
the number (integer) of decimal places the token amount should display. |
balances |
Record<Address, Number> |
Map of addresses to their numeric balance |
/**
@param {State} state
@param {BalanceOf} action
@returns {Result} The current balance of the target address
*/
function balance(state: State, action: BalanceOf) {
return {
result: {
target: action.input.target,
balance: state.balances[action.input.target] || 0
}
}
}
/**
@param {State} state
@param {Transfer} action
@returns {State}
*/
function transfer(state: State, action: Transfer) {
if (!action.input.qty || typeof action.input.qty !== "number") {
throw new ContractError("qty is not defined or is not a number")
}
if (action.caller === action.input.target) {
throw new ContractError("target cannot be caller")
}
if (!state.balances[action.input.target]) {
state.balances[action.input.target] = 0
}
if (!state.balances[action.caller]) {
state.balances[action.caller] = 0
}
if (state.balances[action.caller] < action.input.qty) {
throw new ContractError("not enough balance to transfer")
}
state.balances[action.caller] -= action.input.qty
state.balances[action.input.target] += action.input.qty
return { state }
}