github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/docs/compiler.md (about) 1 # NeoGo smart contract compiler 2 3 The neo-go compiler compiles Go programs to a bytecode that the Neo virtual machine can understand. 4 5 ## Language compatibility 6 7 The compiler is mostly compatible with regular Go language specification. However, 8 there are some important deviations that you need to be aware of that make it 9 a dialect of Go rather than a complete port of the language: 10 * `new()` is not supported, most of the time you can substitute structs with composite literals 11 * `make()` is supported for maps and slices with elements of basic types 12 * `copy()` is supported only for byte slices because of the underlying `MEMCPY` opcode 13 * pointers are supported only for struct literals, one can't take an address 14 of an arbitrary variable 15 * there is no real distinction between different integer types, all of them 16 work as big.Int in Go with a limit of 256 bit in width; so you can use 17 `int` for just about anything. This is the way integers work in Neo VM and 18 adding proper Go types emulation is considered to be too costly. 19 * goroutines, channels and garbage collection are not supported and will 20 never be because emulating that aspects of Go runtime on top of Neo VM is 21 close to impossible 22 * `defer` and `recover` are supported except for the cases where panic occurs in 23 `return` statement because this complicates implementation and imposes runtime 24 overhead for all contracts. This can easily be mitigated by first storing values 25 in variables and returning the result. 26 * lambdas are supported, but closures are not. 27 * maps are supported, but valid map keys are booleans, integers and strings with length <= 64 28 * converting value to interface type doesn't change the underlying type, 29 original value will always be used, therefore it never panics and always "succeeds"; 30 it's up to the programmer whether it's a correct use of a value 31 * type assertion with two return values is not supported; single return value (of the desired type) 32 is supported; type assertion panics if value can't be asserted to the desired type, therefore 33 it's up to the programmer whether assert can be performed successfully. 34 * type aliases including the built-in `any` alias are supported. 35 * generics are not supported, but eventually will be (at least, partially), ref. https://github.com/nspcc-dev/neo-go/issues/2376. 36 37 ## VM API (interop layer) 38 Compiler translates interop function calls into Neo VM syscalls or (for custom 39 functions) into Neo VM instructions. [Refer to 40 pkg.go.dev](https://pkg.go.dev/github.com/nspcc-dev/neo-go/pkg/interop) 41 for full API documentation. In general it provides the same level of 42 functionality as Neo .net Framework library. 43 44 Compiler provides some helpful builtins in `util`, `convert` and `math` packages. 45 Refer to them for detailed documentation. 46 47 `_deploy()` function has a special meaning and is executed when contract is deployed. 48 It should return no value and accept two arguments: the first one is `data` containing 49 all values `deploy` is aware of and able to make use of; the second one is a bool 50 argument which will be true on contract update. 51 `_deploy()` functions are called for every imported package in the same order as `init()`. 52 53 ## Quick start 54 55 ### Go setup 56 57 The compiler uses Go parser internally and depends on regular Go compiler 58 presence, so make sure you have it installed and set up. On some distributions 59 this requires you to set proper `GOROOT` environment variable, like 60 ``` 61 export GOROOT=/usr/lib64/go/1.15 62 ``` 63 64 The best way to create a new contract is to use `contract init` command. This will 65 create an example source file, a config file and `go.mod` with `github.com/nspcc-dev/neo-go/pkg/interop` dependency. 66 ``` 67 $ ./bin/neo-go contract init --name MyAwesomeContract 68 $ cd MyAwesomeContract 69 ``` 70 71 You'll also need to download dependency modules for your contract like this (in the 72 directory containing contract package): 73 ``` 74 $ go mod tidy 75 ``` 76 77 ### Compiling 78 79 ``` 80 ./bin/neo-go contract compile -i contract.go 81 ``` 82 83 By default, the filename will be the name of your .go file with the .nef 84 extension, the file will be located in the same directory with your Go contract. 85 Along with the compiled contract and if the contract configuration file 86 `contract.yml` exist, the following files will be generated: 87 * smart-contract manifest file (`contract.manifest.json`) that is needed to deploy 88 the contract to the network 89 * bindings configuration file (`contract.bindings.yml`) that is needed to generate 90 code-based or RPC contract bindings 91 All of them will be located in the same directory with your Go contract. 92 93 If you want another location for your compiled contract: 94 95 ``` 96 ./bin/neo-go contract compile -i contract.go --out /Users/foo/bar/contract.nef 97 ``` 98 99 If your contract is split across multiple files, you must provide a path 100 to the directory where package files are contained instead of a single Go file 101 (`out.nef` will be used as the default output file in this case): 102 ``` 103 ./bin/neo-go contract compile -i ./path/to/contract 104 ``` 105 106 ### Debugging 107 You can dump the opcodes generated by the compiler with the following command: 108 109 ``` 110 ./bin/neo-go contract inspect -i contract.go -c 111 ``` 112 113 This will result in something like this: 114 115 ``` 116 INDEX OPCODE PARAMETER 117 0 INITSLOT 4 local, 2 arg << 118 3 LDARG1 119 4 NOT 120 5 JMPIFNOT_L 151 (146/92000000) 121 10 SYSCALL System.Storage.GetContext (9bf667ce) 122 15 NOP 123 16 STLOC0 124 17 PUSHDATA1 53746f72616765206b6579206e6f7420796574207365742e2053657474696e6720746f2030 ("Storage key not yet set. Setting to 0") 125 56 CONVERT Buffer (30) 126 58 PUSH1 127 59 PACK 128 60 STLOC1 129 61 PUSHDATA1 696e666f ("info") 130 67 LDLOC1 131 68 SWAP 132 69 SYSCALL System.Runtime.Notify (95016f61) 133 74 NOP 134 75 PUSH0 135 76 STLOC2 136 77 LDLOC0 137 78 PUSHDATA1 746573742d73746f726167652d6b6579 ("test-storage-key") 138 96 LDLOC2 139 97 REVERSE3 140 98 SYSCALL System.Storage.Put (e63f1884) 141 103 NOP 142 104 PUSHDATA1 53746f72616765206b657920697320696e697469616c69736564 ("Storage key is initialised") 143 132 CONVERT Buffer (30) 144 134 PUSH1 145 135 PACK 146 136 STLOC3 147 137 PUSHDATA1 696e666f ("info") 148 143 LDLOC3 149 144 SWAP 150 145 SYSCALL System.Runtime.Notify (95016f61) 151 150 NOP 152 151 RET 153 152 INITSLOT 5 local, 0 arg 154 155 SYSCALL System.Storage.GetContext (9bf667ce) 155 160 NOP 156 161 STLOC0 157 162 LDLOC0 158 163 PUSHDATA1 746573742d73746f726167652d6b6579 ("test-storage-key") 159 181 SWAP 160 182 SYSCALL System.Storage.Get (925de831) 161 187 NOP 162 188 STLOC1 163 189 PUSHDATA1 56616c756520726561642066726f6d2073746f72616765 ("Value read from storage") 164 214 CONVERT Buffer (30) 165 216 PUSH1 166 217 PACK 167 218 STLOC2 168 219 PUSHDATA1 696e666f ("info") 169 225 LDLOC2 170 226 SWAP 171 227 SYSCALL System.Runtime.Notify (95016f61) 172 232 NOP 173 233 PUSHDATA1 53746f72616765206b657920616c7265616479207365742e20496e6372656d656e74696e672062792031 ("Storage key already set. Incrementing by 1") 174 277 CONVERT Buffer (30) 175 279 PUSH1 176 280 PACK 177 281 STLOC3 178 282 PUSHDATA1 696e666f ("info") 179 288 LDLOC3 180 289 SWAP 181 290 SYSCALL System.Runtime.Notify (95016f61) 182 295 NOP 183 296 LDLOC1 184 297 CONVERT Integer (21) 185 299 PUSH1 186 300 ADD 187 301 STLOC1 188 302 LDLOC0 189 303 PUSHDATA1 746573742d73746f726167652d6b6579 ("test-storage-key") 190 321 LDLOC1 191 322 REVERSE3 192 323 SYSCALL System.Storage.Put (e63f1884) 193 328 NOP 194 329 PUSHDATA1 4e65772076616c7565207772697474656e20696e746f2073746f72616765 ("New value written into storage") 195 361 CONVERT Buffer (30) 196 363 PUSH1 197 364 PACK 198 365 STLOC4 199 366 PUSHDATA1 696e666f ("info") 200 372 LDLOC4 201 373 SWAP 202 374 SYSCALL System.Runtime.Notify (95016f61) 203 379 NOP 204 380 LDLOC1 205 381 RET 206 ``` 207 208 #### Neo Smart Contract Debugger support 209 210 It's possible to debug contracts written in Go using standard [Neo Smart 211 Contract Debugger](https://github.com/neo-project/neo-debugger/) which is a 212 part of [Neo Blockchain 213 Toolkit](https://github.com/neo-project/neo-blockchain-toolkit/). To do that 214 you need to generate debug information using `--debug` option, like this: 215 216 ``` 217 $ ./bin/neo-go contract compile -i contract.go -c contract.yml -m contract.manifest.json -o contract.nef --debug contract.debug.json 218 ``` 219 220 This file can then be used by debugger and set up to work just like for any 221 other supported language. 222 223 ### Deploying 224 225 Deploying a contract to blockchain with neo-go requires both NEF and JSON 226 manifest generated by the compiler from a configuration file provided in YAML 227 format. To create contract manifest, pass a YAML file with `-c` parameter and 228 specify the manifest output file with `-m`: 229 ``` 230 ./bin/neo-go contract compile -i contract.go -c config.yml -m contract.manifest.json 231 ``` 232 233 Example of such YAML file contents: 234 ``` 235 name: Contract 236 safemethods: [] 237 supportedstandards: [] 238 events: 239 - name: info 240 parameters: 241 - name: message 242 type: String 243 ``` 244 245 Then, the manifest can be passed to the `deploy` command via `-m` option: 246 247 ``` 248 $ ./bin/neo-go contract deploy -i contract.nef -m contract.manifest.json -r http://localhost:20331 -w wallet.json 249 ``` 250 251 Deployment works via an RPC server, an address of which is passed via `-r` 252 option, and should be signed using a wallet from `-w` option. More details can 253 be found in `deploy` command help. 254 255 #### Config file 256 Configuration file contains following options: 257 258 | Parameter | Description | Example | 259 | --- | --- | --- | 260 | `name` | Contract name in the manifest. | `"My awesome contract"` 261 | `safemethods` | List of methods which don't change contract state, don't emit notifications and are available for anyone to call. | `["balanceOf", "decimals"]` 262 | `supportedstandards` | List of standards this contract implements. For example, `NEP-11` or `NEP-17` token standard. This will enable additional checks in compiler. The check can be disabled with `--no-standards` flag. | `["NEP-17"]` 263 | `events` | Notifications emitted by this contract. | See [Events](#Events). | 264 | `permissions` | Foreign calls allowed for this contract. | See [Permissions](#Permissions). | 265 | `overloads` | Custom method names for this contract. | See [Overloads](#Overloads). | 266 267 ##### Events 268 Each event must have a name and 0 or more parameters. Parameters are specified using their name and type. 269 Both event and parameter names must be strings. 270 Parameter type can be one of the following: 271 272 Type in code | Type in config file 273 --- | --- 274 `bool` | `Boolean` 275 `int`, `int64` etc.| `Integer` 276 `[]byte` | `ByteArray` 277 `string` | `String` 278 Any non-byte slice `[]T`| `Array` 279 `map[K]V` | `Map` 280 `interop.Hash160` | `Hash160` 281 `interop.Hash256` | `Hash256` 282 `interop.Interface` | `InteropInterface` 283 `interop.PublicKey` | `PublicKey` 284 `interop.Signature` | `Signature` 285 anything else | `Any` 286 287 `interop.*` types are defined as aliases in `github.com/nspcc-dev/neo-go/pkg/interop` module 288 with the sole purpose of correct manifest generation. 289 290 As an example, consider `Transfer` event from `NEP-17` standard: 291 ``` 292 - name: Transfer 293 parameters: 294 - name: from 295 type: Hash160 296 - name: to 297 type: Hash160 298 - name: amount 299 type: Integer 300 ``` 301 302 By default, compiler performs some sanity checks. Most of the time 303 it will report missing events and/or parameter type mismatch. 304 It isn't prohibited to use a variable as an event name in code, but it will prevent 305 the compiler from analyzing the event. It is better to use either constant or string literal. 306 It isn't prohibited to use ellipsis expression as an event arguments, but it will also 307 prevent the compiler from analyzing the event. It is better to provide arguments directly 308 without `...`. The type conversion code will be emitted for checked events, it will cast 309 argument types to ones specified in the contract manifest. These checks and conversion can 310 be disabled with `--no-events` flag. 311 312 ##### Permissions 313 Each permission specifies contracts and methods allowed for this permission. 314 If a contract is not specified in a rule, specified set of methods can be called on any contract. 315 By default, no calls are allowed. The simplest permission is to allow everything: 316 ``` 317 - methods: '*' 318 ``` 319 320 Another common case is to allow calling `onNEP17Payment`, which is necessary 321 for most of the NEP-17 token implementations: 322 ``` 323 - methods: ["onNEP17Payment"] 324 ``` 325 326 In addition to `methods`, permission can have one of these fields: 327 1. `hash` contains hash and restricts a set of contracts to a single contract. 328 2. `group` contains public key and restricts a set of contracts to those that 329 have the corresponding group in their manifest. 330 331 Consider an example: 332 ``` 333 - methods: ["onNEP17Payment"] 334 - hash: fffdc93764dbaddd97c48f252a53ea4643faa3fd 335 methods: ["start", "stop"] 336 - group: 03184b018d6b2bc093e535519732b3fd3f7551c8cffaf4621dd5a0b89482ca66c9 337 methods: ["update"] 338 ``` 339 340 This set of permissions allows calling: 341 - `onNEP17Payment` method of any contract 342 - `start` and `stop` methods of contract with hash `fffdc93764dbaddd97c48f252a53ea4643faa3fd` 343 - `update` method of contract in group with public key `03184b018d6b2bc093e535519732b3fd3f7551c8cffaf4621dd5a0b89482ca66c9` 344 345 Also note that a native contract must be included here too. For example, if your contract 346 transfers NEO/GAS or gets some info from the `Ledger` contract, all of these 347 calls must be allowed in permissions. 348 349 The compiler does its best to ensure that correct permissions are specified in the config. 350 Incorrect permissions will result in runtime invocation failures. 351 Using either constant or literal for contract hash and method will allow the compiler 352 to perform more extensive analysis. 353 This check can be disabled with `--no-permissions` flag. 354 355 ##### Overloads 356 NeoVM allows a contract to have multiple methods with the same name 357 but different parameters number. Go lacks this feature, but this can be circumvented 358 with `overloads` section. Essentially, it is a mapping from default contract method names 359 to the new ones. 360 ``` 361 - overloads: 362 oldName1: newName 363 oldName2: newName 364 ``` 365 Since the use-case for this is to provide multiple implementations with the same ABI name, 366 `newName` is required to be already present in the compiled contract. 367 368 As an example, consider [`NEP-11` standard](https://github.com/neo-project/proposals/blob/master/nep-11.mediawiki#transfer). 369 It requires a divisible NFT contract to have 2 `transfer` methods. To achieve this, we might implement 370 `Transfer` and `TransferDivisible` and specify the emitted name in the config: 371 ``` 372 - overloads: 373 transferDivisible:transfer 374 ``` 375 376 377 #### Manifest file 378 Any contract can be included in a group identified by a public key which is used in [permissions](#Permissions). 379 This is achieved with `manifest add-group` command. 380 ``` 381 ./bin/neo-go contract manifest add-group -n contract.nef -m contract.manifest.json --sender <sender> --wallet /path/to/wallet.json --account <account> 382 ``` 383 It accepts contract `.nef` and manifest files emitted by `compile` command as well as 384 sender and signer accounts. `--sender` is the account that will send deploy transaction later (not necessarily in wallet). 385 `--account` is the wallet account which signs contract hash using group private key. 386 387 #### Neo Express support 388 389 It's possible to deploy contracts written in Go using [Neo 390 Express](https://github.com/neo-project/neo-express), which is a part of [Neo 391 Blockchain 392 Toolkit](https://github.com/neo-project/neo-blockchain-toolkit/). To do that, 393 you need to generate a different metadata file using YAML written for 394 deployment with neo-go. It's done in the same step with compilation via 395 `--config` input parameter and `--abi` output parameter, combined with debug 396 support the command line will look like this: 397 398 ``` 399 $ ./bin/neo-go contract compile -i contract.go --config contract.yml -o contract.nef --debug contract.debug.json --abi contract.abi.json 400 ``` 401 402 This file can then be used by toolkit to deploy contract the same way 403 contracts in other languages are deployed. 404 405 406 ### Invoking 407 You can import your contract into a standalone VM and run it there (see [VM 408 documentation](vm.md) for more info), but that only works for simple contracts 409 that don't use blockchain a lot. For more real contracts you need to deploy 410 them first and then do test invocations and regular invocations with `contract 411 testinvokefunction` and `contract invokefunction` commands (or their variants, 412 see `contract` command help for more details. They all work via RPC, so it's a 413 mandatory parameter. 414 415 Example call (contract `f84d6a337fbc3d3a201d41da99e86b479e7a2554` with method 416 `balanceOf` and method's parameter `NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq` using 417 given RPC server and wallet and paying 0.00001 extra GAS for this transaction): 418 419 ``` 420 $ ./bin/neo-go contract invokefunction -r http://localhost:20331 -w my_wallet.json -g 0.00001 f84d6a337fbc3d3a201d41da99e86b479e7a2554 balanceOf NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq 421 ``` 422 423 ### Generating contract bindings 424 To be able to use deployed contract from another contract one needs to have 425 its interface definition (exported methods and hash). While it is possible to 426 use generic contract.Call interop interface, it's not very convenient and 427 efficient. NeoGo can autogenerate contract bindings in Go language for any 428 deployed contract based on its manifest, it creates a Go source file with all 429 of the contract's methods that then can be imported and used as a regular Go 430 package. 431 432 ``` 433 $ ./bin/neo-go contract generate-wrapper --manifest manifest.json --out wrapper.go --hash 0x1b4357bff5a01bdf2a6581247cf9ed1e24629176 434 ``` 435 436 Notice that some structured types can be omitted this way (when a function 437 returns some structure it's just an "Array" type in the manifest with no 438 internal details), but if the contract you're using is written in Go 439 originally you can create a specific configuration file during compilation 440 that will add this data for wrapper generator to use: 441 442 ``` 443 $ ./bin/neo-go contract compile -i contract.go --config contract.yml -o contract.nef --manifest manifest.json --bindings contract.bindings.yml 444 $ ./bin/neo-go contract generate-wrapper --manifest manifest.json --config contract.bindings.yml --out wrapper.go --hash 0x1b4357bff5a01bdf2a6581247cf9ed1e24629176 445 ``` 446 447 ### Generating RPC contract bindings 448 To simplify interacting with the contract via RPC you can generate 449 contract-specific RPC bindings with the "generate-rpcwrapper" command. It 450 generates ContractReader structure for safe methods that accept appropriate 451 data for input and return things returned by the contract. State-changing 452 methods are contained in Contract structure with each contract method 453 represented by three wrapper methods that create/send transaction with a 454 script performing appropriate action. This script invokes contract method and 455 does not do anything else unless the method's returned value is of a boolean 456 type, in this case an ASSERT is added to script making it fail when the method 457 returns false. 458 459 ``` 460 $ ./bin/neo-go contract generate-rpcwrapper --manifest manifest.json --out rpcwrapper.go --hash 0x1b4357bff5a01bdf2a6581247cf9ed1e24629176 461 ``` 462 463 If your contract is NEP-11 or NEP-17 that's autodetected and an appropriate 464 package is included as well. Notice that the type data available in the 465 manifest is limited, so in some cases the interface generated may use generic 466 stackitem types. Any InteropInterface returned from a method is treated as 467 iterator and an appropriate unwrapper is used with UUID and iterator structure 468 result. This pair can then be used in Invoker `TraverseIterator` method to 469 retrieve actual resulting items. 470 471 Go contracts can also make use of additional type data from bindings 472 configuration file generated during compilation. This can cover arrays, maps 473 and structures. Notice that structured types returned by methods can't be Null 474 at the moment (see #2795). 475 476 ``` 477 $ ./bin/neo-go contract compile -i contract.go --config contract.yml -o contract.nef --manifest manifest.json --bindings contract.bindings.yml --guess-eventtypes 478 $ ./bin/neo-go contract generate-rpcwrapper --manifest manifest.json --config contract.bindings.yml --out rpcwrapper.go --hash 0x1b4357bff5a01bdf2a6581247cf9ed1e24629176 479 ``` 480 481 Contract-specific RPC-bindings generated by "generate-rpcwrapper" command include 482 structure wrappers for each event declared in the contract manifest as far as the 483 set of helpers that allow to retrieve emitted event from the application log or 484 from stackitem. By default, event wrappers builder use event structure that was 485 described in the manifest. Since the type data available in the manifest is 486 limited, in some cases the resulting generated event structure may use generic 487 go types. Go contracts can make use of additional type data from bindings 488 configuration file generated during compilation. Like for any other contract 489 types, this can cover arrays, maps and structures. To reach the maximum 490 resemblance between the emitted events and the generated event wrappers, we 491 recommend either to fill in the extended events type information in the contract 492 configuration file before the compilation or to use `--guess-eventtypes` 493 compilation option. 494 495 If using `--guess-eventtypes` compilation option, event parameter types will be 496 guessed from the arguments of `runtime.Notify` calls for each emitted event. If 497 multiple calls of `runtime.Notify` are found, then argument types will be checked 498 for matching (guessed types must be the same across the particular event usages). 499 After that, the extended types binding configuration will be generated according 500 to the emitted events parameter types. `--guess-eventtypes` compilation option 501 is able to recognize those events that has a constant name known at a compilation 502 time and do not include variadic arguments usage. Thus, use this option if your 503 contract suites these requirements. Otherwise, we recommend to manually specify 504 extended event parameter types information in the contract configuration file. 505 506 Extended event parameter type information can be provided manually via contract 507 configuration file under the `events` section. Each event parameter specified in 508 this section may be supplied with additional parameter type information specified 509 under `extendedtype` subsection. The extended type information (`ExtendedType`) 510 has the following structure: 511 512 | Field | Type | Required | Meaning | 513 |-------------|---------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| 514 | `base` | Any valid [NEP-14 parameter type](https://github.com/neo-project/proposals/blob/master/nep-14.mediawiki#parametertype) except `Void`. | Always required. | The base type of a parameter, e.g. `Array` for go structures and any nested arrays, `Map` for nested maps, `Hash160` for 160-bits integers, etc. | 515 | `name` | `string` | Required for structures, omitted for arrays, interfaces and maps. | Name of a structure that will be used in the resulting RPC binding. | 516 | `interface` | `string` | Required for `InteropInterface`-based types, currently `iterator` only is supported. | Underlying value of the `InteropInterface`. | 517 | `key` | Any simple [NEP-14 parameter type](https://github.com/neo-project/proposals/blob/master/nep-14.mediawiki#parametertype). | Required for `Map`-based types. | Key type for maps. | 518 | `value` | `ExtendedType`. | Required for iterators, arrays and maps. | Value type of iterators, arrays and maps. | 519 | `fields` | Array of `FieldExtendedType`. | Required for structures. | Ordered type data for structure fields. | 520 521 The structure's field extended information (`FieldExtendedType`) has the following structure: 522 523 | Field | Type | Required | Meaning | 524 |------------------------|----------------|------------------|-----------------------------------------------------------------------------| 525 | `field` | `string` | Always required. | Name of the structure field that will be used in the resulting RPC binding. | 526 | Inlined `ExtendedType` | `ExtendedType` | Always required. | The extended type information about structure field. | 527 528 529 Any named structures used in the `ExtendedType` description must be manually 530 specified in the contract configuration file under top-level `namedtypes` section 531 in the form of `map[string]ExtendedType`, where the map key is a name of the 532 described named structure that matches the one provided in the `name` field of 533 the event parameter's extended type. 534 535 Here's the example of manually-created contract configuration file that uses 536 extended types for event parameters description: 537 538 ``` 539 name: "HelloWorld contract" 540 supportedstandards: [] 541 events: 542 - name: Some simple notification 543 parameters: 544 - name: intP 545 type: Integer 546 - name: boolP 547 type: Boolean 548 - name: stringP 549 type: String 550 - name: Structure notification 551 parameters: 552 - name: structure parameter 553 type: Array 554 extendedtype: 555 base: Array 556 name: transferData 557 - name: Map of structures notification 558 parameters: 559 - name: map parameter 560 type: Map 561 extendedtype: 562 base: Map 563 key: Integer 564 value: 565 base: Array 566 name: transferData 567 - name: Iterator notification 568 parameters: 569 - name: data 570 type: InteropInterface 571 extendedtype: 572 base: InteropInterface 573 interface: iterator 574 namedtypes: 575 transferData: 576 base: Array 577 fields: 578 - field: IntField 579 base: Integer 580 - field: BoolField 581 base: Boolean 582 ``` 583 584 ## Smart contract examples 585 586 Some examples are provided in the [examples directory](../examples). For more 587 sophisticated real-world contracts written in Go check out [NeoFS 588 contracts](https://github.com/nspcc-dev/neofs-contract/). 589 590 ## How to report compiler bugs 591 1. Make a proper testcase (example testcases can be found in the tests folder) 592 2. Create an issue on Github 593 3. Make a PR with a reference to the created issue, containing the testcase that proves the bug 594 4. Either you fix the bug yourself or wait for patch that solves the problem