From ae3f15523c1608e17c8178601af8c6e183b130da Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Mon, 10 Aug 2020 13:42:02 +0300 Subject: [PATCH] examples: update examples Closes #1234 --- examples/engine/engine.go | 15 ++- examples/iterator/iterator.go | 4 +- examples/runtime/runtime.go | 54 ++++----- examples/storage/storage.go | 79 ++++--------- examples/token-sale/token_sale.go | 181 +++++++++++++++--------------- examples/token/nep5/nep5.go | 6 +- examples/token/token.go | 86 +++----------- 7 files changed, 165 insertions(+), 260 deletions(-) diff --git a/examples/engine/engine.go b/examples/engine/engine.go index 3fe1108c3..f94e29e03 100644 --- a/examples/engine/engine.go +++ b/examples/engine/engine.go @@ -4,19 +4,26 @@ import ( "github.com/nspcc-dev/neo-go/pkg/interop/runtime" ) -// Main is that famous Main() function, you know. -func Main() bool { +// NotifyScriptContainer sends runtime notification with script container hash +func NotifyScriptContainer() { tx := runtime.GetScriptContainer() runtime.Notify("Tx", tx.Hash) +} +// NotifyCallingScriptHash sends runtime notification with calling script hash +func NotifyCallingScriptHash() { callingScriptHash := runtime.GetCallingScriptHash() runtime.Notify("Calling", callingScriptHash) +} +// NotifyExecutingScriptHash sends runtime notification about executing script hash +func NotifyExecutingScriptHash() { execScriptHash := runtime.GetExecutingScriptHash() runtime.Notify("Executing", execScriptHash) +} +// NotifyEntryScriptHash sends notification about entry script hash +func NotifyEntryScriptHash() { entryScriptHash := runtime.GetEntryScriptHash() runtime.Notify("Entry", entryScriptHash) - - return true } diff --git a/examples/iterator/iterator.go b/examples/iterator/iterator.go index 96ccf73f1..fd5a0ad16 100644 --- a/examples/iterator/iterator.go +++ b/examples/iterator/iterator.go @@ -6,8 +6,8 @@ import ( "github.com/nspcc-dev/neo-go/pkg/interop/storage" ) -// Main is Main(), really. -func Main() bool { +// NotifyKeysAndValues sends notification with `foo` storage keys and values +func NotifyKeysAndValues() bool { iter := storage.Find(storage.GetContext(), []byte("foo")) values := iterator.Values(iter) keys := iterator.Keys(iter) diff --git a/examples/runtime/runtime.go b/examples/runtime/runtime.go index 4afc7f395..027d3b441 100644 --- a/examples/runtime/runtime.go +++ b/examples/runtime/runtime.go @@ -5,40 +5,23 @@ import ( "github.com/nspcc-dev/neo-go/pkg/interop/util" ) -// Check if the invoker of the contract is the specified owner -var owner = util.FromAddress("Nis7Cu1Qn6iBb8kbeQ5HgdZT7AsQPqywTC") +var ( + // Check if the invoker of the contract is the specified owner + owner = util.FromAddress("NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt") + trigger byte +) -// Main is something to be ran from outside. -func Main(operation string, args []interface{}) bool { - trigger := runtime.GetTrigger() - - // Log owner upon Verification trigger - if trigger == runtime.Verification { - return CheckWitness() - } - - // Discerns between log and notify for this test - if trigger == runtime.Application { - return handleOperation(operation, args) - } - - return false -} - -func handleOperation(operation string, args []interface{}) bool { - if operation == "log" { - return Log(args) - } - - if operation == "notify" { - return Notify(args) - } - - return false +// init initializes trigger before any other contract method is called +func init() { + trigger = runtime.GetTrigger() } // CheckWitness checks owner's witness func CheckWitness() bool { + // Log owner upon Verification trigger + if trigger != runtime.Verification { + return false + } if runtime.CheckWitness(owner) { runtime.Log("Verified Owner") } @@ -46,14 +29,19 @@ func CheckWitness() bool { } // Log logs given message -func Log(args []interface{}) bool { - message := args[0].(string) +func Log(message string) bool { + if trigger != runtime.Application { + return false + } runtime.Log(message) return true } // Notify notifies about given message -func Notify(args []interface{}) bool { - runtime.Notify("Event", args[0]) +func Notify(event interface{}) bool { + if trigger != runtime.Application { + return false + } + runtime.Notify("Event", event) return true } diff --git a/examples/storage/storage.go b/examples/storage/storage.go index bf2c6f522..9b43c45b6 100644 --- a/examples/storage/storage.go +++ b/examples/storage/storage.go @@ -5,78 +5,39 @@ import ( "github.com/nspcc-dev/neo-go/pkg/interop/storage" ) -// Main is a very useful function. -func Main(operation string, args []interface{}) interface{} { - if operation == "put" { - return Put(args) - } +// ctx holds storage context for contract methods +var ctx storage.Context - if operation == "get" { - return Get(args) - } - - if operation == "delete" { - return Delete(args) - } - - if operation == "find" { - return Find(args) - } - - return false +// init inits storage context before any other contract method is called +func init() { + ctx = storage.GetContext() } // Put puts value at key. -func Put(args []interface{}) interface{} { - ctx := storage.GetContext() - if checkArgs(args, 2) { - key := args[0].([]byte) - value := args[1].([]byte) - storage.Put(ctx, key, value) - return key - } - return false +func Put(key, value []byte) []byte { + storage.Put(ctx, key, value) + return key } // Get returns the value at passed key. -func Get(args []interface{}) interface{} { - ctx := storage.GetContext() - if checkArgs(args, 1) { - key := args[0].([]byte) - return storage.Get(ctx, key) - } - return false +func Get(key []byte) interface{} { + return storage.Get(ctx, key) } // Delete deletes the value at passed key. -func Delete(args []interface{}) interface{} { - ctx := storage.GetContext() - key := args[0].([]byte) +func Delete(key []byte) bool { storage.Delete(ctx, key) return true } -// Find returns an array of key-value pairs with key that matched the passed value. -func Find(args []interface{}) interface{} { - ctx := storage.GetContext() - if checkArgs(args, 1) { - value := args[0].([]byte) - iter := storage.Find(ctx, value) - result := []string{} - for iterator.Next(iter) { - val := iterator.Value(iter) - key := iterator.Key(iter) - result = append(result, key.(string)+":"+val.(string)) - } - return result +// Find returns an array of key-value pairs with key that matched the passed value +func Find(value []byte) []string { + iter := storage.Find(ctx, value) + result := []string{} + for iterator.Next(iter) { + val := iterator.Value(iter) + key := iterator.Key(iter) + result = append(result, key.(string)+":"+val.(string)) } - return false -} - -func checkArgs(args []interface{}, length int) bool { - if len(args) == length { - return true - } - - return false + return result } diff --git a/examples/token-sale/token_sale.go b/examples/token-sale/token_sale.go index 88e56acda..05a70462d 100644 --- a/examples/token-sale/token_sale.go +++ b/examples/token-sale/token_sale.go @@ -11,7 +11,12 @@ const ( multiplier = decimals * 10 ) -var owner = util.FromAddress("NNf7GXcNMFHU8pLvU84afYZCfzXDopy71M") +var ( + owner = util.FromAddress("NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt") + trigger byte + token TokenConfig + ctx storage.Context +) // TokenConfig holds information about the token we want to use for the sale. type TokenConfig struct { @@ -51,8 +56,8 @@ type TokenConfig struct { KYCKey []byte } -// NewTokenConfig returns the initialized TokenConfig. -func NewTokenConfig() TokenConfig { +// newTokenConfig returns the initialized TokenConfig. +func newTokenConfig() TokenConfig { return TokenConfig{ Name: "My awesome token", Symbol: "MAT", @@ -82,108 +87,91 @@ func getIntFromDB(ctx storage.Context, key []byte) int { return res } -// InCirculation return the amount of total tokens that are in circulation. -func (t TokenConfig) InCirculation(ctx storage.Context) int { - return getIntFromDB(ctx, t.CirculationKey) +// InCirculation returns the amount of total tokens that are in circulation. +func InCirculation() int { + return getIntFromDB(ctx, token.CirculationKey) } // AddToCirculation sets the given amount as "in circulation" in the storage. -func (t TokenConfig) AddToCirculation(ctx storage.Context, amount int) bool { - supply := getIntFromDB(ctx, t.CirculationKey) +func AddToCirculation(amount int) bool { + supply := getIntFromDB(ctx, token.CirculationKey) supply += amount - storage.Put(ctx, t.CirculationKey, supply) + storage.Put(ctx, token.CirculationKey, supply) return true } -// TokenSaleAvailableAmount returns the total amount of available tokens left +// AvailableAmount returns the total amount of available tokens left // to be distributed. -func (t TokenConfig) TokenSaleAvailableAmount(ctx storage.Context) int { - inCirc := getIntFromDB(ctx, t.CirculationKey) - return t.TotalSupply - inCirc +func AvailableAmount() int { + inCirc := getIntFromDB(ctx, token.CirculationKey) + return token.TotalSupply - inCirc } -// Main smart contract entry point. -func Main(operation string, args []interface{}) interface{} { - var ( - trigger = runtime.GetTrigger() - cfg = NewTokenConfig() - ctx = storage.GetContext() - ) +// init initializes runtime trigger, TokenConfig and storage context before any +// other contract method is called +func init() { + trigger = runtime.GetTrigger() + token = newTokenConfig() + ctx = storage.GetContext() +} +// checkOwnerWitness is a helper function which checks whether the invoker is the +// owner of the contract. +func checkOwnerWitness() bool { // This is used to verify if a transfer of system assets (NEO and Gas) // involving this contract's address can proceed. - if trigger == runtime.Verification { - // Check if the invoker is the owner of the contract. - if runtime.CheckWitness(cfg.Owner) { - return true - } - // Otherwise TODO - return false - } if trigger == runtime.Application { - return handleOperation(operation, args, ctx, cfg) - } - return true -} - -func handleOperation(op string, args []interface{}, ctx storage.Context, cfg TokenConfig) interface{} { - // NEP-5 handlers - if op == "name" { - return cfg.Name - } - if op == "decimals" { - return cfg.Decimals - } - if op == "symbol" { - return cfg.Symbol - } - if op == "totalSupply" { - return getIntFromDB(ctx, cfg.CirculationKey) - } - if op == "balanceOf" { - if len(args) == 1 { - return getIntFromDB(ctx, args[0].([]byte)) - } - } - if op == "transfer" { - if len(args) != 3 { - return false - } - from := args[0].([]byte) - to := args[1].([]byte) - amount := args[2].(int) - return transfer(cfg, ctx, from, to, amount) - } - if op == "transferFrom" { - if len(args) != 3 { - return false - } - from := args[0].([]byte) - to := args[1].([]byte) - amount := args[2].(int) - return transferFrom(cfg, ctx, from, to, amount) - } - if op == "approve" { - if len(args) != 3 { - return false - } - from := args[0].([]byte) - to := args[1].([]byte) - amount := args[2].(int) - return approve(ctx, from, to, amount) - } - if op == "allowance" { - if len(args) != 2 { - return false - } - from := args[0].([]byte) - to := args[1].([]byte) - return allowance(ctx, from, to) + // Check if the invoker is the owner of the contract. + return runtime.CheckWitness(token.Owner) } return false } -func transfer(cfg TokenConfig, ctx storage.Context, from, to []byte, amount int) bool { +// Name returns the token name +func Name() interface{} { + if trigger != runtime.Application { + return false + } + return token.Name +} + +// Decimals returns the token decimals +func Decimals() interface{} { + if trigger != runtime.Application { + return false + } + return token.Decimals +} + +// Symbol returns the token symbol +func Symbol() interface{} { + if trigger != runtime.Application { + return false + } + return token.Symbol +} + +// TotalSupply returns the token total supply value +func TotalSupply() interface{} { + if trigger != runtime.Application { + return false + } + return getIntFromDB(ctx, token.CirculationKey) +} + +// BalanceOf returns the amount of token on the specified address +func BalanceOf(holder []byte) interface{} { + if trigger != runtime.Application { + return false + } + return getIntFromDB(ctx, holder) +} + +// Transfer transfers specified amount of token from one user to another +func Transfer(from, to []byte, amount int) bool { + if trigger != runtime.Application { + return false + } if amount <= 0 || len(to) != 20 || !runtime.CheckWitness(from) { return false } @@ -203,7 +191,13 @@ func transfer(cfg TokenConfig, ctx storage.Context, from, to []byte, amount int) return true } -func transferFrom(cfg TokenConfig, ctx storage.Context, from, to []byte, amount int) bool { +// TransferFrom transfers specified amount of token from one user to another. +// It differs from Transfer in that it use allowance value to store the amount +// of token available to transfer. +func TransferFrom(from, to []byte, amount int) bool { + if trigger != runtime.Application { + return false + } if amount <= 0 { return false } @@ -234,8 +228,9 @@ func transferFrom(cfg TokenConfig, ctx storage.Context, from, to []byte, amount return true } -func approve(ctx storage.Context, owner, spender []byte, amount int) bool { - if !runtime.CheckWitness(owner) || amount < 0 { +// Approve stores token transfer data if the owner has enough token to send. +func Approve(owner, spender []byte, amount int) bool { + if !checkOwnerWitness() || amount < 0 { return false } if len(spender) != 20 { @@ -254,7 +249,11 @@ func approve(ctx storage.Context, owner, spender []byte, amount int) bool { return true } -func allowance(ctx storage.Context, from, to []byte) int { +// Allowance returns allowance value for specified sender and receiver. +func Allowance(from, to []byte) interface{} { + if trigger != runtime.Application { + return false + } key := append(from, to...) return getIntFromDB(ctx, key) } diff --git a/examples/token/nep5/nep5.go b/examples/token/nep5/nep5.go index 79f7b7692..8f5d35a5d 100644 --- a/examples/token/nep5/nep5.go +++ b/examples/token/nep5/nep5.go @@ -34,12 +34,12 @@ func getIntFromDB(ctx storage.Context, key []byte) int { } // GetSupply gets the token totalSupply value from VM storage -func (t Token) GetSupply(ctx storage.Context) interface{} { +func (t Token) GetSupply(ctx storage.Context) int { return getIntFromDB(ctx, []byte(t.CirculationKey)) } // BalanceOf gets the token balance of a specific address -func (t Token) BalanceOf(ctx storage.Context, holder []byte) interface{} { +func (t Token) BalanceOf(ctx storage.Context, holder []byte) int { return getIntFromDB(ctx, holder) } @@ -104,7 +104,7 @@ func IsUsableAddress(addr []byte) bool { return false } -// Mint initial supply of tokens. +// Mint initial supply of tokens func (t Token) Mint(ctx storage.Context, to []byte) bool { if !IsUsableAddress(t.Owner) { return false diff --git a/examples/token/token.go b/examples/token/token.go index 1bacf8e72..0925b4fd1 100644 --- a/examples/token/token.go +++ b/examples/token/token.go @@ -11,11 +11,16 @@ const ( multiplier = 100000000 ) -var owner = util.FromAddress("NMipL5VsNoLUBUJKPKLhxaEbPQVCZnyJyB") +var ( + owner = util.FromAddress("NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt") + token nep5.Token + ctx storage.Context +) -// createToken initializes the Token Interface for the Smart Contract to operate with -func createToken() nep5.Token { - return nep5.Token{ +// init initializes the Token Interface and storage context for the Smart +// Contract to operate with +func init() { + token = nep5.Token{ Name: "Awesome NEO Token", Symbol: "ANT", Decimals: decimals, @@ -23,95 +28,40 @@ func createToken() nep5.Token { TotalSupply: 11000000 * multiplier, CirculationKey: "TokenCirculation", } -} - -// Main function = contract entry -func Main(operation string, args []interface{}) interface{} { - if operation == "name" { - return Name() - } - if operation == "symbol" { - return Symbol() - } - if operation == "decimals" { - return Decimals() - } - - if operation == "totalSupply" { - return TotalSupply() - } - - if operation == "balanceOf" { - hodler := args[0].([]byte) - return BalanceOf(hodler) - } - - if operation == "transfer" && checkArgs(args, 3) { - from := args[0].([]byte) - to := args[1].([]byte) - amount := args[2].(int) - return Transfer(from, to, amount) - } - - if operation == "mint" && checkArgs(args, 1) { - addr := args[0].([]byte) - return Mint(addr) - } - - 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 + ctx = storage.GetContext() } // Name returns the token name func Name() string { - t := createToken() - return t.Name + return token.Name } // Symbol returns the token symbol func Symbol() string { - t := createToken() - return t.Symbol + return token.Symbol } // Decimals returns the token decimals func Decimals() int { - t := createToken() - return t.Decimals + return token.Decimals } // TotalSupply returns the token total supply value -func TotalSupply() interface{} { - t := createToken() - ctx := storage.GetContext() - return t.GetSupply(ctx) +func TotalSupply() int { + return token.GetSupply(ctx) } // BalanceOf returns the amount of token on the specified address func BalanceOf(holder []byte) interface{} { - t := createToken() - ctx := storage.GetContext() - return t.BalanceOf(ctx, holder) + return token.BalanceOf(ctx, holder) } // Transfer token from one user to another func Transfer(from []byte, to []byte, amount int) bool { - t := createToken() - ctx := storage.GetContext() - return t.Transfer(ctx, from, to, amount) + return token.Transfer(ctx, from, to, amount) } // Mint initial supply of tokens func Mint(to []byte) bool { - t := createToken() - ctx := storage.GetContext() - return t.Mint(ctx, to) + return token.Mint(ctx, to) }