Skip to content

btc-vision/OP_20

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Deploying and Customizing an OP_20 Token on OP_NET

Bitcoin AssemblyScript TypeScript NodeJS WebAssembly NPM

code style: prettier

Prerequisites

  • Ensure you have Node.js and npm installed on your computer.

Step-by-Step Guide

1. Install OP_WALLET Chrome Extension

2. Obtain Testnet Bitcoin

  • If you don't have any Regtest Bitcoin, get some from this faucet.

3. Download OP_20 Template Contract

4. Edit Token Details

This step is crucial for customizing your OP_20 token. You will need to adjust several key properties such as maxSupply, decimals, name, and symbol.

Understanding Token Properties

Here’s what each property means and how you can customize it:

  1. maxSupply:
  • This defines the total supply of your token.
  • It’s a u256 value representing the maximum number of tokens that will ever exist.
  • The number should include the full number of decimals.
  • Example: If you want a total supply of 1,000,000 tokens with 18 decimals, the value should be 1000000000000000000000000.
const maxSupply: u256 = u128.fromString('1000000000000000000000000').toU256(); // 1,000,000 tokens with 18 decimals
  1. decimals:
  • This property defines how divisible your token is.
  • A value of 18 means the token can be divided down to 18 decimal places, similar to how Ethereum handles its tokens.
const decimals: u8 = 18; // Your decimals
  1. name:
  • The name is a string representing the full name of your token.
  • This will be displayed in wallets and exchanges.
const name: string = 'YourTokenName'; // e.g., 'My Custom Token'
  1. symbol:
  • The symbol is a short string representing the ticker symbol of your token.
  • Similar to how "BTC" represents Bitcoin.
const symbol: string = 'SYM'; // e.g., 'MYT'

Modifying the Contract Code

Open the OP_20 template repository in your IDE or text editor and navigate to src/contracts/MyToken.ts. Look for the following section in the onInstantiated method:

const maxSupply: u256 = u128.fromString('1000000000000000000000000').toU256(); // Your max supply
const decimals: u8 = 18; // Your decimals
const name: string = 'YourTokenName'; // Your token name
const symbol: string = 'SYM'; // Your token symbol

Modify the values as needed for your token.

5. Install Dependencies and Build

After customizing your token's properties, build the contract:

  • Open your terminal and navigate to the location of the downloaded OP_20 template folder.

  • Run the following commands:

    npm install
    npm run build
  • After building, a build folder will be created in the root of the OP_20 folder. Look for [nameoftoken].wasm for the compiled contract.

6. Deploy the Token Contract

  • Open the OP_WALLET extension and select the "deploy" option.
  • Drag your .wasm file or click to choose it.
  • Send your transaction to deploy the token contract onto Bitcoin with OP_NET.

7. Add Liquidity on Motoswap

  • Copy the token address from your OP_WALLET.
  • Go to Motoswap and paste your token address into the top or bottom box.
  • Enter the amount of tokens you wish to add to the liquidity pool.
  • Select the other side of the liquidity pair (e.g., WBTC) and enter the amount of tokens you wish to add.
  • Click "Add Liquidity".

Your token is now tradeable on Motoswap!


Customizing Your Token Further

Now that you've set up the basic token properties, you can add additional functionality to your OP_20 token contract. Here are some common customizations:

Adding Custom Methods

To add custom functionality to your token, you can define new methods in your contract. For example, let's say you want to add an "airdrop" function that distributes tokens to multiple addresses.

Example: Airdrop Function

public override callMethod(method: Selector, calldata: Calldata): BytesWriter {
    switch (method) {
        case encodeSelector('airdrop'):
            return this.airdrop(calldata);
        default:
            return super.callMethod(method, calldata);
    }
}

private airdrop(calldata: Calldata): BytesWriter {
    const drops: Map<Address, u256> = calldata.readAddressValueTuple();

    const addresses: Address[] = drops.keys();
    for (let i: i32 = 0; i < addresses.length; i++) {
        const address = addresses[i];
        const amount = drops.get(address);

        this._mint(address, amount);
    }

    const writer: BytesWriter = new BytesWriter(1);
    writer.writeBoolean(true);

    return writer;
}

Overriding Methods

You may want to override some of the existing methods in the DeployableOP_20 base class. For example, you might want to add additional logic when minting tokens.

Example: Overriding _mint Method

protected _mint(to: Address, amount: u256): void {
    super._mint(to, amount);

    // Add custom logic here
    Blockchain.log(`Minted ${amount.toString()} tokens to ${to.toString()}`); // Only work inside OP_NET Uint Test Framework
}

Creating Events

Events in OP_NET allow you to emit signals that external observers can listen to. These are useful for tracking specific actions within your contract, such as token transfers or approvals.

Example: Transfer Event

class TransferEvent extends NetEvent {
    constructor(from: Address, to: Address, amount: u256) {
        const writer = new BytesWriter(ADDRESS_BYTE_LENGTH + ADDRESS_BYTE_LENGTH + 32);
        writer.writeAddress(from);
        writer.writeAddress(to);
        writer.writeU256(amount);
        super('Transfer', writer);
    }
}

class MyToken extends DeployableOP_20 {
    public transfer(to: Address, amount: u256): void {
        const from: Address = Blockchain.sender;
        this._mint(to, amount);
        this.emitEvent(new TransferEvent(from, to, amount));
    }
}

Implementing Additional Security Measures

If you want to add more control over who can call certain methods or add advanced features like pausing token transfers, you can implement access control mechanisms.

Example: Only Owner Modifier

public mint(to: Address, amount: u256): void {
    this.onlyOwner(Blockchain.sender); // Restrict minting to the contract owner
    this._mint(to, amount);
}

Differences Between Solidity and AssemblyScript on OP_NET

Constructor Behavior

  • Solidity: The constructor runs only once at the time of contract deployment and is used for initializing contract state.
  • AssemblyScript on OP_NET: The constructor runs every time the contract is instantiated. Use onInstantiated() for initialization that should occur only once.

State Management

  • Solidity: Variables declared at the contract level are automatically persistent and are stored in the contract's state.
  • AssemblyScript on OP_NET: Persistent state must be managed explicitly using storage classes like StoredU256, StoredBoolean, and StoredString.

Method Overriding

  • Solidity: Method selectors are built-in, and overriding them is straightforward.
  • AssemblyScript on OP_NET: Method selectors are manually defined using functions like encodeSelector(), and method overriding is handled in callMethod.

Event Handling

  • Solidity: Events are declared and emitted using the emit keyword.
  • AssemblyScript on OP_NET: Events are custom classes derived from NetEvent and are emitted using the emitEvent function.

Advanced Features

Implementing Additional Custom Logic

The OPNet runtime allows you to implement complex logic in your token contract. For example, you can add functionality such as token freezing, custom transaction fees, or governance mechanisms.

These features are implemented by extending the base DeployableOP_20 or OP_20 class and overriding its methods as needed.


Additional Documentation

For more detailed explanations on specific topics related to the OPNet runtime, refer to the following documentation:


License

This project is licensed under the MIT License. View the full license here.

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •