MIGRATE TO N3

Introducing:
Neo X

Neo’s EVM-based sidechain is here.
Find out what opportunities await.
Latest News:
All in One - All in Neo
All in One - All in Neo
Interoperability
Native Oracles
Self-Sovereign ID
Decentralized Storage
Neo Name Service
One Block Finality
Best-In-Class Tooling
Smart Contracts
Multi-Language
Neo is
new again
After four years of stable MainNet operation, Neo is undergoing its biggest evolution as it migrates to N3 - The most powerful and feature rich version of the Neo blockchain to date.
Learn More
Building Blocks for the Next Generation Internet
Neo provides a full stack of features out of the box, but doesn't keep you boxed in.

Native functionality provides all the infrastructure you need to build complete decentralized applications, while advanced interoperability allows you to harness the power of the global blockchain ecosystem.
Learn More
One Block Finality
dBFT consensus mechanism guarantees fast and efficient finality in a single block.
Oracle
A built-in oracle enabling secured access to any off-chain data.
NeoFS
A distributed data storage solution made for scalability and privacy.
Smart Contracts
Write your smart contracts in C#, Go, Python, Java, or TypeScript.
Neo Name Service
A decentralized .neo domain name service for next-gen internet web applications.
Interoperability
Poly.Network enabled cross-chain interoperability with Ethereum, Binance Chain, and more.
NeoID
A set of self-sovereign decentralized identity solution standards.
Blockchain
You know
Write smart contracts in a language you already love
Learn More
Python
C#
Go
Typescript
Java
Python
Python

from boa3.builtin.contract import Nep17TransferEvent, abort

@metadata
def manifest_metadata() -> NeoMetadata:
    meta = NeoMetadata()
    meta.author = "coz"
    return meta

OWNER = UInt160(b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
TOKEN_TOTAL_SUPPLY = 100_000_000 * 100_000_000  # 10m total supply * 10^8 (decimals)

# Events
on_transfer = Nep17TransferEvent

@public
def transfer(from_address: UInt160, to_address: UInt160, amount: int, data: Any) -> bool:
    assert len(from_address) == 20 and len(to_address) == 20
    assert amount >= 0

    # The function MUST return false if the from account balance does not have enough tokens to spend.
    from_balance = get(from_address).to_int()
    if from_balance < amount:
        return False

    # The function should check whether the from address equals the caller contract hash.
    if from_address != calling_script_hash:
        if not check_witness(from_address):
            return False

    # skip balance changes if transferring to yourself or transferring 0 cryptocurrency
    if from_address != to_address and amount != 0:
        if from_balance == amount:
            delete(from_address)
        else:
            put(from_address, from_balance - amount)

        to_balance = get(to_address).to_int()
        put(to_address, to_balance + amount)

    on_transfer(from_address, to_address, amount)
    # if the to_address is a smart contract, it must call the contract's onPayment method
    post_transfer(from_address, to_address, amount, data)
    return True

C#
C#

using Neo;
using Neo.SmartContract;
using Neo.SmartContract.Framework;
using Neo.SmartContract.Framework.Attributes;
using Neo.SmartContract.Framework.Native;
using Neo.SmartContract.Framework.Services;
using System;
using System.Numerics;

namespace Desktop
{
    [ManifestExtra("Author", "Neo")]
    [ManifestExtra("Email", "dev@neo.org")]
    [ManifestExtra("Description", "This is a contract example")]
    [ContractSourceCode("https://github.com/neo-project/neo-devpack-dotnet/tree/master/src/Neo.SmartContract.Template")]
    public class Contract1 : SmartContract
    {
        //TODO: Replace it with your own address.
        [InitialValue("NiNmXL8FjEUEs1nfX9uHFBNaenxDHJtmuB", ContractParameterType.Hash160)]
        static readonly UInt160 Owner = default;

        private static bool IsOwner() => Runtime.CheckWitness(Owner);

        // When this contract address is included in the transaction signature,
        // this method will be triggered as a VerificationTrigger to verify that the signature is correct.
        // For example, this method needs to be called when withdrawing token from the contract.
        public static bool Verify() => IsOwner();

        // TODO: Replace it with your methods.
        public static string MyMethod()
        {
            return Storage.Get(Storage.CurrentContext, "Hello");
        }

        public static void _deploy(object data, bool update)
        {
            if (update) return;

            // It will be executed during deploy
            Storage.Put(Storage.CurrentContext, "Hello", "World");
        }

        public static void Update(ByteString nefFile, string manifest)
        {
            if (!IsOwner()) throw new Exception("No authorization.");
            ContractManagement.Update(nefFile, manifest, null);
        }

        public static void Destroy()
        {
            if (!IsOwner()) throw new Exception("No authorization.");
            ContractManagement.Destroy();
        }
    }
}

Go
Go

package nep17Contract

var (
    token nep17.Token
    ctx   storage.Context
)
// initializes the Token Interface and storage context
func init() {
    token = nep17.Token{
        ...
        Name:           "Nep17 example",
        Owner:          util.FromAddress("NdHjSPVnw99RDMCoJdCnAcjkE23gvqUeg2"),
        TotalSupply:    10000000000000000
    }
    ctx = storage.GetContext()
}
// Transfer token from one user to another
func (t Token) Transfer(ctx storage.Context, from, to interop.Hash160, amount int, data interface{}) bool {
    amountFrom := t.CanTransfer(ctx, from, to, amount)
    if amountFrom == -1 {
        return false
    }

    if amountFrom == 0 {
        storage.Delete(ctx, from)
    }

    if amountFrom > 0 {
        diff := amountFrom - amount
        storage.Put(ctx, from, diff)
    }

    amountTo := getIntFromDB(ctx, to)
    totalAmountTo := amountTo + amount
    storage.Put(ctx, to, totalAmountTo)
    runtime.Notify("Transfer", from, to, amount)
    if to != nil && management.GetContract(to) != nil {
        contract.Call(to, "onNEP17Payment", contract.All, from, amount, data)
    }
    return true
}

Typescript
Typescript

import {  SmartContract} from '@neo-one/smart-contract';

export class NEP17Contract extends SmartContract {
  public readonly properties = {
    name: 'NEO•ONE NEP17 Example',
    groups: [],
    trusts: '*',
    permissions: [],
  };
  public readonly name = 'NEO•ONE NEP17 Example';
  public readonly decimals = 8;

  private readonly notifyTransfer = createEventNotifier<Address | undefined, Address | undefined, Fixed<8>>(
    'Transfer', 'from', 'to', 'amount',
  );

  public transfer(from: Address, to: Address, amount: Fixed<8>, data?: any): boolean {
    if (amount < 0) {throw new Error(`Amount must be greater than 0: ${amount}`);}

    const fromBalance = this.balanceOf(from);
    if (fromBalance < amount) { return false; }

    const contract = Contract.for(to);
    if (contract !== undefined && !Address.isCaller(to)) {
      const smartContract = SmartContract.for<TokenPayableContract>(to);
      if (!smartContract.approveReceiveTransfer(from, amount, this.address)) {
        return false;
      }
    }

    const toBalance = this.balanceOf(to);
    this.balances.set(from, fromBalance - amount);
    this.balances.set(to, toBalance + amount);
    this.notifyTransfer(from, to, amount);

    if (contract !== undefined) {
      const smartContract = SmartContract.for<TokenPayableContract>(to);
      smartContract.onNEP17Payable(from, amount, data);
    }
    return true;
  }
}

Java
Java

package io.neow3j.examples.contractdevelopment.contracts;

import static io.neow3j.devpack.StringLiteralHelper.addressToScriptHash;

import io.neow3j.devpack.*

@ManifestExtra(key = "name", value = "FungibleToken")
@ManifestExtra(key = "author", value = "AxLabs")
@SupportedStandards("NEP-17")
@Permission(contract = "fffdc93764dbaddd97c48f252a53ea4643faa3fd") // ContractManagement
public class FungibleToken {

    static final Hash160 owner = addressToScriptHash("NM7Aky765FG8NhhwtxjXRx7jEL1cnw7PBP");

    @DisplayName("Transfer")
    static Event3Args onTransfer;

    static final int initialSupply = 200_000_000;
    static final int decimals = 8;
    static final String assetPrefix = "asset";
    static final String totalSupplyKey = "totalSupply";
    static final StorageContext sc = Storage.getStorageContext();
    static final StorageMap assetMap = sc.createMap(assetPrefix);

    public static String symbol() {
        return "FGT";
    }

    public static int decimals() {
        return decimals;
    }

    public static int totalSupply() {
        return getTotalSupply();
    }

    static int getTotalSupply() {
        return Storage.getInteger(sc, totalSupplyKey);
    }

    public static boolean transfer(Hash160 from, Hash160 to, int amount, Object[] data)
            throws Exception {

        if (!Hash160.isValid(from) || !Hash160.isValid(to)) {
            throw new Exception("From or To address is not a valid address.");
        }
        if (amount < 0) {
            throw new Exception("The transfer amount was negative.");
        }
        if (!Runtime.checkWitness(from) && from != Runtime.getCallingScriptHash()) {
            throw new Exception("Invalid sender signature. The sender of the tokens needs to be "
                    + "the signing account.");
        }
        if (getBalance(from) < amount) {
            return false;
        }
        if (from != to && amount != 0) {
            deductFromBalance(from, amount);
            addToBalance(to, amount);
        }

        onTransfer.fire(from, to, amount);
        if (ContractManagement.getContract(to) != null) {
            Contract.call(to, "onNEP17Payment", CallFlags.All, data);
        }

        return true;
    }

    public static int balanceOf(Hash160 account) throws Exception {
        if (!Hash160.isValid(account)) {
            throw new Exception("Argument is not a valid address.");
        }
        return getBalance(account);
    }

    @OnDeployment
    public static void deploy(Object data, boolean update) throws Exception {
        throwIfSignerIsNotOwner();
        if (!update) {
            if (Storage.get(sc, totalSupplyKey) != null) {
                throw new Exception("Contract was already deployed.");
            }
            // Initialize supply
            Storage.put(sc, totalSupplyKey, initialSupply);
            // And allocate all tokens to the contract owner.
            assetMap.put(owner.toByteArray(), initialSupply);
        }
    }

    public static void update(ByteString script, String manifest) throws Exception {
        throwIfSignerIsNotOwner();
        if (script.length() == 0 && manifest.length() == 0) {
            throw new Exception("The new contract script and manifest must not be empty.");
        }
        ContractManagement.update(script, manifest);
    }

    public static void destroy() throws Exception {
        throwIfSignerIsNotOwner();
        ContractManagement.destroy();
    }

    @OnVerification
    public static boolean verify() throws Exception {
        throwIfSignerIsNotOwner();
        return true;
    }

    /**
     * Gets the address of the contract owner.
     *
     * @return the address of the contract owner.
     */
    public static Hash160 contractOwner() {
        return owner;
    }

    private static void throwIfSignerIsNotOwner() throws Exception {
        if (!Runtime.checkWitness(owner)) {
            throw new Exception("The calling entity is not the owner of this contract.");
        }
    }

    private static void addToBalance(Hash160 key, int value) {
        assetMap.put(key.toByteArray(), getBalance(key) + value);
    }

    private static void deductFromBalance(Hash160 key, int value) {
        int oldValue = getBalance(key);
        if (oldValue == value) {
            assetMap.delete(key.toByteArray());
        } else {
            assetMap.put(key.toByteArray(), oldValue - value);
        }
    }

    private static int getBalance(Hash160 key) {
        return assetMap.getInteger(key.toByteArray());
    }

}
    
Learn More
Dual
Tokens
Neo has a unique dual token model that separates governance from utility.
NEO token
GAS token
NEO token holders are the owners of the network and are able to participate in governance. NEO holders also receive passive distribution of the network utility token, GAS - No staking required. GAS rewards are increased for voting participation.

GAS is used to pay for network fees, smart contract deployments, and in dApp purchases.
NEO & GAS Calculator
A user with
500
would receive up to
0.44
Gas Per Month*
For holding NEO
17.52
Gas Per Month*
For Governance Participation
*estimate based on average 20% circulating NEO voting participation
On-chain
Governance
A dynamic on-chain council voted in by the NEO token holders.
N3 introduces the ability for NEO holders to vote in council members and consensus nodes that maintain the liveliness of the Neo network and adjust critical blockchain parameters.

GAS rewards are distributed to both voters and committee members.
On-chain
Governance
A dynamic on-chain council voted in by the NEO token holders.
N3 introduces the ability for NEO holders to vote in council members and consensus nodes that maintain the liveliness of the Neo network and adjust critical blockchain parameters.

GAS rewards are distributed to both voters and committee members.
On-chain
Governance
A dynamic on-chain council voted in by the NEO token holders.
N3 introduces the ability for NEO holders to vote in council members and consensus nodes that maintain the liveliness of the Neo network and adjust critical blockchain parameters.

GAS rewards are distributed to both voters and committee members.
Global
Contributors
Neo is a joint effort by community groups from all over the world.
3.4Kstars
3.4Kstars
988forks
988forks
388subscribers
388subscribers
NDG Enterprise GitHub NDG Enterprise Website NDG Tracker GitHub NDG Tracker Website COZ GitHub COZ Website NEO Research GitHub NEO Research Website Red4Sec GitHub Red4Sec Website AxLabs GitHub AxLabs Website NEO S.Petersburg Center GitHub NEO S.Petersburg Center Website NGD Shanghai GitHub NGD Shanghai Website NewEconoLab GitHub NewEconoLab Website NEXT GitHub NEXT Website
Join the Community
Explore the Ecosystem
Industry Partners