diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index ab8016d01..90c325c86 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -60,8 +60,16 @@ const ( import "github.com/nspcc-dev/neo-go/pkg/interop/runtime" -func Main(op string, args []interface{}) { - runtime.Notify("Hello world!") +var notificationName string + +// 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 // parameters and cosigners for invoke* commands @@ -325,6 +333,17 @@ func initSmartContract(ctx *cli.Context) error { m := ProjectConfig{ SupportedStandards: []string{}, + Events: []manifest.Event{ + { + Name: "Hello world!", + Parameters: []manifest.Parameter{ + { + Name: "args", + Type: smartcontract.ArrayType, + }, + }, + }, + }, } b, err := yaml.Marshal(m) if err != nil { @@ -369,6 +388,7 @@ func contractCompile(ctx *cli.Context) error { return err } o.ContractFeatures = conf.GetFeatures() + o.ContractEvents = conf.Events o.ContractSupportedStandards = conf.SupportedStandards } 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/engine/engine.yml b/examples/engine/engine.yml new file mode 100644 index 000000000..1fa77b421 --- /dev/null +++ b/examples/engine/engine.yml @@ -0,0 +1,8 @@ +hasstorage: false +ispayable: false +supportedstandards: [] +events: + - name: Tx + parameters: + - name: txHash + type: ByteString 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/iterator/iterator.yml b/examples/iterator/iterator.yml new file mode 100644 index 000000000..af36a5660 --- /dev/null +++ b/examples/iterator/iterator.yml @@ -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 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/runtime/runtime.yml b/examples/runtime/runtime.yml new file mode 100644 index 000000000..3f206d027 --- /dev/null +++ b/examples/runtime/runtime.yml @@ -0,0 +1,8 @@ +hasstorage: false +ispayable: false +supportedstandards: [] +events: + - name: Event + parameters: + - name: event + type: Any 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/storage/storage.yml b/examples/storage/storage.yml new file mode 100644 index 000000000..d9b6984cf --- /dev/null +++ b/examples/storage/storage.yml @@ -0,0 +1,4 @@ +hasstorage: true +ispayable: false +supportedstandards: [] +events: [] 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-sale/token_sale.yml b/examples/token-sale/token_sale.yml new file mode 100644 index 000000000..50258d5c2 --- /dev/null +++ b/examples/token-sale/token_sale.yml @@ -0,0 +1,4 @@ +hasstorage: true +ispayable: false +supportedstandards: ["NEP-5"] +events: [] diff --git a/examples/token/nep5/nep5.go b/examples/token/nep5/nep5.go index 79f7b7692..f5b911953 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 @@ -116,6 +116,7 @@ func (t Token) Mint(ctx storage.Context, to []byte) bool { storage.Put(ctx, to, t.TotalSupply) storage.Put(ctx, []byte("minted"), true) + storage.Put(ctx, []byte(t.CirculationKey), t.TotalSupply) runtime.Notify("transfer", "", to, t.TotalSupply) return true } 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) } diff --git a/examples/token/token.yml b/examples/token/token.yml new file mode 100644 index 000000000..f8476fbf9 --- /dev/null +++ b/examples/token/token.yml @@ -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 diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index 7c131319f..4950dc93e 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -14,6 +14,7 @@ import ( "strings" "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" "golang.org/x/tools/go/loader" ) @@ -37,6 +38,9 @@ type Options struct { // Contract features. ContractFeatures smartcontract.PropertyState + // Runtime notifications. + ContractEvents []manifest.Event + // The list of standards supported by the contract. ContractSupportedStandards []string } @@ -190,7 +194,7 @@ func CompileAndSave(src string, o *Options) ([]byte, error) { } if o.ManifestFile != "" { - m, err := di.ConvertToManifest(o.ContractFeatures, o.ContractSupportedStandards...) + m, err := di.ConvertToManifest(o.ContractFeatures, o.ContractEvents, o.ContractSupportedStandards...) if err != nil { return b, fmt.Errorf("failed to convert debug info to manifest: %w", err) } diff --git a/pkg/compiler/debug.go b/pkg/compiler/debug.go index 5aad14726..71e8f4adb 100644 --- a/pkg/compiler/debug.go +++ b/pkg/compiler/debug.go @@ -363,8 +363,7 @@ func parsePairJSON(data []byte, sep string) (string, string, error) { // 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. -func (di *DebugInfo) ConvertToManifest(fs smartcontract.PropertyState, supportedStandards ...string) (*manifest.Manifest, error) { - var err error +func (di *DebugInfo) ConvertToManifest(fs smartcontract.PropertyState, events []manifest.Event, supportedStandards ...string) (*manifest.Manifest, error) { if di.MainPkg == "" { 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) } } - 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.Features = fs if supportedStandards != nil { result.SupportedStandards = supportedStandards } + if events == nil { + events = make([]manifest.Event, 0) + } result.ABI = manifest.ABI{ Hash: di.Hash, Methods: methods, diff --git a/pkg/compiler/debug_test.go b/pkg/compiler/debug_test.go index fee427df5..69305f10d 100644 --- a/pkg/compiler/debug_test.go +++ b/pkg/compiler/debug_test.go @@ -127,7 +127,7 @@ func unexportedMethod() int { return 1 } } 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) // note: offsets are hard to predict, so we just take them from the output expected := &manifest.Manifest{ diff --git a/pkg/compiler/interop_test.go b/pkg/compiler/interop_test.go index 79c00d93f..f0cdc2fac 100644 --- a/pkg/compiler/interop_test.go +++ b/pkg/compiler/interop_test.go @@ -88,7 +88,7 @@ func TestAppCall(t *testing.T) { inner, di, err := compiler.CompileWithDebugInfo("foo.go", strings.NewReader(srcInner)) require.NoError(t, err) - m, err := di.ConvertToManifest(smartcontract.NoProperties) + m, err := di.ConvertToManifest(smartcontract.NoProperties, nil) require.NoError(t, err) ih := hash.Hash160(inner) diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index fb4edb92e..a4f9b86ef 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -233,7 +233,7 @@ func TestCreateBasicChain(t *testing.T) { t.Logf("contractHash: %s", hash.Hash160(avm).StringLE()) script := io.NewBufBinWriter() - m, err := di.ConvertToManifest(smartcontract.HasStorage) + m, err := di.ConvertToManifest(smartcontract.HasStorage, nil) require.NoError(t, err) bs, err := m.MarshalJSON() require.NoError(t, err)