Merge pull request #1296 from nspcc-dev/smartcontract/examples

examples: update examples
This commit is contained in:
Roman Khimov 2020-08-11 19:09:13 +03:00 committed by GitHub
commit c3f7a419a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 248 additions and 275 deletions

View file

@ -60,8 +60,16 @@ const (
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime" import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
func Main(op string, args []interface{}) { var notificationName string
runtime.Notify("Hello world!")
// init initializes notificationName before calling any other smart-contract method
func init() {
notificationName = "Hello world!"
}
// RuntimeNotify sends runtime notification with "Hello world!" name
func RuntimeNotify(args []interface{}) {
runtime.Notify(notificationName, args)
}` }`
// cosignersSeparator is a special value which is used to distinguish // cosignersSeparator is a special value which is used to distinguish
// parameters and cosigners for invoke* commands // parameters and cosigners for invoke* commands
@ -325,6 +333,17 @@ func initSmartContract(ctx *cli.Context) error {
m := ProjectConfig{ m := ProjectConfig{
SupportedStandards: []string{}, SupportedStandards: []string{},
Events: []manifest.Event{
{
Name: "Hello world!",
Parameters: []manifest.Parameter{
{
Name: "args",
Type: smartcontract.ArrayType,
},
},
},
},
} }
b, err := yaml.Marshal(m) b, err := yaml.Marshal(m)
if err != nil { if err != nil {
@ -369,6 +388,7 @@ func contractCompile(ctx *cli.Context) error {
return err return err
} }
o.ContractFeatures = conf.GetFeatures() o.ContractFeatures = conf.GetFeatures()
o.ContractEvents = conf.Events
o.ContractSupportedStandards = conf.SupportedStandards o.ContractSupportedStandards = conf.SupportedStandards
} }

View file

@ -4,19 +4,26 @@ import (
"github.com/nspcc-dev/neo-go/pkg/interop/runtime" "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
) )
// Main is that famous Main() function, you know. // NotifyScriptContainer sends runtime notification with script container hash
func Main() bool { func NotifyScriptContainer() {
tx := runtime.GetScriptContainer() tx := runtime.GetScriptContainer()
runtime.Notify("Tx", tx.Hash) runtime.Notify("Tx", tx.Hash)
}
// NotifyCallingScriptHash sends runtime notification with calling script hash
func NotifyCallingScriptHash() {
callingScriptHash := runtime.GetCallingScriptHash() callingScriptHash := runtime.GetCallingScriptHash()
runtime.Notify("Calling", callingScriptHash) runtime.Notify("Calling", callingScriptHash)
}
// NotifyExecutingScriptHash sends runtime notification about executing script hash
func NotifyExecutingScriptHash() {
execScriptHash := runtime.GetExecutingScriptHash() execScriptHash := runtime.GetExecutingScriptHash()
runtime.Notify("Executing", execScriptHash) runtime.Notify("Executing", execScriptHash)
}
// NotifyEntryScriptHash sends notification about entry script hash
func NotifyEntryScriptHash() {
entryScriptHash := runtime.GetEntryScriptHash() entryScriptHash := runtime.GetEntryScriptHash()
runtime.Notify("Entry", entryScriptHash) runtime.Notify("Entry", entryScriptHash)
return true
} }

View file

@ -0,0 +1,8 @@
hasstorage: false
ispayable: false
supportedstandards: []
events:
- name: Tx
parameters:
- name: txHash
type: ByteString

View file

@ -6,8 +6,8 @@ import (
"github.com/nspcc-dev/neo-go/pkg/interop/storage" "github.com/nspcc-dev/neo-go/pkg/interop/storage"
) )
// Main is Main(), really. // NotifyKeysAndValues sends notification with `foo` storage keys and values
func Main() bool { func NotifyKeysAndValues() bool {
iter := storage.Find(storage.GetContext(), []byte("foo")) iter := storage.Find(storage.GetContext(), []byte("foo"))
values := iterator.Values(iter) values := iterator.Values(iter)
keys := iterator.Keys(iter) keys := iterator.Keys(iter)

View file

@ -0,0 +1,12 @@
hasstorage: true
ispayable: false
supportedstandards: []
events:
- name: found storage values
parameters:
- name: values
type: Any
- name: found storage keys
parameters:
- name: keys
type: Any

View file

@ -5,40 +5,23 @@ import (
"github.com/nspcc-dev/neo-go/pkg/interop/util" "github.com/nspcc-dev/neo-go/pkg/interop/util"
) )
var (
// Check if the invoker of the contract is the specified owner // Check if the invoker of the contract is the specified owner
var owner = util.FromAddress("Nis7Cu1Qn6iBb8kbeQ5HgdZT7AsQPqywTC") owner = util.FromAddress("NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt")
trigger byte
)
// Main is something to be ran from outside. // init initializes trigger before any other contract method is called
func Main(operation string, args []interface{}) bool { func init() {
trigger := runtime.GetTrigger() 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
} }
// CheckWitness checks owner's witness // CheckWitness checks owner's witness
func CheckWitness() bool { func CheckWitness() bool {
// Log owner upon Verification trigger
if trigger != runtime.Verification {
return false
}
if runtime.CheckWitness(owner) { if runtime.CheckWitness(owner) {
runtime.Log("Verified Owner") runtime.Log("Verified Owner")
} }
@ -46,14 +29,19 @@ func CheckWitness() bool {
} }
// Log logs given message // Log logs given message
func Log(args []interface{}) bool { func Log(message string) bool {
message := args[0].(string) if trigger != runtime.Application {
return false
}
runtime.Log(message) runtime.Log(message)
return true return true
} }
// Notify notifies about given message // Notify notifies about given message
func Notify(args []interface{}) bool { func Notify(event interface{}) bool {
runtime.Notify("Event", args[0]) if trigger != runtime.Application {
return false
}
runtime.Notify("Event", event)
return true return true
} }

View file

@ -0,0 +1,8 @@
hasstorage: false
ispayable: false
supportedstandards: []
events:
- name: Event
parameters:
- name: event
type: Any

View file

@ -5,62 +5,33 @@ import (
"github.com/nspcc-dev/neo-go/pkg/interop/storage" "github.com/nspcc-dev/neo-go/pkg/interop/storage"
) )
// Main is a very useful function. // ctx holds storage context for contract methods
func Main(operation string, args []interface{}) interface{} { var ctx storage.Context
if operation == "put" {
return Put(args)
}
if operation == "get" { // init inits storage context before any other contract method is called
return Get(args) func init() {
} ctx = storage.GetContext()
if operation == "delete" {
return Delete(args)
}
if operation == "find" {
return Find(args)
}
return false
} }
// Put puts value at key. // Put puts value at key.
func Put(args []interface{}) interface{} { func Put(key, value []byte) []byte {
ctx := storage.GetContext()
if checkArgs(args, 2) {
key := args[0].([]byte)
value := args[1].([]byte)
storage.Put(ctx, key, value) storage.Put(ctx, key, value)
return key return key
} }
return false
}
// Get returns the value at passed key. // Get returns the value at passed key.
func Get(args []interface{}) interface{} { func Get(key []byte) interface{} {
ctx := storage.GetContext()
if checkArgs(args, 1) {
key := args[0].([]byte)
return storage.Get(ctx, key) return storage.Get(ctx, key)
} }
return false
}
// Delete deletes the value at passed key. // Delete deletes the value at passed key.
func Delete(args []interface{}) interface{} { func Delete(key []byte) bool {
ctx := storage.GetContext()
key := args[0].([]byte)
storage.Delete(ctx, key) storage.Delete(ctx, key)
return true return true
} }
// Find returns an array of key-value pairs with key that matched the passed value. // Find returns an array of key-value pairs with key that matched the passed value
func Find(args []interface{}) interface{} { func Find(value []byte) []string {
ctx := storage.GetContext()
if checkArgs(args, 1) {
value := args[0].([]byte)
iter := storage.Find(ctx, value) iter := storage.Find(ctx, value)
result := []string{} result := []string{}
for iterator.Next(iter) { for iterator.Next(iter) {
@ -70,13 +41,3 @@ func Find(args []interface{}) interface{} {
} }
return result return result
} }
return false
}
func checkArgs(args []interface{}, length int) bool {
if len(args) == length {
return true
}
return false
}

View file

@ -0,0 +1,4 @@
hasstorage: true
ispayable: false
supportedstandards: []
events: []

View file

@ -11,7 +11,12 @@ const (
multiplier = decimals * 10 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. // TokenConfig holds information about the token we want to use for the sale.
type TokenConfig struct { type TokenConfig struct {
@ -51,8 +56,8 @@ type TokenConfig struct {
KYCKey []byte KYCKey []byte
} }
// NewTokenConfig returns the initialized TokenConfig. // newTokenConfig returns the initialized TokenConfig.
func NewTokenConfig() TokenConfig { func newTokenConfig() TokenConfig {
return TokenConfig{ return TokenConfig{
Name: "My awesome token", Name: "My awesome token",
Symbol: "MAT", Symbol: "MAT",
@ -82,108 +87,91 @@ func getIntFromDB(ctx storage.Context, key []byte) int {
return res return res
} }
// InCirculation return the amount of total tokens that are in circulation. // InCirculation returns the amount of total tokens that are in circulation.
func (t TokenConfig) InCirculation(ctx storage.Context) int { func InCirculation() int {
return getIntFromDB(ctx, t.CirculationKey) return getIntFromDB(ctx, token.CirculationKey)
} }
// AddToCirculation sets the given amount as "in circulation" in the storage. // AddToCirculation sets the given amount as "in circulation" in the storage.
func (t TokenConfig) AddToCirculation(ctx storage.Context, amount int) bool { func AddToCirculation(amount int) bool {
supply := getIntFromDB(ctx, t.CirculationKey) supply := getIntFromDB(ctx, token.CirculationKey)
supply += amount supply += amount
storage.Put(ctx, t.CirculationKey, supply) storage.Put(ctx, token.CirculationKey, supply)
return true return true
} }
// TokenSaleAvailableAmount returns the total amount of available tokens left // AvailableAmount returns the total amount of available tokens left
// to be distributed. // to be distributed.
func (t TokenConfig) TokenSaleAvailableAmount(ctx storage.Context) int { func AvailableAmount() int {
inCirc := getIntFromDB(ctx, t.CirculationKey) inCirc := getIntFromDB(ctx, token.CirculationKey)
return t.TotalSupply - inCirc return token.TotalSupply - inCirc
} }
// Main smart contract entry point. // init initializes runtime trigger, TokenConfig and storage context before any
func Main(operation string, args []interface{}) interface{} { // other contract method is called
var ( func init() {
trigger = runtime.GetTrigger() trigger = runtime.GetTrigger()
cfg = NewTokenConfig() token = newTokenConfig()
ctx = storage.GetContext() 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) // This is used to verify if a transfer of system assets (NEO and Gas)
// involving this contract's address can proceed. // 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 { if trigger == runtime.Application {
return handleOperation(operation, args, ctx, cfg) // Check if the invoker is the owner of the contract.
} return runtime.CheckWitness(token.Owner)
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)
} }
return false 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) { if amount <= 0 || len(to) != 20 || !runtime.CheckWitness(from) {
return false return false
} }
@ -203,7 +191,13 @@ func transfer(cfg TokenConfig, ctx storage.Context, from, to []byte, amount int)
return true 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 { if amount <= 0 {
return false return false
} }
@ -234,8 +228,9 @@ func transferFrom(cfg TokenConfig, ctx storage.Context, from, to []byte, amount
return true return true
} }
func approve(ctx storage.Context, owner, spender []byte, amount int) bool { // Approve stores token transfer data if the owner has enough token to send.
if !runtime.CheckWitness(owner) || amount < 0 { func Approve(owner, spender []byte, amount int) bool {
if !checkOwnerWitness() || amount < 0 {
return false return false
} }
if len(spender) != 20 { if len(spender) != 20 {
@ -254,7 +249,11 @@ func approve(ctx storage.Context, owner, spender []byte, amount int) bool {
return true 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...) key := append(from, to...)
return getIntFromDB(ctx, key) return getIntFromDB(ctx, key)
} }

View file

@ -0,0 +1,4 @@
hasstorage: true
ispayable: false
supportedstandards: ["NEP-5"]
events: []

View file

@ -34,12 +34,12 @@ func getIntFromDB(ctx storage.Context, key []byte) int {
} }
// GetSupply gets the token totalSupply value from VM storage // 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)) return getIntFromDB(ctx, []byte(t.CirculationKey))
} }
// BalanceOf gets the token balance of a specific address // 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) return getIntFromDB(ctx, holder)
} }
@ -104,7 +104,7 @@ func IsUsableAddress(addr []byte) bool {
return false return false
} }
// Mint initial supply of tokens. // Mint initial supply of tokens
func (t Token) Mint(ctx storage.Context, to []byte) bool { func (t Token) Mint(ctx storage.Context, to []byte) bool {
if !IsUsableAddress(t.Owner) { if !IsUsableAddress(t.Owner) {
return false return false
@ -116,6 +116,7 @@ func (t Token) Mint(ctx storage.Context, to []byte) bool {
storage.Put(ctx, to, t.TotalSupply) storage.Put(ctx, to, t.TotalSupply)
storage.Put(ctx, []byte("minted"), true) storage.Put(ctx, []byte("minted"), true)
storage.Put(ctx, []byte(t.CirculationKey), t.TotalSupply)
runtime.Notify("transfer", "", to, t.TotalSupply) runtime.Notify("transfer", "", to, t.TotalSupply)
return true return true
} }

View file

@ -11,11 +11,16 @@ const (
multiplier = 100000000 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 // init initializes the Token Interface and storage context for the Smart
func createToken() nep5.Token { // Contract to operate with
return nep5.Token{ func init() {
token = nep5.Token{
Name: "Awesome NEO Token", Name: "Awesome NEO Token",
Symbol: "ANT", Symbol: "ANT",
Decimals: decimals, Decimals: decimals,
@ -23,95 +28,40 @@ func createToken() nep5.Token {
TotalSupply: 11000000 * multiplier, TotalSupply: 11000000 * multiplier,
CirculationKey: "TokenCirculation", CirculationKey: "TokenCirculation",
} }
} ctx = storage.GetContext()
// 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
} }
// Name returns the token name // Name returns the token name
func Name() string { func Name() string {
t := createToken() return token.Name
return t.Name
} }
// Symbol returns the token symbol // Symbol returns the token symbol
func Symbol() string { func Symbol() string {
t := createToken() return token.Symbol
return t.Symbol
} }
// Decimals returns the token decimals // Decimals returns the token decimals
func Decimals() int { func Decimals() int {
t := createToken() return token.Decimals
return t.Decimals
} }
// TotalSupply returns the token total supply value // TotalSupply returns the token total supply value
func TotalSupply() interface{} { func TotalSupply() int {
t := createToken() return token.GetSupply(ctx)
ctx := storage.GetContext()
return t.GetSupply(ctx)
} }
// BalanceOf returns the amount of token on the specified address // BalanceOf returns the amount of token on the specified address
func BalanceOf(holder []byte) interface{} { func BalanceOf(holder []byte) interface{} {
t := createToken() return token.BalanceOf(ctx, holder)
ctx := storage.GetContext()
return t.BalanceOf(ctx, holder)
} }
// Transfer token from one user to another // Transfer token from one user to another
func Transfer(from []byte, to []byte, amount int) bool { func Transfer(from []byte, to []byte, amount int) bool {
t := createToken() return token.Transfer(ctx, from, to, amount)
ctx := storage.GetContext()
return t.Transfer(ctx, from, to, amount)
} }
// Mint initial supply of tokens // Mint initial supply of tokens
func Mint(to []byte) bool { func Mint(to []byte) bool {
t := createToken() return token.Mint(ctx, to)
ctx := storage.GetContext()
return t.Mint(ctx, to)
} }

12
examples/token/token.yml Normal file
View file

@ -0,0 +1,12 @@
hasstorage: true
ispayable: false
supportedstandards: ["NEP-5"]
events:
- name: transfer
parameters:
- name: from
type: ByteString
- name: to
type: ByteString
- name: amount
type: Integer

View file

@ -14,6 +14,7 @@ import (
"strings" "strings"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
"golang.org/x/tools/go/loader" "golang.org/x/tools/go/loader"
) )
@ -37,6 +38,9 @@ type Options struct {
// Contract features. // Contract features.
ContractFeatures smartcontract.PropertyState ContractFeatures smartcontract.PropertyState
// Runtime notifications.
ContractEvents []manifest.Event
// The list of standards supported by the contract. // The list of standards supported by the contract.
ContractSupportedStandards []string ContractSupportedStandards []string
} }
@ -190,7 +194,7 @@ func CompileAndSave(src string, o *Options) ([]byte, error) {
} }
if o.ManifestFile != "" { if o.ManifestFile != "" {
m, err := di.ConvertToManifest(o.ContractFeatures, o.ContractSupportedStandards...) m, err := di.ConvertToManifest(o.ContractFeatures, o.ContractEvents, o.ContractSupportedStandards...)
if err != nil { if err != nil {
return b, fmt.Errorf("failed to convert debug info to manifest: %w", err) return b, fmt.Errorf("failed to convert debug info to manifest: %w", err)
} }

View file

@ -363,8 +363,7 @@ func parsePairJSON(data []byte, sep string) (string, string, error) {
// ConvertToManifest converts contract to the manifest.Manifest struct for debugger. // ConvertToManifest converts contract to the manifest.Manifest struct for debugger.
// Note: manifest is taken from the external source, however it can be generated ad-hoc. See #1038. // Note: manifest is taken from the external source, however it can be generated ad-hoc. See #1038.
func (di *DebugInfo) ConvertToManifest(fs smartcontract.PropertyState, supportedStandards ...string) (*manifest.Manifest, error) { func (di *DebugInfo) ConvertToManifest(fs smartcontract.PropertyState, events []manifest.Event, supportedStandards ...string) (*manifest.Manifest, error) {
var err error
if di.MainPkg == "" { if di.MainPkg == "" {
return nil, errors.New("no Main method was found") return nil, errors.New("no Main method was found")
} }
@ -378,19 +377,15 @@ func (di *DebugInfo) ConvertToManifest(fs smartcontract.PropertyState, supported
methods = append(methods, mMethod) methods = append(methods, mMethod)
} }
} }
events := make([]manifest.Event, len(di.Events))
for i, event := range di.Events {
events[i], err = event.ToManifestEvent()
if err != nil {
return nil, err
}
}
result := manifest.NewManifest(di.Hash) result := manifest.NewManifest(di.Hash)
result.Features = fs result.Features = fs
if supportedStandards != nil { if supportedStandards != nil {
result.SupportedStandards = supportedStandards result.SupportedStandards = supportedStandards
} }
if events == nil {
events = make([]manifest.Event, 0)
}
result.ABI = manifest.ABI{ result.ABI = manifest.ABI{
Hash: di.Hash, Hash: di.Hash,
Methods: methods, Methods: methods,

View file

@ -127,7 +127,7 @@ func unexportedMethod() int { return 1 }
} }
t.Run("convert to Manifest", func(t *testing.T) { t.Run("convert to Manifest", func(t *testing.T) {
actual, err := d.ConvertToManifest(smartcontract.HasStorage) actual, err := d.ConvertToManifest(smartcontract.HasStorage, nil)
require.NoError(t, err) require.NoError(t, err)
// note: offsets are hard to predict, so we just take them from the output // note: offsets are hard to predict, so we just take them from the output
expected := &manifest.Manifest{ expected := &manifest.Manifest{

View file

@ -88,7 +88,7 @@ func TestAppCall(t *testing.T) {
inner, di, err := compiler.CompileWithDebugInfo("foo.go", strings.NewReader(srcInner)) inner, di, err := compiler.CompileWithDebugInfo("foo.go", strings.NewReader(srcInner))
require.NoError(t, err) require.NoError(t, err)
m, err := di.ConvertToManifest(smartcontract.NoProperties) m, err := di.ConvertToManifest(smartcontract.NoProperties, nil)
require.NoError(t, err) require.NoError(t, err)
ih := hash.Hash160(inner) ih := hash.Hash160(inner)

View file

@ -233,7 +233,7 @@ func TestCreateBasicChain(t *testing.T) {
t.Logf("contractHash: %s", hash.Hash160(avm).StringLE()) t.Logf("contractHash: %s", hash.Hash160(avm).StringLE())
script := io.NewBufBinWriter() script := io.NewBufBinWriter()
m, err := di.ConvertToManifest(smartcontract.HasStorage) m, err := di.ConvertToManifest(smartcontract.HasStorage, nil)
require.NoError(t, err) require.NoError(t, err)
bs, err := m.MarshalJSON() bs, err := m.MarshalJSON()
require.NoError(t, err) require.NoError(t, err)