diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 270a4014b..dc9205953 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -363,6 +363,7 @@ func initSmartContract(ctx *cli.Context) error { m := ProjectConfig{ Name: contractName, SupportedStandards: []string{}, + SafeMethods: []string{}, Events: []manifest.Event{ { Name: "Hello world!", @@ -423,6 +424,7 @@ func contractCompile(ctx *cli.Context) error { o.Name = conf.Name o.ContractEvents = conf.Events o.ContractSupportedStandards = conf.SupportedStandards + o.SafeMethods = conf.SafeMethods } result, err := compiler.CompileAndSave(src, o) @@ -646,6 +648,7 @@ func testInvokeScript(ctx *cli.Context) error { // ProjectConfig contains project metadata. type ProjectConfig struct { Name string + SafeMethods []string SupportedStandards []string Events []manifest.Event } diff --git a/cli/smartcontract/smart_contract_test.go b/cli/smartcontract/smart_contract_test.go index 8264cb858..eba92c021 100644 --- a/cli/smartcontract/smart_contract_test.go +++ b/cli/smartcontract/smart_contract_test.go @@ -59,6 +59,7 @@ func RuntimeNotify(args []interface{}) { require.NoError(t, err) require.Equal(t, `name: testContract +safemethods: [] supportedstandards: [] events: - name: Hello world! diff --git a/examples/token-sale/token_sale.yml b/examples/token-sale/token_sale.yml index bda6ba182..20ea78365 100644 --- a/examples/token-sale/token_sale.yml +++ b/examples/token-sale/token_sale.yml @@ -1,5 +1,6 @@ name: "My awesome token" supportedstandards: ["NEP-17"] +safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"] events: - name: Transfer parameters: diff --git a/examples/token/token.yml b/examples/token/token.yml index 32fd428b5..071976019 100644 --- a/examples/token/token.yml +++ b/examples/token/token.yml @@ -1,5 +1,6 @@ name: "Awesome NEO Token" supportedstandards: ["NEP-17"] +safemethods: ["balanceOf", "decimals", "symbol", "totalSupply"] events: - name: Transfer parameters: diff --git a/internal/testchain/transaction.go b/internal/testchain/transaction.go index c024ad85c..10e71529e 100644 --- a/internal/testchain/transaction.go +++ b/internal/testchain/transaction.go @@ -62,7 +62,7 @@ func NewDeployTx(name string, sender util.Uint160, r gio.Reader) (*transaction.T return nil, util.Uint160{}, err } - m, err := di.ConvertToManifest(name, nil) + m, err := di.ConvertToManifest(&compiler.Options{Name: name}) if err != nil { return nil, util.Uint160{}, err } diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index 41fe8d0c8..02987acb7 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -51,6 +51,9 @@ type Options struct { // The list of standards supported by the contract. ContractSupportedStandards []string + + // SafeMethods contains list of methods which will be marked as safe in manifest. + SafeMethods []string } type buildInfo struct { @@ -219,7 +222,7 @@ func CompileAndSave(src string, o *Options) ([]byte, error) { } if o.ManifestFile != "" { - m, err := di.ConvertToManifest(o.Name, o.ContractEvents, o.ContractSupportedStandards...) + m, err := di.ConvertToManifest(o) 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 d82fc688e..49812c1b8 100644 --- a/pkg/compiler/debug.go +++ b/pkg/compiler/debug.go @@ -334,49 +334,27 @@ func (d *DebugParam) UnmarshalJSON(data []byte) error { } // ToManifestParameter converts DebugParam to manifest.Parameter -func (d *DebugParam) ToManifestParameter() (manifest.Parameter, error) { +func (d *DebugParam) ToManifestParameter() manifest.Parameter { return manifest.Parameter{ Name: d.Name, Type: d.TypeSC, - }, nil + } } // ToManifestMethod converts MethodDebugInfo to manifest.Method -func (m *MethodDebugInfo) ToManifestMethod() (manifest.Method, error) { +func (m *MethodDebugInfo) ToManifestMethod() manifest.Method { var ( result manifest.Method - err error ) parameters := make([]manifest.Parameter, len(m.Parameters)) for i, p := range m.Parameters { - parameters[i], err = p.ToManifestParameter() - if err != nil { - return result, err - } + parameters[i] = p.ToManifestParameter() } result.Name = m.Name.Name result.Offset = int(m.Range.Start) result.Parameters = parameters result.ReturnType = m.ReturnTypeSC - return result, nil -} - -// ToManifestEvent converts EventDebugInfo to manifest.Event -func (e *EventDebugInfo) ToManifestEvent() (manifest.Event, error) { - var ( - result manifest.Event - err error - ) - parameters := make([]manifest.Parameter, len(e.Parameters)) - for i, p := range e.Parameters { - parameters[i], err = p.ToManifestParameter() - if err != nil { - return result, err - } - } - result.Name = e.Name - result.Parameters = parameters - return result, nil + return result } // MarshalJSON implements json.Marshaler interface. @@ -425,31 +403,31 @@ 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(name string, events []manifest.Event, supportedStandards ...string) (*manifest.Manifest, error) { - if di.MainPkg == "" { - return nil, errors.New("no Main method was found") - } +func (di *DebugInfo) ConvertToManifest(o *Options) (*manifest.Manifest, error) { methods := make([]manifest.Method, 0) for _, method := range di.Methods { if method.IsExported && method.IsFunction && method.Name.Namespace == di.MainPkg { - mMethod, err := method.ToManifestMethod() - if err != nil { - return nil, err + mMethod := method.ToManifestMethod() + for i := range o.SafeMethods { + if mMethod.Name == o.SafeMethods[i] { + mMethod.Safe = true + break + } } methods = append(methods, mMethod) } } - result := manifest.NewManifest(name) - if supportedStandards != nil { - result.SupportedStandards = supportedStandards - } - if events == nil { - events = make([]manifest.Event, 0) + result := manifest.NewManifest(o.Name) + if o.ContractSupportedStandards != nil { + result.SupportedStandards = o.ContractSupportedStandards } result.ABI = manifest.ABI{ Methods: methods, - Events: events, + Events: o.ContractEvents, + } + if result.ABI.Events == nil { + result.ABI.Events = make([]manifest.Event, 0) } result.Permissions = []manifest.Permission{ { diff --git a/pkg/compiler/debug_test.go b/pkg/compiler/debug_test.go index 3be6ec420..fcced5851 100644 --- a/pkg/compiler/debug_test.go +++ b/pkg/compiler/debug_test.go @@ -150,7 +150,7 @@ func _deploy(isUpdate bool) {} } t.Run("convert to Manifest", func(t *testing.T) { - actual, err := d.ConvertToManifest("MyCTR", nil) + actual, err := d.ConvertToManifest(&Options{Name: "MyCTR", SafeMethods: []string{"methodInt", "methodString"}}) require.NoError(t, err) // note: offsets are hard to predict, so we just take them from the output expected := &manifest.Manifest{ @@ -183,12 +183,14 @@ func _deploy(isUpdate bool) {} }, }, ReturnType: smartcontract.IntegerType, + Safe: true, }, { Name: "methodString", Offset: 101, Parameters: []manifest.Parameter{}, ReturnType: smartcontract.StringType, + Safe: true, }, { Name: "methodByteArray", diff --git a/pkg/compiler/interop_test.go b/pkg/compiler/interop_test.go index 6aa603aaa..eb81b717b 100644 --- a/pkg/compiler/interop_test.go +++ b/pkg/compiler/interop_test.go @@ -128,7 +128,7 @@ func TestAppCall(t *testing.T) { }` barCtr, di, err := compiler.CompileWithDebugInfo("bar.go", strings.NewReader(srcDeep)) require.NoError(t, err) - mBar, err := di.ConvertToManifest("Bar", nil) + mBar, err := di.ConvertToManifest(&compiler.Options{Name: "Bar"}) require.NoError(t, err) barH := hash.Hash160(barCtr) @@ -160,7 +160,7 @@ func TestAppCall(t *testing.T) { inner, di, err := compiler.CompileWithDebugInfo("foo.go", strings.NewReader(srcInner)) require.NoError(t, err) - m, err := di.ConvertToManifest("Foo", nil) + m, err := di.ConvertToManifest(&compiler.Options{Name: "Foo"}) require.NoError(t, err) ih := hash.Hash160(inner) diff --git a/pkg/smartcontract/manifest/standard/nep17.go b/pkg/smartcontract/manifest/standard/nep17.go index ff76c4199..098ce6cfc 100644 --- a/pkg/smartcontract/manifest/standard/nep17.go +++ b/pkg/smartcontract/manifest/standard/nep17.go @@ -14,18 +14,22 @@ var nep17 = &manifest.Manifest{ {Type: smartcontract.Hash160Type}, }, ReturnType: smartcontract.IntegerType, + Safe: true, }, { Name: "decimals", ReturnType: smartcontract.IntegerType, + Safe: true, }, { Name: "symbol", ReturnType: smartcontract.StringType, + Safe: true, }, { Name: "totalSupply", ReturnType: smartcontract.IntegerType, + Safe: true, }, { Name: "transfer",