* feat: add token example

* feat: code splitted package

* feat: use updated apis

Imported from CityOfZion/neo-storm (e2bab450d7355b559ae2d70a87f557e8a6dbfff6).
This commit is contained in:
Jeroen Peeters 2018-08-22 18:23:19 +02:00 committed by Roman Khimov
parent 8bfaed0e4b
commit b3037cd598
3 changed files with 186 additions and 0 deletions

1
.gitignore vendored
View file

@ -13,6 +13,7 @@
# Added by CoZ developers # Added by CoZ developers
vendor/ vendor/
bin/ bin/
!examples/**/vendor
# text editors # text editors
# vscode # vscode

70
examples/token/token.go Normal file
View file

@ -0,0 +1,70 @@
package token_contract
import (
"token"
"github.com/CityOfZion/neo-storm/interop/storage"
"github.com/CityOfZion/neo-storm/interop/util"
)
const (
decimals = 8
multiplier = 100000000
)
var owner = util.FromAddress("AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y")
// CreateToken initializes the Token Interface for the Smart Contract to operate with
func CreateToken() token.Token {
return token.Token{
Name: "Awesome NEO Token",
Symbol: "ANT",
Decimals: decimals,
Owner: owner,
TotalSupply: 11000000 * multiplier,
CirculationKey: "TokenCirculation",
}
}
// Main function = contract entry
func Main(operation string, args []interface{}) interface{} {
token := CreateToken()
if operation == "name" {
return token.Name
}
if operation == "symbol" {
return token.Symbol
}
if operation == "decimals" {
return token.Decimals
}
// The following operations need ctx
ctx := storage.GetContext()
if operation == "totalSupply" {
return token.GetSupply(ctx)
}
if operation == "balanceOf" {
hodler := args[0].([]byte)
return token.BalanceOf(ctx, hodler)
}
if operation == "transfer" && CheckArgs(args, 3) {
from := args[0].([]byte)
to := args[1].([]byte)
amount := args[2].(int)
return token.Transfer(ctx, from, to, amount)
}
return true
}
// CheckArgs checks args array against a length indicator
func CheckArgs(args []interface{}, length int) bool {
if len(args) == length {
return true
}
return false
}

115
examples/token/vendor/token/token.go vendored Normal file
View file

@ -0,0 +1,115 @@
package token
import (
"github.com/CityOfZion/neo-storm/interop/engine"
"github.com/CityOfZion/neo-storm/interop/runtime"
"github.com/CityOfZion/neo-storm/interop/storage"
)
// Token holds all token info
type Token struct {
// Token name
Name string
// Ticker symbol
Symbol string
// Amount of decimals
Decimals int
// Token owner address
Owner []byte
// Total tokens * multiplier
TotalSupply int
// Storage key for circulation value
CirculationKey string
}
// TODO: Transfer event
// DoTransfer := action.RegisterAction("transfer", "from", "to", "amount")
// GetSupply gets the token totalSupply value from VM storage
func (t Token) GetSupply(ctx storage.Context) interface{} {
return storage.Get(ctx, t.CirculationKey)
}
// BalanceOf gets the token balance of a specific address
func (t Token) BalanceOf(ctx storage.Context, hodler []byte) interface{} {
return storage.Get(ctx, hodler)
}
// Transfer token from one user to another
func (t Token) Transfer(ctx storage.Context, from []byte, to []byte, amount int) 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 := storage.Get(ctx, to).(int)
totalAmountTo := amountTo + amount
storage.Put(ctx, to, totalAmountTo)
// DoTransfer(from, to, amount)
return true
}
// CanTransfer returns the amount it can transfer
func (t Token) CanTransfer(ctx storage.Context, from []byte, to []byte, amount int) int {
if len(to) != 20 && !IsUsableAddress(from) {
return -1
}
amountFrom := storage.Get(ctx, from).(int)
if amountFrom < amount {
return -1
}
// Tell Transfer the result is equal - special case since it uses Delete
if amountFrom == amount {
return 0
}
// return amountFrom value back to Transfer, reduces extra Get
return amountFrom
}
// IsUsableAddress checks if the sender is either the correct NEO address or SC address
func IsUsableAddress(addr []byte) bool {
if len(addr) == 20 {
if runtime.CheckWitness(addr) {
return true
}
// Check if a smart contract is calling scripthash
callingScriptHash := engine.GetCallingScriptHash()
if EqualAddresses(callingScriptHash, addr) {
return true
}
}
return false
}
// EqualAddresses compares two addresses if they're equal
// also returns false if one of the two - or both - aren't actual addresses
func EqualAddresses(a []byte, b []byte) bool {
aLen := len(a)
bLen := len(b)
if aLen != bLen || aLen != 20 || bLen != 20 {
return false
}
for i := 0; i < aLen; i++ {
if a[i] != b[i] {
return false
}
}
return true
}