ERC20 Token
A complete example of an ERC20 implementation using the AssemblyScript Stylus SDK.
Complete Contract: You can view the full ERC20 contract implementation here.
Contract Structure
Events
Events record token activity for external indexing:
@Event
export class Transfer {
@Indexed from: Address;
@Indexed to: Address;
value: U256;
}
@Event
export class Approval {
@Indexed owner: Address;
@Indexed spender: Address;
value: U256;
}
Storage State
State variables that persist on the blockchain:
@Contract
export class ERC20Full {
static balances: Mapping<Address, U256> = new Mapping<Address, U256>();
static allowances: Mapping2<Address, Address, U256> = new Mapping2<Address, Address, U256>();
static totalSupply: U256;
static name: Str;
static symbol: Str;
Constructor
Initializes the token with name and symbol:
constructor(_name: string, _symbol: string) {
const nameStr = StrFactory.fromString(_name);
const symbolStr = StrFactory.fromString(_symbol);
name = nameStr;
symbol = symbolStr;
}
View Functions
Read-only methods for querying information:
@View
static name(): string {
return name;
}
@View
static symbol(): string {
return symbol;
}
@View
static totalSupply(): U256 {
return totalSupply;
}
@View
static balanceOf(account: Address): U256 {
return balances.get(account);
}
@View
static allowance(owner: Address, spender: Address): U256 {
return allowances.get(owner, spender);
}
Transfer Function
Transfers tokens between accounts:
@External
static transfer(to: Address, amount: U256): boolean {
const sender = msg.sender;
const senderBal = balances.get(sender);
if (senderBal < amount) {
return false;
}
balances.set(sender, senderBal.sub(amount));
const recvBal = balances.get(to);
balances.set(to, recvBal.add(amount));
Transfer.emit(sender, to, amount);
return true;
}
Approval System
Allows third parties to spend tokens on your behalf:
@External
static approve(spender: Address, amount: U256): boolean {
const owner = msg.sender;
allowances.set(owner, spender, amount);
Approval.emit(owner, spender, amount);
return true;
}
@External
static transferFrom(from: Address, to: Address, amount: U256): boolean {
const spender = msg.sender;
const allowed = allowances.get(from, spender);
if (allowed < amount) {
return false;
}
const fromBal = balances.get(from);
if (fromBal < amount) {
return false;
}
balances.set(from, fromBal.sub(amount));
const toBal = balances.get(to);
balances.set(to, toBal.add(amount));
allowances.set(from, spender, allowed.sub(amount));
Transfer.emit(from, to, amount);
return true;
}
Mint & Burn
Functions to mint and burn tokens:
@External
static mint(to: Address, amount: U256): void {
totalSupply = totalSupply.add(amount);
const toAmount = balances.get(to);
balances.set(to, toAmount.add(amount));
const AddressZero = AddressFactory.fromString("0x0000000000000000000000000000000000000000");
Transfer.emit(AddressZero, to, amount);
}
@External
static burn(amount: U256): void {
const sender = msg.sender;
const senderBal = balances.get(sender);
if (senderBal < amount) {
return;
}
balances.set(sender, senderBal.sub(amount));
totalSupply = totalSupply.sub(amount);
const AddressZero = AddressFactory.fromString("0x0000000000000000000000000000000000000000");
Transfer.emit(sender, AddressZero, amount);
}
}