OP_20 Implementations

Introduction

All OP_NET smart contracts:
  • Are required to extend the OP_NET base class (directly or indirectly).
  • Use the Calldata parameters and BytesWriter return values patterns.
  • Accepting tokens must implement the onOP20Received callback.

Calldata Encoding and Result Decoding

The BytesWriter class encodes calldata parameters for contract calls, while the response data can be decoded using corresponding read methods. The calldata is constructed by writing the function selector followed by each parameter in order. After executing the call, the response is decoded by reading values in the same sequence as the contract returns them.

assemblyscript
Encoding and decoding Calldata and result
// How to encode the Calldata parameters
// 1st parameter: selector (method to call)
// 2nd parameter: address1
// 3rd parameter: amount1
const calldata = new BytesWriter(SELECTOR_BYTE_LENGTH +
    ADDRESS_BYTE_LENGTH +
    U256_BYTE_LENGTH);

calldata.writeSelector('FUNCTION SELECTOR HERE');
calldata.writeAddress(address1);
calldata.writeU256(amount1);

// How to decode BytesWriter return values
const response = Blockchain.call(token, calldata);

if (response.data.byteLength != 0){
    thow new Revert('Invalid response.');
}

// Decode response
const value = response.data.readU256();
const name = response.data.readStringWithLength();

OP20 Abstract Class

The OP20 class is the OP_NET concrete implementation of the OP_20 standard. It implements the IOP20 interface and extends ReentrancyGuard, which provides both OP_NET base class inheritance and built-in reentrancy attack protection.

Protected methods can be overridden to implement custom logic or extend the default behavior, providing flexibility for specialized token implementations.

assemblyscript
OP20 class
abstract class OP20 extends ReentrancyGuard implements IOP20 {
    public name(_: Calldata): BytesWriter;
    public symbol(_: Calldata): BytesWriter;
    public icon(_: Calldata): BytesWriter;
    public decimals(_: Calldata): BytesWriter;
    public totalSupply(_: Calldata): BytesWriter;
    public maximumSupply(_: Calldata): BytesWriter;
    public metadata(_: Calldata): BytesWriter;
    public domainSeparator(_: Calldata): BytesWriter;
    public balanceOf(calldata: Calldata): BytesWriter;
    public nonceOf(calldata: Calldata): BytesWriter;
    public allowance(calldata: Calldata): BytesWriter;
    public safeTransfer(calldata: Calldata): BytesWriter;
    public safeTransferFrom(calldata: Calldata): BytesWriter;
    public transfer(calldata: Calldata): BytesWriter;
    public transferFrom(calldata: Calldata): BytesWriter;
    public burn(calldata: Calldata): BytesWriter;
    public increaseAllowance(calldata: Calldata): BytesWriter;
    public decreaseAllowance(calldata: Calldata): BytesWriter;
    public increaseAllowanceBySignature(calldata: Calldata): BytesWriter;
    public decreaseAllowanceBySignature(calldata: Calldata): BytesWriter;

    // Used for token deployments
    public instantiate(params: OP20InitParameters, skipDeployerVerification: boolean = false): void;

    // Overrides
    protected _balanceOf(owner: Address): u256;
    protected _allowance(owner: Address, spender: Address): u256;
    protected _safeTransfer(from: Address, to: Address, amount: u256, data: Uint8Array): void;
    protected _transfer(from: Address, to: Address, amount: u256): void;
    protected _spendAllowance(owner: Address, spender: Address, amount: u256): void;
    protected _callOnOP20Received( from: Address, to: Address, amount: u256,data: Uint8Array): void;
    protected _increaseAllowance(owner: Address, spender: Address, amount: u256): void;
    protected _decreaseAllowance(owner: Address, spender: Address, amount: u256): void;
    protected _increaseAllowanceBySignature(owner: Address,spender: Address,amount: u256,deadline: u64,signature: Uint8Array): void;
    protected _decreaseAllowanceBySignature(owner: Address, spender: Address, amount: u256, deadline: u64, signature: Uint8Array): void;
    protected _verifySignature(typeHash: u8[], owner: Address, spender: Address, amount: u256, deadline: u64, signature: Uint8Array): void;
    protected _buildDomainSeparator(): Uint8Array;
    protected _mint(to: Address, amount: u256): void;
    protected _burn(from: Address, amount: u256): void;
}

Reference

name
symbol
icon
decimals
totalSupply
maximumSupply
metadata
domainSeparator
balanceOf
nonceOf
allowance
safeTransfer
safeTransferFrom
transfer
transferFrom
burn
increaseAllowance
decreaseAllowance
increaseAllowanceBySignature
decreaseAllowanceBySignature
instantiate
Warning
The following protected methods can be overridden to implement custom logic. However, this must be done with caution. Any override must ensure that OP_20 standard requirements are still met and must not break the existing implementation.
_balanceOf
_allowance
_safeTransfer
_transfer
_spendAllowance
_callOnOP20Received
_increaseAllowance
_decreaseAllowance
_increaseAllowanceBySignature
_decreaseAllowanceBySignature
_verifySignature
_buildDomainSeparator
_mint
_burn

Events

The OP20 class emits the three OP_20 standard events: Approved, Burned, and Transferred.

Additionally, the OP20 class emits a Minted event, which is specific to this implementation and is implemented by the OP20MintedEvent class.

Approved

assemblyscript
OP20ApprovedEvent
class OP20ApprovedEvent extends NetEvent {
    constructor(owner: Address, spender: Address, amount: u256);
}

Reference

constructor

Burned

assemblyscript
BurnedEvent
class OP20BurnedEvent extends NetEvent {
    constructor(from: Address, amount: u256);
}

Reference

constructor

Minted

assemblyscript
MintedEvent
class OP20MintedEvent extends NetEvent {
    constructor(to: Address, amount: u256)
}

Reference

constructor

Transferred

assemblyscript
TransferredEvent
class OP20TransferredEvent extends NetEvent {
    constructor(operator: Address, from: Address, to: Address, amount: u256);
}

Reference

constructor

Callbacks

The IOP20Receiver interface is not implemented by the OP20 abstract class. Instead, derived classes must provide their own implementation.

assemblyscript
IOP20Receiver concrete implementation example
interface IOP20Receiver {
    onOP20Received(callData: Calldata): BytesWriter;
}

// Example
@final
export class ContractEx extends ReentrancyGuard implements IOP20Receiver {
    ...
    public override execute(method: Selector, calldata: Calldata): BytesWriter {
        let writer: BytesWriter;

        switch (method) {
            case encodeSelector('onOP20Received(address,address,uint256,bytes)'):
                return this.onOP20Received(calldata);
            default:
                return super.execute(method, calldata);
        }

        return writer;
    }

    public onOP20Received(calldata: Calldata): BytesWriter {
        const operator = calldata.readAddress();
        const from = calldata.readAddress();
        const amount = calldata.readU256();
        const data: Uint8Array = calldata.readBytesWithLength();
        // Custom logic here if needed
        ...

        const writer = new BytesWriter(SELECTOR_BYTE_LENGTH);
        writer.writeSelector(ON_OP_20_RECEIVED_SELECTOR);
        return writer;
    }
    ...
}

Data Structures

OP20InitParameters

assemblyscript
OP20InitParameters
export class OP20InitParameters {
    readonly maxSupply: u256;
    readonly decimals: u8;
    readonly name: string;
    readonly symbol: string;
    readonly icon: string;

    constructor(maxSupply: u256, decimals: u8, name: string, symbol: string, icon: string = '') {
        this.maxSupply = maxSupply;
        this.decimals = decimals;
        this.name = name;
        this.symbol = symbol;
        this.icon = icon;
    }
}

Reference

constructor

Type Definitions

Type definitions only, not concrete implementations:

  • OP712Domain
  • OP20AllowanceIncrease
  • OP20AllowanceDecrease

These type definitions define the data schema used by methods for signature validation and hash generation, such as signed allowance operations and the domainSeparator method.

Refer to the OP_20 Standard specification for detailed definitions.