Developers
  • SWT PROTOCOL
    • Introduction
    • Accounts
    • Transactions
    • Fees
    • Smart Contracts
  • GETTING STARTED
    • Network Node
      • Introduction
      • STEP 1:RENTING A LINUX VPS
      • STEP 2:INSTALLATION OF PUTTY
      • STEP 3:INSTALLATION OF FILEZILLA
      • STEP 4:VPS CONNECTION AND LINUX CONFIGURATION WITH PUTTY (SSH)
      • STEP 5:HOW TO SECURE YOUR VPS
      • STEP 6:USING TMUX THROUGH PUTTY
      • STEP 7:UPLOAD OF THE SWT SOFTWARE WITH FILEZILLA
      • STEP 8:EXTRACT THE SWT SOFTWARE FOLDER
      • STEP 9:RUNNING THE SWT NODE THROUGH TMUX
      • STEP 10:RUNNING THE MONITORING TOOLS
  • API REFERENCE
    • Apache Thrift API
      • Transactions
      • Blocks
      • Smart contract
      • Tokens
      • Wallets
      • Sync info
      • Data structures
    • REST API
      • GetBlocks()
      • GetNodeInfo()
      • GetBalance()
      • GetWalletInfo()
      • GetTokenBalance()
      • GetTransactionsByWallet()
      • GetTransactionInfo()
      • GetEstimatedFee()
      • GetContractByAddress()
      • GetContractFromTransaction()
      • GetContractMethods()
      • ContractValidation()
      • ContractCall()
      • TransactionPack()
      • TransactionExec()
  • SMART CONTRACTS
    • Creating "Hello-world" Smart Contract
    • Smart Contract Methods
    • Smart Contract Standarts
      • Token Smart Contract
      • Escrow Smart Contract
      • Stable coin Token
  • HOW TO REST API
    • Introduction
    • Retrieve a balance from the blockchain
    • Request a specific transaction from the blockchain
    • Sending Transactions to the SWT Blockchain
    • Validating and deploying a Smart Contract with REST API
Powered by GitBook
On this page
  1. SMART CONTRACTS
  2. Smart Contract Standarts

Token Smart Contract

The code below is an example and requires further refinement for specific business tasks.

Interface BasicStandard is necessary to create a token (implementation is mandatory and provided below).

public interface BasicStandard {

   String getName();

   String getSymbol();

   int getDecimal();

   boolean setFrozen(boolean frozen);

   String totalSupply();

   String balanceOf(String owner);

   String allowance(String owner, String spender);

   boolean transfer(String to, String amount);

   boolean transferFrom(String from, String to, String amount);

   void approve(String spender, String amount);

   boolean burn(String amount);

}

As well as interface ExtensionStandard (Implementation is not mandatory, but recommended and is provided below).

public interface ExtensionStandard extends BasicStandard {

   void register();

   boolean buyTokens(String amount);

}

Further is the example of a token implementation according to SWT standard.

Examples sets the following in the class constructor:

  • Token name (name)

  • Token symbol (symbol)

  • Number of decimals (decimal)

  • Public key of the token owner (owner)

  • Total number of tokens (totalCoins)

Examples of implementation of Interfaces BasicStandard and ExtensionsStandard are provided below.

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import com.credits.scapi.annotations.*;
import com.credits.scapi.v0.*;

import static java.math.BigDecimal.ROUND_FLOOR;
import static java.math.BigDecimal.ZERO;

public class Token12 extends SmartContract implements ExtensionStandard {

    private final String owner;
    private final BigDecimal tokenCost;
    private final int decimal;
    HashMap<String, BigDecimal> balances;
    private String name;
    private String symbol;
    private BigDecimal totalCoins;
    private HashMap<String, Map<String, BigDecimal>> allowed;
    private boolean frozen;

    public Token12() {
        super();
        name = "1";
        symbol = "12";
        decimal = 1;
        tokenCost = new BigDecimal(0).setScale(decimal, ROUND_FLOOR);
        totalCoins = new BigDecimal(100).setScale(decimal, ROUND_FLOOR);
        owner = initiator;
        allowed = new HashMap<>();
        balances = new HashMap<>();
        balances.put(owner, new BigDecimal(100L).setScale(decimal, ROUND_FLOOR));
    }

    @Override
    public int getDecimal() {
        return decimal;
    }

    @Override
    public void register() {
        balances.putIfAbsent(initiator, ZERO.setScale(decimal, ROUND_FLOOR));
    }

    @Override
    public boolean setFrozen(boolean isFrozen) {
        if (!initiator.equals(owner)) {
            throw new RuntimeException("unable change frozen state! The wallet "+ initiator + " is not owner");
        }
        this.frozen = isFrozen;
        return true;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getSymbol() {
        return symbol;
    }

    @Override
    public String totalSupply() {
        return totalCoins.toString();
    }

    @Override
    public String balanceOf(String owner) {
        return getTokensBalance(owner).toString();
    }

    @Override
    public String allowance(String owner, String spender) {
        if (allowed.get(owner) == null) {
            return "0";
        }
        BigDecimal amount = allowed.get(owner).get(spender);
        return amount != null ? amount.toString() : "0";
    }

    @Override
    public boolean transfer(String to, String amount) {
        contractIsNotFrozen();
        if (!to.equals(initiator)) {
            BigDecimal decimalAmount = toBigDecimal(amount);
            BigDecimal sourceBalance = getTokensBalance(initiator);
            BigDecimal targetTokensBalance = getTokensBalance(to);
            if (decimalAmount.compareTo(ZERO.setScale(decimal, ROUND_FLOOR)) < 0) {
                throw new RuntimeException("invalid amount");
            }
            if(targetTokensBalance == null)
            {
                targetTokensBalance = new BigDecimal(0).setScale(decimal, ROUND_FLOOR);
            }
            if (sourceBalance.compareTo(decimalAmount) < 0) {
                throw new RuntimeException("the wallet"  + initiator + "doesn't have enough tokens to transfer");
            }
            balances.put(initiator, sourceBalance.subtract(decimalAmount));
            balances.put(to, targetTokensBalance.add(decimalAmount));
        }
        return true;
    }

    @Override
    public boolean transferFrom(String from, String to, String amount) {
        contractIsNotFrozen();

        if (!from.equals(to)) {
            BigDecimal sourceBalance = getTokensBalance(from);
            BigDecimal targetTokensBalance = getTokensBalance(to);
            if(targetTokensBalance == null)
            {
                targetTokensBalance = new BigDecimal(0).setScale(decimal, ROUND_FLOOR);
            }
            BigDecimal decimalAmount = toBigDecimal(amount);
            if (decimalAmount.compareTo(ZERO.setScale(decimal, ROUND_FLOOR)) < 0) {
                throw new RuntimeException("invalid amount");
            }
            if (sourceBalance.compareTo(decimalAmount) < 0)
                throw new RuntimeException("unable transfer tokens! The balance of " + from + " less then " + amount);

            Map<String, BigDecimal> spender = allowed.get(from);
            if (spender == null || !spender.containsKey(initiator))
                throw new RuntimeException("unable transfer tokens! The wallet " + from + " not allow transfer tokens for " + to);

            BigDecimal allowTokens = spender.get(initiator);
            if (allowTokens.compareTo(decimalAmount) < 0) {
                throw new RuntimeException("unable transfer tokens! Not enough allowed tokens. For the wallet " + initiator + " allow only " + allowTokens + " tokens");
            }

            spender.put(initiator, allowTokens.subtract(decimalAmount));
            balances.put(from, sourceBalance.subtract(decimalAmount));
            balances.put(to, targetTokensBalance.add(decimalAmount));
        }
        return true;
    }

    @Override
    public void approve(String spender, String amount) {
        initiatorIsRegistered();
        BigDecimal decimalAmount = toBigDecimal(amount);
        if (decimalAmount.compareTo(ZERO.setScale(decimal, ROUND_FLOOR)) < 0) {
                throw new RuntimeException("invalid amount");
        }
        Map<String, BigDecimal> initiatorSpenders = allowed.get(initiator);
        if (initiatorSpenders == null) {
            Map<String, BigDecimal> newSpender = new HashMap<>();
            newSpender.put(spender, decimalAmount);
            allowed.put(initiator, newSpender);
        } else {
            BigDecimal spenderAmount = initiatorSpenders.get(spender);
            initiatorSpenders.put(spender, spenderAmount == null ? decimalAmount : spenderAmount.add(decimalAmount));
        }
    }

    @Override
    public boolean burn(String amount) {
        contractIsNotFrozen();
        BigDecimal decimalAmount = toBigDecimal(amount);
        if (decimalAmount.compareTo(ZERO.setScale(decimal, ROUND_FLOOR)) < 0) {
            throw new RuntimeException("invalid amount");
        }
        if (!initiator.equals(owner))
            throw new RuntimeException("can not burn tokens! The wallet " + initiator + " is not owner");
        if (totalCoins.compareTo(decimalAmount) < 0) totalCoins = ZERO;
        else totalCoins = totalCoins.subtract(decimalAmount);
        return true;
    }

    public void payable(String amount, String currency) {
        contractIsNotFrozen();
        BigDecimal decimalAmount = toBigDecimal(amount);
        if (totalCoins.compareTo(decimalAmount) < 0) throw new RuntimeException("not enough tokes to buy");
        balances.put(initiator, Optional.ofNullable(balances.get(initiator)).orElse(ZERO).add(decimalAmount));
        totalCoins = totalCoins.subtract(decimalAmount);
    }

    @Override
    public boolean buyTokens(String amount) {
        return false;
    }

    private void contractIsNotFrozen() {
        if (frozen) throw new RuntimeException("unavailable action! The smart-contract is frozen");
    }

    private void initiatorIsRegistered() {
        if (!balances.containsKey(initiator))
            throw new RuntimeException("unavailable action! The wallet " + initiator + " is not registered");
    }

    private BigDecimal toBigDecimal(String stringValue) {
        return new BigDecimal(stringValue).setScale(decimal, ROUND_FLOOR);
    }

    private BigDecimal getTokensBalance(String address) {
        return balances.get(address);
    }
}
PreviousSmart Contract StandartsNextEscrow Smart Contract

Last updated 1 year ago