2018-02-09 16:08:50 +00:00
package smartcontract
import (
2018-03-05 08:53:09 +00:00
"encoding/hex"
"encoding/json"
2020-08-06 14:44:08 +00:00
"errors"
2018-03-05 08:53:09 +00:00
"fmt"
2018-08-25 14:40:15 +00:00
"os"
"path/filepath"
2020-03-11 18:11:51 +00:00
"strings"
2022-08-07 18:59:25 +00:00
"time"
2018-03-05 08:53:09 +00:00
2021-04-21 07:54:10 +00:00
"github.com/nspcc-dev/neo-go/cli/cmdargs"
2020-03-11 18:11:51 +00:00
"github.com/nspcc-dev/neo-go/cli/flags"
2020-08-31 09:22:09 +00:00
"github.com/nspcc-dev/neo-go/cli/input"
2020-06-17 21:15:13 +00:00
"github.com/nspcc-dev/neo-go/cli/options"
2020-10-02 13:13:17 +00:00
"github.com/nspcc-dev/neo-go/cli/paramcontext"
2022-06-23 13:50:21 +00:00
cliwallet "github.com/nspcc-dev/neo-go/cli/wallet"
2020-03-03 14:21:42 +00:00
"github.com/nspcc-dev/neo-go/pkg/compiler"
2020-11-18 20:10:48 +00:00
"github.com/nspcc-dev/neo-go/pkg/core/state"
2020-06-11 08:45:17 +00:00
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
2020-03-11 18:11:51 +00:00
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
2020-12-01 08:40:58 +00:00
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
2022-07-22 16:09:29 +00:00
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
2022-08-07 12:17:52 +00:00
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
2022-08-16 15:17:07 +00:00
"github.com/nspcc-dev/neo-go/pkg/rpcclient/management"
2020-03-03 14:21:42 +00:00
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
2020-06-09 13:12:58 +00:00
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
2020-06-25 16:21:49 +00:00
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
2020-03-03 14:21:42 +00:00
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
2020-03-11 18:11:51 +00:00
"github.com/nspcc-dev/neo-go/pkg/wallet"
2018-02-09 16:08:50 +00:00
"github.com/urfave/cli"
2021-09-25 10:09:55 +00:00
"gopkg.in/yaml.v3"
2018-02-09 16:08:50 +00:00
)
2022-06-23 13:50:21 +00:00
// addressFlagName is a flag name used for address-related operations. It should be
// the same within the smartcontract package, thus, use this constant.
const addressFlagName = "address, a"
2018-08-25 14:40:15 +00:00
var (
2022-06-23 13:50:21 +00:00
errNoInput = errors . New ( "no input file was found, specify an input file with the '--in or -i' flag" )
errNoConfFile = errors . New ( "no config file was found, specify a config file with the '--config' or '-c' flag" )
errNoManifestFile = errors . New ( "no manifest file was found, specify manifest file with '--manifest' or '-m' flag" )
errNoMethod = errors . New ( "no method specified for function invocation command" )
errNoWallet = errors . New ( "no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag" )
errConflictingWalletFlags = errors . New ( "--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location" )
errNoScriptHash = errors . New ( "no smart contract hash was provided, specify one as the first argument" )
errNoSmartContractName = errors . New ( "no name was provided, specify the '--name or -n' flag" )
errFileExist = errors . New ( "A file with given smart-contract name already exists" )
2019-11-29 15:16:46 +00:00
2020-03-11 18:11:51 +00:00
walletFlag = cli . StringFlag {
Name : "wallet, w" ,
2022-06-23 13:50:21 +00:00
Usage : "wallet to use to get the key for transaction signing; conflicts with --wallet-config flag" ,
}
walletConfigFlag = cli . StringFlag {
Name : "wallet-config" ,
Usage : "path to wallet config to use to get the key for transaction signing; conflicts with --wallet flag" ,
2020-03-11 18:11:51 +00:00
}
addressFlag = flags . AddressFlag {
2022-06-23 13:50:21 +00:00
Name : addressFlagName ,
2020-03-11 18:11:51 +00:00
Usage : "address to use as transaction signee (and gas source)" ,
2019-11-29 15:59:55 +00:00
}
2020-03-12 16:41:54 +00:00
gasFlag = flags . Fixed8Flag {
2019-11-29 15:59:55 +00:00
Name : "gas, g" ,
2021-07-01 16:03:30 +00:00
Usage : "network fee to add to the transaction (prioritizing it)" ,
}
sysGasFlag = flags . Fixed8Flag {
Name : "sysgas, e" ,
Usage : "system fee to add to transaction (compensating for execution)" ,
2019-11-29 15:59:55 +00:00
}
2020-10-02 13:13:17 +00:00
outFlag = cli . StringFlag {
Name : "out" ,
Usage : "file to put JSON transaction to" ,
}
2020-12-04 07:59:46 +00:00
forceFlag = cli . BoolFlag {
2020-10-12 09:45:38 +00:00
Name : "force" ,
Usage : "force-push the transaction in case of bad VM state after test script invocation" ,
}
2018-08-25 14:40:15 +00:00
)
2022-01-14 11:18:33 +00:00
// ModVersion contains `pkg/interop` module version
// suitable to be used in go.mod.
var ModVersion string
2019-11-29 15:11:49 +00:00
const (
2018-08-25 14:40:15 +00:00
// smartContractTmpl is written to a file when used with `init` command.
2021-05-12 20:17:03 +00:00
// %s is parsed to be the smartContractName.
2018-08-25 14:40:15 +00:00
smartContractTmpl = ` package % s
2020-03-03 14:21:42 +00:00
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
2018-08-25 14:40:15 +00:00
2020-08-10 13:01:56 +00:00
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 )
2018-08-25 14:40:15 +00:00
} `
2018-02-24 09:10:45 +00:00
)
2019-10-19 20:58:45 +00:00
// NewCommands returns 'contract' command.
func NewCommands ( ) [ ] cli . Command {
2020-06-17 21:15:13 +00:00
testInvokeScriptFlags := [ ] cli . Flag {
cli . StringFlag {
Name : "in, i" ,
2020-06-25 16:21:49 +00:00
Usage : "Input location of the .nef file that needs to be invoked" ,
2020-06-17 21:15:13 +00:00
} ,
}
testInvokeScriptFlags = append ( testInvokeScriptFlags , options . RPC ... )
invokeFunctionFlags := [ ] cli . Flag {
walletFlag ,
2022-06-23 13:50:21 +00:00
walletConfigFlag ,
2020-06-17 21:15:13 +00:00
addressFlag ,
gasFlag ,
2021-07-01 16:03:30 +00:00
sysGasFlag ,
2020-10-02 13:13:17 +00:00
outFlag ,
2020-10-12 09:45:38 +00:00
forceFlag ,
2020-06-17 21:15:13 +00:00
}
invokeFunctionFlags = append ( invokeFunctionFlags , options . RPC ... )
2021-04-22 12:14:02 +00:00
deployFlags := append ( invokeFunctionFlags , [ ] cli . Flag {
cli . StringFlag {
Name : "in, i" ,
Usage : "Input file for the smart contract (*.nef)" ,
} ,
cli . StringFlag {
Name : "manifest, m" ,
Usage : "Manifest input file (*.manifest.json)" ,
} ,
} ... )
2019-10-19 20:58:45 +00:00
return [ ] cli . Command { {
2018-02-09 16:08:50 +00:00
Name : "contract" ,
Usage : "compile - debug - deploy smart contracts" ,
Subcommands : [ ] cli . Command {
{
2022-08-05 13:23:50 +00:00
Name : "compile" ,
Usage : "compile a smart contract to a .nef file" ,
UsageText : "neo-go contract compile -i path [-o nef] [-v] [-d] [-m manifest] [-c yaml] [--bindings file] [--no-standards] [--no-events] [--no-permissions]" ,
Action : contractCompile ,
2018-02-15 15:35:49 +00:00
Flags : [ ] cli . Flag {
2018-02-24 09:10:45 +00:00
cli . StringFlag {
Name : "in, i" ,
Usage : "Input file for the smart contract to be compiled" ,
} ,
2018-02-15 15:35:49 +00:00
cli . StringFlag {
Name : "out, o" ,
Usage : "Output of the compiled contract" ,
} ,
2018-03-25 16:21:00 +00:00
cli . BoolFlag {
2020-04-06 12:32:06 +00:00
Name : "verbose, v" ,
Usage : "Print out additional information after a compiling" ,
2018-03-25 16:21:00 +00:00
} ,
2020-04-02 12:38:53 +00:00
cli . StringFlag {
2020-04-08 10:11:44 +00:00
Name : "debug, d" ,
2020-04-02 12:38:53 +00:00
Usage : "Emit debug info in a separate file" ,
} ,
compiler: add ability to generate .abi.json file
A part of integration with NEO Blockchain Toolkit (see #902). To be
able to deploy smart-contract compiled with neo-go compiler via NEO
Express, we have to generate additional .abi.json file. This file
contains the following information:
- hash of the compiled contract
- smart-contract metadata (title, description, version, author,
email, has-storage, has-dynamic-invoke, is-payable)
- smart-contract entry point
- functions
- events
However, this .abi.json file is slightly different from the one,
described in manifest.go, so we have to add auxilaury stractures for
json marshalling. The .abi.json format used by NEO-Express is described
[here](https://github.com/neo-project/neo-devpack-dotnet/blob/master/src/Neo.Compiler.MSIL/FuncExport.cs#L66).
2020-04-28 16:39:01 +00:00
cli . StringFlag {
2020-06-25 13:10:08 +00:00
Name : "manifest, m" ,
Usage : "Emit contract manifest (*.manifest.json) file into separate file using configuration input file (*.yml)" ,
compiler: add ability to generate .abi.json file
A part of integration with NEO Blockchain Toolkit (see #902). To be
able to deploy smart-contract compiled with neo-go compiler via NEO
Express, we have to generate additional .abi.json file. This file
contains the following information:
- hash of the compiled contract
- smart-contract metadata (title, description, version, author,
email, has-storage, has-dynamic-invoke, is-payable)
- smart-contract entry point
- functions
- events
However, this .abi.json file is slightly different from the one,
described in manifest.go, so we have to add auxilaury stractures for
json marshalling. The .abi.json format used by NEO-Express is described
[here](https://github.com/neo-project/neo-devpack-dotnet/blob/master/src/Neo.Compiler.MSIL/FuncExport.cs#L66).
2020-04-28 16:39:01 +00:00
} ,
cli . StringFlag {
Name : "config, c" ,
Usage : "Configuration input file (*.yml)" ,
} ,
2020-11-24 10:38:24 +00:00
cli . BoolFlag {
Name : "no-standards" ,
Usage : "do not check compliance with supported standards" ,
} ,
2020-11-24 13:36:35 +00:00
cli . BoolFlag {
Name : "no-events" ,
Usage : "do not check emitted events with the manifest" ,
} ,
2021-06-24 15:36:40 +00:00
cli . BoolFlag {
Name : "no-permissions" ,
Usage : "do not check if invoked contracts are allowed in manifest" ,
} ,
2022-02-11 12:16:15 +00:00
cli . StringFlag {
Name : "bindings" ,
Usage : "output file for smart-contract bindings configuration" ,
} ,
2018-02-15 15:35:49 +00:00
} ,
2018-02-09 16:08:50 +00:00
} ,
2019-11-20 13:07:43 +00:00
{
2021-04-16 14:48:00 +00:00
Name : "deploy" ,
Usage : "deploy a smart contract (.nef with description)" ,
2021-07-01 16:03:30 +00:00
UsageText : "neo-go contract deploy -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] --in contract.nef --manifest contract.manifest.json [--out file] [--force] [data]" ,
2020-03-11 17:32:06 +00:00
Description : ` Deploys given contract into the chain . The gas parameter is for additional
2021-04-16 15:04:19 +00:00
gas to be added as a network fee to prioritize the transaction . The data
parameter is an optional parameter to be passed to ' _deploy ' method .
2020-03-11 17:32:06 +00:00
` ,
2019-11-20 13:07:43 +00:00
Action : contractDeploy ,
2020-06-17 21:15:13 +00:00
Flags : deployFlags ,
2019-11-29 15:59:55 +00:00
} ,
2021-10-25 11:48:21 +00:00
generateWrapperCmd ,
2019-11-29 15:59:55 +00:00
{
Name : "invokefunction" ,
Usage : "invoke deployed contract on the blockchain" ,
2021-07-01 16:03:30 +00:00
UsageText : "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] [--out file] [--force] scripthash [method] [arguments...] [--] [signers...]" ,
2020-06-11 08:45:17 +00:00
Description : ` Executes given ( as a script hash ) deployed script with the given method ,
2020-07-29 16:57:38 +00:00
arguments and signers . Sender is included in the list of signers by default
2020-10-01 12:26:51 +00:00
with None witness scope . If you ' d like to change default sender ' s scope ,
2020-07-29 16:57:38 +00:00
specify it via signers parameter . See testinvokefunction documentation for
the details about parameters . It differs from testinvokefunction in that this
command sends an invocation transaction to the network .
2019-11-29 15:59:55 +00:00
` ,
Action : invokeFunction ,
2020-06-17 21:15:13 +00:00
Flags : invokeFunctionFlags ,
2019-11-20 13:07:43 +00:00
} ,
2019-11-27 09:52:15 +00:00
{
Name : "testinvokefunction" ,
Usage : "invoke deployed contract on the blockchain (test mode)" ,
2020-07-29 16:57:38 +00:00
UsageText : "neo-go contract testinvokefunction -r endpoint scripthash [method] [arguments...] [--] [signers...]" ,
2020-06-11 08:45:17 +00:00
Description : ` Executes given ( as a script hash ) deployed script with the given method ,
2020-07-29 16:57:38 +00:00
arguments and signers ( sender is not included by default ) . If no method is given
"" is passed to the script , if no arguments are given , an empty array is
passed , if no signers are given no array is passed . If signers are specified ,
the first one of them is treated as a sender . All of the given arguments are
encapsulated into array before invoking the script . The script thus should
follow the regular convention of smart contract arguments ( method string and
an array of other arguments ) .
2019-11-27 09:52:15 +00:00
Arguments always do have regular Neo smart contract parameter types , either
specified explicitly or being inferred from the value . To specify the type
manually use "type:value" syntax where the type is one of the following :
' signature ' , ' bool ' , ' int ' , ' hash160 ' , ' hash256 ' , ' bytes ' , ' key ' or ' string ' .
2020-08-26 09:08:17 +00:00
Array types are also supported : use special space - separated '[' and ']'
symbols around array values to denote array bounds . Nested arrays are also
supported .
2019-11-27 09:52:15 +00:00
2021-02-18 15:13:03 +00:00
There is ability to provide an argument of ' bytearray ' type via file . Use a
special ' filebytes ' argument type for this with a filepath specified after
the colon , e . g . ' filebytes : my_file . txt ' .
2019-11-27 09:52:15 +00:00
Given values are type - checked against given types with the following
restrictions applied :
* ' signature ' type values should be hex - encoded and have a ( decoded )
length of 64 bytes .
* ' bool ' type values are ' true ' and ' false ' .
* ' int ' values are decimal integers that can be successfully converted
from the string .
* ' hash160 ' values are Neo addresses and hex - encoded 20 - bytes long ( after
decoding ) strings .
* ' hash256 ' type values should be hex - encoded and have a ( decoded )
length of 32 bytes .
* ' bytes ' type values are any hex - encoded things .
2021-02-18 15:13:03 +00:00
* ' filebytes ' type values are filenames with the argument value inside .
2019-11-27 09:52:15 +00:00
* ' key ' type values are hex - encoded marshalled public keys .
* ' string ' type values are any valid UTF - 8 strings . In the value ' s part of
the string the colon looses it ' s special meaning as a separator between
type and value and is taken literally .
If no type is explicitly specified , it is inferred from the value using the
following logic :
- anything that can be interpreted as a decimal integer gets
an ' int ' type
- ' true ' and ' false ' strings get ' bool ' type
- valid Neo addresses and 20 bytes long hex - encoded strings get ' hash160 '
type
- valid hex - encoded public keys get ' key ' type
- 32 bytes long hex - encoded values get ' hash256 ' type
- 64 bytes long hex - encoded values get ' signature ' type
- any other valid hex - encoded values get ' bytes ' type
- anything else is a ' string '
Backslash character is used as an escape character and allows to use colon in
an implicitly typed string . For any other characters it has no special
meaning , to get a literal backslash in the string use the '\\' sequence .
Examples :
* ' int : 42 ' is an integer with a value of 42
* ' 42 ' is an integer with a value of 42
* ' bad ' is a string with a value of ' bad '
* ' dead ' is a byte array with a value of ' dead '
* ' string : dead ' is a string with a value of ' dead '
2021-02-18 15:13:03 +00:00
* ' filebytes : my_data . txt ' is bytes decoded from a content of my_data . txt
2019-11-27 09:52:15 +00:00
* ' AK2nJJpJr6o664CWJKi1QRXjqeic2zRp8y ' is a hash160 with a value
of ' 23 ba2703c53263e8d6e522dc32203339dcd8eee9 '
* ' \ 4 \ 2 ' is an integer with a value of 42
* ' \ \ 4 \ 2 ' is a string with a value of '\42'
* ' string : string ' is a string with a value of ' string '
* ' string \ : string ' is a string with a value of ' string : string '
* ' 03 b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c ' is a
key with a value of ' 03 b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c '
2020-08-26 09:08:17 +00:00
* ' [ a b c ] ' is an array with strings values 'a' , 'b' and 'c'
* ' [ a b [ c d ] e ] ' is an array with 4 values : string 'a' , string 'b' ,
array of two strings 'c' and 'd' , string 'e'
* ' [ ] ' is an empty array
2020-06-11 08:45:17 +00:00
2020-07-29 16:57:38 +00:00
Signers represent a set of Uint160 hashes with witness scopes and are used
to verify hashes in System . Runtime . CheckWitness syscall . First signer is treated
as a sender . To specify signers use signer [ : scope ] syntax where
2021-01-27 19:32:29 +00:00
* ' signer ' is a signer ' s address ( as Neo address or hex - encoded 160 bit ( 20 byte )
LE value with or without ' 0 x ' prefix ) .
2020-06-11 08:45:17 +00:00
* ' scope ' is a comma - separated set of cosigner ' s scopes , which could be :
2020-10-01 12:26:51 +00:00
- ' None ' - default witness scope which may be used for the sender
to only pay fee for the transaction .
2020-06-11 08:45:17 +00:00
- ' Global ' - allows this witness in all contexts . This cannot be combined
with other flags .
- ' CalledByEntry ' - means that this condition must hold : EntryScriptHash
== CallingScriptHash . The witness / permission / signature
given on first invocation will automatically expire if
entering deeper internal invokes . This can be default
safe choice for native NEO / GAS .
- ' CustomContracts ' - define valid custom contract hashes for witness check .
2021-05-24 13:21:53 +00:00
Hashes are be provided as hex - encoded LE value string .
At lest one hash must be provided . Multiple hashes
are separated by ':' .
- ' CustomGroups ' - define custom public keys for group members . Public keys are
provided as short - form ( 1 - byte prefix + 32 bytes ) hex - encoded
values . At least one key must be provided . Multiple keys
are separated by ':' .
2020-06-11 08:45:17 +00:00
2021-04-19 08:52:28 +00:00
If no scopes were specified , ' CalledByEntry ' used as default . If no signers were
2020-07-29 16:57:38 +00:00
specified , no array is passed . Note that scopes are properly handled by
2020-06-11 08:45:17 +00:00
neo - go RPC server only . C # implementation does not support scopes capability .
Examples :
2021-01-27 19:32:29 +00:00
* ' NNQk4QXsxvsrr3GSozoWBUxEmfag7B6hz5 '
* ' NVquyZHoPirw6zAEPvY1ZezxM493zMWQqs : Global '
2020-06-11 08:45:17 +00:00
* ' 0x0000000009070e030d0f0e020d0c06050e030c02 '
2021-05-24 13:21:53 +00:00
* ' 0000000009070e030 d0f0e020d0c06050e030c02 : CalledByEntry , ` +
` CustomGroups : 0206 d7495ceb34c197093b5fc1cccf1996ada05e69ef67e765462a7f5d88ee14d0 '
* ' 0000000009070e030 d0f0e020d0c06050e030c02 : CalledByEntry , ` +
` CustomContracts : 1011120009070e030 d0f0e020d0c06050e030c02 : 0x1211100009070e030d0f0e020d0c06050e030c02 '
2019-11-27 09:52:15 +00:00
` ,
Action : testInvokeFunction ,
2020-06-17 21:15:13 +00:00
Flags : options . RPC ,
2019-11-27 09:52:15 +00:00
} ,
2018-03-05 08:53:09 +00:00
{
2020-06-11 08:45:17 +00:00
Name : "testinvokescript" ,
2020-06-25 16:21:49 +00:00
Usage : "Invoke compiled AVM code in NEF format on the blockchain (test mode, not creating a transaction for it)" ,
2020-07-29 16:57:38 +00:00
UsageText : "neo-go contract testinvokescript -r endpoint -i input.nef [signers...]" ,
2020-06-25 16:21:49 +00:00
Description : ` Executes given compiled AVM instructions in NEF format with the given set of
2020-07-29 16:57:38 +00:00
signers not included sender by default . See testinvokefunction documentation
for the details about parameters .
2020-06-11 08:45:17 +00:00
` ,
2019-11-26 14:00:43 +00:00
Action : testInvokeScript ,
2020-06-17 21:15:13 +00:00
Flags : testInvokeScriptFlags ,
2018-03-05 08:53:09 +00:00
} ,
2018-08-25 14:40:15 +00:00
{
2022-08-05 13:23:50 +00:00
Name : "init" ,
Usage : "initialize a new smart-contract in a directory with boiler plate code" ,
UsageText : "neo-go contract init -n name [--skip-details]" ,
Action : initSmartContract ,
2018-08-25 14:40:15 +00:00
Flags : [ ] cli . Flag {
cli . StringFlag {
Name : "name, n" ,
Usage : "name of the smart-contract to be initialized" ,
} ,
2018-10-16 06:33:29 +00:00
cli . BoolFlag {
Name : "skip-details, skip" ,
Usage : "skip filling in the projects and contract details" ,
} ,
2018-08-25 14:40:15 +00:00
} ,
} ,
2018-10-23 08:23:03 +00:00
{
2022-08-05 13:23:50 +00:00
Name : "inspect" ,
Usage : "creates a user readable dump of the program instructions" ,
UsageText : "neo-go contract inspect -i file [-c]" ,
Action : inspect ,
2018-10-23 08:23:03 +00:00
Flags : [ ] cli . Flag {
2019-10-29 09:56:44 +00:00
cli . BoolFlag {
Name : "compile, c" ,
Usage : "compile input file (it should be go code then)" ,
} ,
2018-10-23 08:23:03 +00:00
cli . StringFlag {
Name : "in, i" ,
2020-06-25 16:21:49 +00:00
Usage : "input file of the program (either .go or .nef)" ,
2018-10-23 08:23:03 +00:00
} ,
} ,
} ,
2020-12-17 12:41:53 +00:00
{
2022-08-05 13:23:50 +00:00
Name : "calc-hash" ,
Usage : "calculates hash of a contract after deployment" ,
UsageText : "neo-go contract calc-hash -i nef -m manifest -s address" ,
Action : calcHash ,
2020-12-17 12:41:53 +00:00
Flags : [ ] cli . Flag {
2021-04-16 09:09:59 +00:00
flags . AddressFlag {
2020-12-17 12:41:53 +00:00
Name : "sender, s" ,
Usage : "sender script hash or address" ,
} ,
cli . StringFlag {
Name : "in" ,
Usage : "path to NEF file" ,
} ,
2021-01-22 09:22:48 +00:00
cli . StringFlag {
Name : "manifest, m" ,
Usage : "path to manifest file" ,
} ,
2020-12-17 12:41:53 +00:00
} ,
} ,
2021-08-02 08:10:26 +00:00
{
Name : "manifest" ,
Usage : "manifest-related commands" ,
Subcommands : [ ] cli . Command {
{
2022-08-05 13:23:50 +00:00
Name : "add-group" ,
Usage : "adds group to the manifest" ,
UsageText : "neo-go contract manifest add-group -w wallet [--wallet-config path] -n nef -m manifest -a address -s address" ,
Action : manifestAddGroup ,
2021-08-02 08:10:26 +00:00
Flags : [ ] cli . Flag {
walletFlag ,
2022-06-23 13:50:21 +00:00
walletConfigFlag ,
2021-08-02 08:10:26 +00:00
cli . StringFlag {
Name : "sender, s" ,
Usage : "deploy transaction sender" ,
} ,
2022-06-23 13:50:21 +00:00
flags . AddressFlag {
Name : addressFlagName , // use the same name for handler code unification.
2021-08-02 08:10:26 +00:00
Usage : "account to sign group with" ,
} ,
cli . StringFlag {
Name : "nef, n" ,
Usage : "path to the NEF file" ,
} ,
cli . StringFlag {
Name : "manifest, m" ,
Usage : "path to the manifest" ,
} ,
} ,
} ,
} ,
} ,
2018-02-09 16:08:50 +00:00
} ,
2019-10-19 20:58:45 +00:00
} }
2018-02-09 16:08:50 +00:00
}
2018-08-25 14:40:15 +00:00
// initSmartContract initializes a given directory with some boiler plate code.
func initSmartContract ( ctx * cli . Context ) error {
2022-08-05 10:32:37 +00:00
if err := cmdargs . EnsureNone ( ctx ) ; err != nil {
return err
}
2018-10-16 06:33:29 +00:00
contractName := ctx . String ( "name" )
if contractName == "" {
2018-08-25 14:40:15 +00:00
return cli . NewExitError ( errNoSmartContractName , 1 )
}
// Check if the file already exists, if yes, exit
2018-10-16 06:33:29 +00:00
if _ , err := os . Stat ( contractName ) ; err == nil {
2018-08-25 14:40:15 +00:00
return cli . NewExitError ( errFileExist , 1 )
}
2018-10-16 06:33:29 +00:00
basePath := contractName
2021-11-17 11:14:22 +00:00
contractName = filepath . Base ( contractName )
2018-08-25 14:40:15 +00:00
fileName := "main.go"
// create base directory
2018-10-16 06:33:29 +00:00
if err := os . Mkdir ( basePath , os . ModePerm ) ; err != nil {
2018-08-25 14:40:15 +00:00
return cli . NewExitError ( err , 1 )
}
2020-08-04 09:55:36 +00:00
m := ProjectConfig {
2020-11-20 08:02:58 +00:00
Name : contractName ,
2021-09-23 21:19:37 +00:00
SourceURL : "http://example.com/" ,
2020-08-04 09:55:36 +00:00
SupportedStandards : [ ] string { } ,
2020-12-10 14:55:52 +00:00
SafeMethods : [ ] string { } ,
2020-08-10 13:01:56 +00:00
Events : [ ] manifest . Event {
{
Name : "Hello world!" ,
Parameters : [ ] manifest . Parameter {
{
Name : "args" ,
Type : smartcontract . ArrayType ,
} ,
} ,
} ,
} ,
2021-06-02 07:50:17 +00:00
Permissions : [ ] permission { permission ( * manifest . NewPermission ( manifest . PermissionWildcard ) ) } ,
2020-08-04 09:55:36 +00:00
}
2020-06-09 13:12:58 +00:00
b , err := yaml . Marshal ( m )
if err != nil {
return cli . NewExitError ( err , 1 )
}
2022-02-22 16:27:32 +00:00
if err := os . WriteFile ( filepath . Join ( basePath , "neo-go.yml" ) , b , 0644 ) ; err != nil {
2020-06-09 13:12:58 +00:00
return cli . NewExitError ( err , 1 )
2018-10-16 06:33:29 +00:00
}
2022-01-14 11:18:33 +00:00
ver := ModVersion
if ver == "" {
ver = "latest"
}
2021-12-02 14:44:53 +00:00
gm := [ ] byte ( "module " + contractName + `
require (
2022-01-14 11:18:33 +00:00
github . com / nspcc - dev / neo - go / pkg / interop ` + ver + `
2021-12-02 14:44:53 +00:00
) ` )
2022-02-22 16:27:32 +00:00
if err := os . WriteFile ( filepath . Join ( basePath , "go.mod" ) , gm , 0644 ) ; err != nil {
2021-12-02 14:44:53 +00:00
return cli . NewExitError ( err , 1 )
}
2018-10-16 06:33:29 +00:00
data := [ ] byte ( fmt . Sprintf ( smartContractTmpl , contractName ) )
2022-02-22 16:27:32 +00:00
if err := os . WriteFile ( filepath . Join ( basePath , fileName ) , data , 0644 ) ; err != nil {
2018-08-25 14:40:15 +00:00
return cli . NewExitError ( err , 1 )
}
2018-10-16 06:33:29 +00:00
2020-08-28 09:11:19 +00:00
fmt . Fprintf ( ctx . App . Writer , "Successfully initialized smart contract [%s]\n" , contractName )
2018-10-16 06:33:29 +00:00
2018-08-25 14:40:15 +00:00
return nil
}
2018-02-09 16:08:50 +00:00
func contractCompile ( ctx * cli . Context ) error {
2022-08-05 10:32:37 +00:00
if err := cmdargs . EnsureNone ( ctx ) ; err != nil {
return err
}
2018-02-24 09:10:45 +00:00
src := ctx . String ( "in" )
if len ( src ) == 0 {
2018-03-05 08:53:09 +00:00
return cli . NewExitError ( errNoInput , 1 )
2018-02-15 15:35:49 +00:00
}
2020-06-25 13:10:08 +00:00
manifestFile := ctx . String ( "manifest" )
compiler: add ability to generate .abi.json file
A part of integration with NEO Blockchain Toolkit (see #902). To be
able to deploy smart-contract compiled with neo-go compiler via NEO
Express, we have to generate additional .abi.json file. This file
contains the following information:
- hash of the compiled contract
- smart-contract metadata (title, description, version, author,
email, has-storage, has-dynamic-invoke, is-payable)
- smart-contract entry point
- functions
- events
However, this .abi.json file is slightly different from the one,
described in manifest.go, so we have to add auxilaury stractures for
json marshalling. The .abi.json format used by NEO-Express is described
[here](https://github.com/neo-project/neo-devpack-dotnet/blob/master/src/Neo.Compiler.MSIL/FuncExport.cs#L66).
2020-04-28 16:39:01 +00:00
confFile := ctx . String ( "config" )
2020-06-30 11:21:58 +00:00
debugFile := ctx . String ( "debug" )
if len ( confFile ) == 0 && ( len ( manifestFile ) != 0 || len ( debugFile ) != 0 ) {
compiler: add ability to generate .abi.json file
A part of integration with NEO Blockchain Toolkit (see #902). To be
able to deploy smart-contract compiled with neo-go compiler via NEO
Express, we have to generate additional .abi.json file. This file
contains the following information:
- hash of the compiled contract
- smart-contract metadata (title, description, version, author,
email, has-storage, has-dynamic-invoke, is-payable)
- smart-contract entry point
- functions
- events
However, this .abi.json file is slightly different from the one,
described in manifest.go, so we have to add auxilaury stractures for
json marshalling. The .abi.json format used by NEO-Express is described
[here](https://github.com/neo-project/neo-devpack-dotnet/blob/master/src/Neo.Compiler.MSIL/FuncExport.cs#L66).
2020-04-28 16:39:01 +00:00
return cli . NewExitError ( errNoConfFile , 1 )
}
2018-02-15 15:35:49 +00:00
2018-02-19 09:24:28 +00:00
o := & compiler . Options {
Outfile : ctx . String ( "out" ) ,
2020-04-02 12:38:53 +00:00
2020-06-30 11:21:58 +00:00
DebugInfo : debugFile ,
2020-06-25 13:10:08 +00:00
ManifestFile : manifestFile ,
2022-02-11 12:16:15 +00:00
BindingsFile : ctx . String ( "bindings" ) ,
2020-11-24 10:38:24 +00:00
2021-06-24 15:36:40 +00:00
NoStandardCheck : ctx . Bool ( "no-standards" ) ,
NoEventsCheck : ctx . Bool ( "no-events" ) ,
NoPermissionsCheck : ctx . Bool ( "no-permissions" ) ,
compiler: add ability to generate .abi.json file
A part of integration with NEO Blockchain Toolkit (see #902). To be
able to deploy smart-contract compiled with neo-go compiler via NEO
Express, we have to generate additional .abi.json file. This file
contains the following information:
- hash of the compiled contract
- smart-contract metadata (title, description, version, author,
email, has-storage, has-dynamic-invoke, is-payable)
- smart-contract entry point
- functions
- events
However, this .abi.json file is slightly different from the one,
described in manifest.go, so we have to add auxilaury stractures for
json marshalling. The .abi.json format used by NEO-Express is described
[here](https://github.com/neo-project/neo-devpack-dotnet/blob/master/src/Neo.Compiler.MSIL/FuncExport.cs#L66).
2020-04-28 16:39:01 +00:00
}
if len ( confFile ) != 0 {
2021-03-22 09:21:48 +00:00
conf , err := ParseContractConfig ( confFile )
compiler: add ability to generate .abi.json file
A part of integration with NEO Blockchain Toolkit (see #902). To be
able to deploy smart-contract compiled with neo-go compiler via NEO
Express, we have to generate additional .abi.json file. This file
contains the following information:
- hash of the compiled contract
- smart-contract metadata (title, description, version, author,
email, has-storage, has-dynamic-invoke, is-payable)
- smart-contract entry point
- functions
- events
However, this .abi.json file is slightly different from the one,
described in manifest.go, so we have to add auxilaury stractures for
json marshalling. The .abi.json format used by NEO-Express is described
[here](https://github.com/neo-project/neo-devpack-dotnet/blob/master/src/Neo.Compiler.MSIL/FuncExport.cs#L66).
2020-04-28 16:39:01 +00:00
if err != nil {
return err
}
2020-11-20 08:02:58 +00:00
o . Name = conf . Name
2021-09-23 21:19:37 +00:00
o . SourceURL = conf . SourceURL
2020-08-11 08:21:54 +00:00
o . ContractEvents = conf . Events
2020-08-04 09:55:36 +00:00
o . ContractSupportedStandards = conf . SupportedStandards
2021-06-02 07:50:17 +00:00
o . Permissions = make ( [ ] manifest . Permission , len ( conf . Permissions ) )
for i := range conf . Permissions {
o . Permissions [ i ] = manifest . Permission ( conf . Permissions [ i ] )
}
2020-12-10 14:55:52 +00:00
o . SafeMethods = conf . SafeMethods
2021-10-16 11:10:17 +00:00
o . Overloads = conf . Overloads
2018-02-15 15:35:49 +00:00
}
2019-11-22 14:16:52 +00:00
result , err := compiler . CompileAndSave ( src , o )
if err != nil {
2018-02-24 09:10:45 +00:00
return cli . NewExitError ( err , 1 )
}
2020-04-06 12:33:44 +00:00
if ctx . Bool ( "verbose" ) {
2020-08-28 09:11:19 +00:00
fmt . Fprintln ( ctx . App . Writer , hex . EncodeToString ( result ) )
2020-04-06 12:33:44 +00:00
}
2018-03-25 16:21:00 +00:00
2018-02-24 09:10:45 +00:00
return nil
2018-02-09 16:08:50 +00:00
}
2020-12-17 12:41:53 +00:00
func calcHash ( ctx * cli . Context ) error {
2022-08-05 10:32:37 +00:00
if err := cmdargs . EnsureNone ( ctx ) ; err != nil {
return err
}
2021-04-16 09:09:59 +00:00
sender := ctx . Generic ( "sender" ) . ( * flags . Address )
if ! sender . IsSet {
return cli . NewExitError ( "sender is not set" , 1 )
2020-12-17 12:41:53 +00:00
}
p := ctx . String ( "in" )
if p == "" {
return cli . NewExitError ( errors . New ( "no .nef file was provided" ) , 1 )
}
2021-01-22 09:22:48 +00:00
mpath := ctx . String ( "manifest" )
if mpath == "" {
return cli . NewExitError ( errors . New ( "no manifest file provided" ) , 1 )
}
2022-02-22 16:27:32 +00:00
f , err := os . ReadFile ( p )
2020-12-17 12:41:53 +00:00
if err != nil {
return cli . NewExitError ( fmt . Errorf ( "can't read .nef file: %w" , err ) , 1 )
}
nefFile , err := nef . FileFromBytes ( f )
if err != nil {
return cli . NewExitError ( fmt . Errorf ( "can't unmarshal .nef file: %w" , err ) , 1 )
}
2022-02-22 16:27:32 +00:00
manifestBytes , err := os . ReadFile ( mpath )
2021-01-22 09:22:48 +00:00
if err != nil {
return cli . NewExitError ( fmt . Errorf ( "failed to read manifest file: %w" , err ) , 1 )
}
m := & manifest . Manifest { }
err = json . Unmarshal ( manifestBytes , m )
if err != nil {
return cli . NewExitError ( fmt . Errorf ( "failed to restore manifest file: %w" , err ) , 1 )
}
2021-04-16 09:09:59 +00:00
fmt . Fprintln ( ctx . App . Writer , "Contract hash:" , state . CreateContractHash ( sender . Uint160 ( ) , nefFile . Checksum , m . Name ) . StringLE ( ) )
2020-12-17 12:41:53 +00:00
return nil
}
2019-11-27 09:52:15 +00:00
func testInvokeFunction ( ctx * cli . Context ) error {
2020-06-10 08:31:01 +00:00
return invokeInternal ( ctx , false )
2019-11-29 15:59:55 +00:00
}
func invokeFunction ( ctx * cli . Context ) error {
2020-06-10 08:31:01 +00:00
return invokeInternal ( ctx , true )
2019-11-29 15:59:55 +00:00
}
2020-06-10 08:31:01 +00:00
func invokeInternal ( ctx * cli . Context , signAndPush bool ) error {
2019-11-29 15:59:55 +00:00
var (
2021-04-22 12:14:02 +00:00
err error
exitErr * cli . ExitError
operation string
params = make ( [ ] smartcontract . Parameter , 0 )
paramsStart = 1
cosigners [ ] transaction . Signer
cosignersOffset = 0
2019-11-29 15:59:55 +00:00
)
2019-11-28 16:40:13 +00:00
2019-11-27 09:52:15 +00:00
args := ctx . Args ( )
if ! args . Present ( ) {
return cli . NewExitError ( errNoScriptHash , 1 )
}
2021-02-17 14:48:41 +00:00
script , err := flags . ParseAddress ( args [ 0 ] )
2020-07-02 13:38:33 +00:00
if err != nil {
2020-08-06 16:09:57 +00:00
return cli . NewExitError ( fmt . Errorf ( "incorrect script hash: %w" , err ) , 1 )
2020-07-02 13:38:33 +00:00
}
2020-06-10 08:31:01 +00:00
if len ( args ) <= 1 {
return cli . NewExitError ( errNoMethod , 1 )
2019-11-27 09:52:15 +00:00
}
2020-06-10 08:31:01 +00:00
operation = args [ 1 ]
paramsStart ++
2019-11-28 16:40:13 +00:00
if len ( args ) > paramsStart {
2021-04-21 10:14:55 +00:00
cosignersOffset , params , err = cmdargs . ParseParams ( args [ paramsStart : ] , true )
2020-08-26 09:08:17 +00:00
if err != nil {
return cli . NewExitError ( err , 1 )
2019-11-27 09:52:15 +00:00
}
}
2020-08-26 09:08:17 +00:00
cosignersStart := paramsStart + cosignersOffset
2021-04-21 07:54:10 +00:00
cosigners , exitErr = cmdargs . GetSignersFromContext ( ctx , cosignersStart )
if exitErr != nil {
return exitErr
2020-06-11 08:45:17 +00:00
}
2021-08-02 10:42:15 +00:00
var (
acc * wallet . Account
w * wallet . Wallet
)
if signAndPush {
acc , w , err = getAccFromContext ( ctx )
if err != nil {
return cli . NewExitError ( err , 1 )
}
2022-09-01 18:44:49 +00:00
defer w . Close ( )
2021-08-02 10:42:15 +00:00
}
2022-09-08 12:57:27 +00:00
return invokeWithArgs ( ctx , acc , w , script , operation , params , cosigners )
2021-04-22 12:14:02 +00:00
}
2022-09-08 12:57:27 +00:00
func invokeWithArgs ( ctx * cli . Context , acc * wallet . Account , wall * wallet . Wallet , script util . Uint160 , operation string , params [ ] smartcontract . Parameter , cosigners [ ] transaction . Signer ) error {
2021-04-22 12:14:02 +00:00
var (
2022-08-19 17:53:16 +00:00
err error
gas , sysgas fixedn . Fixed8
signersAccounts [ ] actor . SignerAccount
resp * result . Invoke
signAndPush = acc != nil
act * actor . Actor
2021-04-22 12:14:02 +00:00
)
2019-11-29 15:59:55 +00:00
if signAndPush {
2020-03-12 16:41:54 +00:00
gas = flags . Fixed8FromContext ( ctx , "gas" )
2021-07-01 16:03:30 +00:00
sysgas = flags . Fixed8FromContext ( ctx , "sysgas" )
2022-08-19 17:53:16 +00:00
signersAccounts , err = cmdargs . GetSignersAccounts ( acc , wall , cosigners , transaction . None )
2021-04-21 12:22:13 +00:00
if err != nil {
2022-09-08 12:57:27 +00:00
return cli . NewExitError ( fmt . Errorf ( "invalid signers: %w" , err ) , 1 )
2021-03-02 12:43:09 +00:00
}
2019-11-29 15:59:55 +00:00
}
2020-06-17 21:15:13 +00:00
gctx , cancel := options . GetTimeoutContext ( ctx )
defer cancel ( )
c , err := options . GetRPCClient ( gctx , ctx )
2019-11-27 09:52:15 +00:00
if err != nil {
2022-09-08 12:57:27 +00:00
return err
2019-11-27 09:52:15 +00:00
}
2022-08-07 12:17:52 +00:00
if signAndPush {
2022-08-19 17:53:16 +00:00
act , err = actor . New ( c , signersAccounts )
2022-08-07 12:17:52 +00:00
if err != nil {
2022-09-08 12:57:27 +00:00
return cli . NewExitError ( fmt . Errorf ( "failed to create RPC actor: %w" , err ) , 1 )
2022-08-07 12:17:52 +00:00
}
}
2022-02-01 09:46:30 +00:00
out := ctx . String ( "out" )
2022-08-07 12:17:52 +00:00
// It's a bit easier to keep this as is (not using invoker.Invoker)
// during transition period. Mostly because of the need to convert params
// to []interface{}.
2020-06-11 08:45:17 +00:00
resp , err = c . InvokeFunction ( script , operation , params , cosigners )
2019-11-27 09:52:15 +00:00
if err != nil {
2022-09-08 12:57:27 +00:00
return cli . NewExitError ( err , 1 )
2019-11-27 09:52:15 +00:00
}
2022-02-01 09:46:30 +00:00
if resp . State != "HALT" {
2022-06-29 12:12:24 +00:00
errText := fmt . Sprintf ( "Warning: %s VM state returned from the RPC node: %s" , resp . State , resp . FaultException )
2022-08-06 13:36:11 +00:00
if ! signAndPush {
2022-09-08 12:57:27 +00:00
return cli . NewExitError ( errText , 1 )
2022-06-29 12:09:11 +00:00
}
2022-08-31 06:51:57 +00:00
action := "send"
process := "Sending"
2022-08-06 13:36:11 +00:00
if out != "" {
2022-08-31 06:51:57 +00:00
action = "save"
process = "Saving"
2022-02-01 09:46:30 +00:00
}
2020-12-04 07:59:46 +00:00
if ! ctx . Bool ( "force" ) {
2022-09-08 12:57:27 +00:00
return cli . NewExitError ( errText + ".\nUse --force flag to " + action + " the transaction anyway." , 1 )
2020-10-12 09:45:38 +00:00
}
2022-06-29 12:12:24 +00:00
fmt . Fprintln ( ctx . App . Writer , errText + ".\n" + process + " transaction..." )
2020-10-12 09:45:38 +00:00
}
2022-08-06 13:36:11 +00:00
if ! signAndPush {
b , err := json . MarshalIndent ( resp , "" , " " )
2022-02-21 10:41:14 +00:00
if err != nil {
2022-09-08 12:57:27 +00:00
return cli . NewExitError ( err , 1 )
2020-10-02 13:13:17 +00:00
}
2022-08-06 13:36:11 +00:00
fmt . Fprintln ( ctx . App . Writer , string ( b ) )
} else {
2020-02-20 18:08:22 +00:00
if len ( resp . Script ) == 0 {
2022-09-08 12:57:27 +00:00
return cli . NewExitError ( errors . New ( "no script returned from the RPC node" ) , 1 )
2019-11-29 15:59:55 +00:00
}
2022-08-07 18:59:25 +00:00
ver := act . GetVersion ( )
2022-08-07 12:17:52 +00:00
tx , err := act . MakeUnsignedUncheckedRun ( resp . Script , resp . GasConsumed + int64 ( sysgas ) , nil )
2021-09-15 09:40:30 +00:00
if err != nil {
2022-09-08 12:57:27 +00:00
return cli . NewExitError ( fmt . Errorf ( "failed to create tx: %w" , err ) , 1 )
2021-09-15 09:40:30 +00:00
}
2022-08-07 12:17:52 +00:00
tx . NetworkFee += int64 ( gas )
2022-08-06 13:36:11 +00:00
if out != "" {
2022-08-07 19:08:13 +00:00
// Make a long-lived transaction, it's to be signed manually.
tx . ValidUntilBlock += ( ver . Protocol . MaxValidUntilBlockIncrement - uint32 ( ver . Protocol . ValidatorsCount ) ) - 2
2022-08-07 12:17:52 +00:00
m := act . GetNetwork ( )
2022-08-06 13:36:11 +00:00
if err := paramcontext . InitAndSave ( m , tx , acc , out ) ; err != nil {
2022-09-08 12:57:27 +00:00
return cli . NewExitError ( err , 1 )
2021-09-15 09:40:30 +00:00
}
2022-08-06 13:36:11 +00:00
fmt . Fprintln ( ctx . App . Writer , tx . Hash ( ) . StringLE ( ) )
} else {
if ! ctx . Bool ( "force" ) {
2022-08-07 18:59:25 +00:00
promptTime := time . Now ( )
2022-08-06 13:36:11 +00:00
err := input . ConfirmTx ( ctx . App . Writer , tx )
if err != nil {
2022-09-08 12:57:27 +00:00
return cli . NewExitError ( err , 1 )
2022-08-06 13:36:11 +00:00
}
2022-08-07 18:59:25 +00:00
waitTime := time . Since ( promptTime )
// Compensate for confirmation waiting.
tx . ValidUntilBlock += uint32 ( ( waitTime . Milliseconds ( ) / int64 ( ver . Protocol . MillisecondsPerBlock ) ) ) + 1
2022-08-06 13:36:11 +00:00
}
2022-08-07 12:17:52 +00:00
txHash , _ , err := act . SignAndSend ( tx )
2022-08-06 13:36:11 +00:00
if err != nil {
2022-09-08 12:57:27 +00:00
return cli . NewExitError ( fmt . Errorf ( "failed to push invocation tx: %w" , err ) , 1 )
2022-08-06 13:36:11 +00:00
}
fmt . Fprintf ( ctx . App . Writer , "Sent invocation transaction %s\n" , txHash . StringLE ( ) )
2021-09-15 09:40:30 +00:00
}
2019-11-27 09:52:15 +00:00
}
2022-09-08 12:57:27 +00:00
return nil
2019-11-27 09:52:15 +00:00
}
2019-11-26 14:00:43 +00:00
func testInvokeScript ( ctx * cli . Context ) error {
2018-03-05 08:53:09 +00:00
src := ctx . String ( "in" )
if len ( src ) == 0 {
return cli . NewExitError ( errNoInput , 1 )
}
2018-03-25 16:21:00 +00:00
2022-02-22 16:27:32 +00:00
b , err := os . ReadFile ( src )
2018-03-05 08:53:09 +00:00
if err != nil {
return cli . NewExitError ( err , 1 )
}
2020-06-25 16:21:49 +00:00
nefFile , err := nef . FileFromBytes ( b )
if err != nil {
2020-08-06 14:44:08 +00:00
return cli . NewExitError ( fmt . Errorf ( "failed to restore .nef file: %w" , err ) , 1 )
2020-06-25 16:21:49 +00:00
}
2018-03-05 08:53:09 +00:00
2021-04-21 07:54:10 +00:00
signers , exitErr := cmdargs . GetSignersFromContext ( ctx , 0 )
if exitErr != nil {
return exitErr
2020-06-11 08:45:17 +00:00
}
2020-06-17 21:15:13 +00:00
gctx , cancel := options . GetTimeoutContext ( ctx )
defer cancel ( )
c , err := options . GetRPCClient ( gctx , ctx )
2018-03-05 08:53:09 +00:00
if err != nil {
2020-06-17 21:15:13 +00:00
return err
2018-03-05 08:53:09 +00:00
}
2020-07-29 16:57:38 +00:00
resp , err := c . InvokeScript ( nefFile . Script , signers )
2018-03-05 08:53:09 +00:00
if err != nil {
return cli . NewExitError ( err , 1 )
}
2020-02-20 18:08:22 +00:00
b , err = json . MarshalIndent ( resp , "" , " " )
2018-03-05 08:53:09 +00:00
if err != nil {
return cli . NewExitError ( err , 1 )
}
2020-08-28 09:11:19 +00:00
fmt . Fprintln ( ctx . App . Writer , string ( b ) )
2018-03-05 08:53:09 +00:00
return nil
}
2019-11-20 09:29:37 +00:00
// ProjectConfig contains project metadata.
type ProjectConfig struct {
2020-11-20 08:02:58 +00:00
Name string
2021-09-23 21:19:37 +00:00
SourceURL string
2020-12-10 14:55:52 +00:00
SafeMethods [ ] string
2020-08-04 09:55:36 +00:00
SupportedStandards [ ] string
Events [ ] manifest . Event
2021-06-02 07:50:17 +00:00
Permissions [ ] permission
2021-10-16 11:10:17 +00:00
Overloads map [ string ] string ` yaml:"overloads,omitempty" `
2018-10-16 06:33:29 +00:00
}
2018-10-23 08:23:03 +00:00
func inspect ( ctx * cli . Context ) error {
2022-08-05 10:32:37 +00:00
if err := cmdargs . EnsureNone ( ctx ) ; err != nil {
return err
}
2019-10-29 09:56:44 +00:00
in := ctx . String ( "in" )
compile := ctx . Bool ( "compile" )
if len ( in ) == 0 {
2018-10-23 08:23:03 +00:00
return cli . NewExitError ( errNoInput , 1 )
}
2020-08-12 09:22:16 +00:00
var (
b [ ] byte
err error
)
2019-10-29 09:56:44 +00:00
if compile {
2020-08-10 15:23:45 +00:00
b , err = compiler . Compile ( in , nil )
2019-10-29 09:56:44 +00:00
if err != nil {
2020-08-06 14:44:08 +00:00
return cli . NewExitError ( fmt . Errorf ( "failed to compile: %w" , err ) , 1 )
2019-10-29 09:56:44 +00:00
}
2020-06-25 16:21:49 +00:00
} else {
2022-02-22 16:27:32 +00:00
f , err := os . ReadFile ( in )
2020-08-12 09:22:16 +00:00
if err != nil {
return cli . NewExitError ( fmt . Errorf ( "failed to read .nef file: %w" , err ) , 1 )
}
nefFile , err := nef . FileFromBytes ( f )
2020-06-25 16:21:49 +00:00
if err != nil {
2020-08-06 14:44:08 +00:00
return cli . NewExitError ( fmt . Errorf ( "failed to restore .nef file: %w" , err ) , 1 )
2020-06-25 16:21:49 +00:00
}
b = nefFile . Script
2019-10-29 09:56:44 +00:00
}
v := vm . New ( )
v . LoadScript ( b )
2020-12-01 13:52:23 +00:00
v . PrintOps ( ctx . App . Writer )
2019-10-29 09:56:44 +00:00
2018-10-23 08:23:03 +00:00
return nil
}
2019-11-20 13:07:43 +00:00
2021-03-02 12:43:09 +00:00
func getAccFromContext ( ctx * cli . Context ) ( * wallet . Account , * wallet . Wallet , error ) {
2020-03-11 18:11:51 +00:00
var addr util . Uint160
wPath := ctx . String ( "wallet" )
2022-06-23 13:50:21 +00:00
walletConfigPath := ctx . String ( "wallet-config" )
if len ( wPath ) != 0 && len ( walletConfigPath ) != 0 {
return nil , nil , errConflictingWalletFlags
}
if len ( wPath ) == 0 && len ( walletConfigPath ) == 0 {
return nil , nil , errNoWallet
}
var pass * string
if len ( walletConfigPath ) != 0 {
cfg , err := cliwallet . ReadWalletConfig ( walletConfigPath )
if err != nil {
return nil , nil , err
}
wPath = cfg . Path
pass = & cfg . Password
2019-11-29 15:59:55 +00:00
}
2020-03-11 18:11:51 +00:00
wall , err := wallet . NewWalletFromFile ( wPath )
if err != nil {
2022-06-23 13:50:21 +00:00
return nil , nil , err
2020-03-11 18:11:51 +00:00
}
addrFlag := ctx . Generic ( "address" ) . ( * flags . Address )
if addrFlag . IsSet {
addr = addrFlag . Uint160 ( )
} else {
addr = wall . GetChangeAddress ( )
}
2021-08-02 08:10:26 +00:00
2022-06-23 13:50:21 +00:00
acc , err := getUnlockedAccount ( wall , addr , pass )
2021-08-02 08:10:26 +00:00
return acc , wall , err
}
2022-06-23 13:50:21 +00:00
func getUnlockedAccount ( wall * wallet . Wallet , addr util . Uint160 , pass * string ) ( * wallet . Account , error ) {
2020-03-11 18:11:51 +00:00
acc := wall . GetAccount ( addr )
if acc == nil {
2022-06-23 13:50:21 +00:00
return nil , fmt . Errorf ( "wallet contains no account for '%s'" , address . Uint160ToString ( addr ) )
2021-08-02 08:10:26 +00:00
}
2022-09-01 14:54:00 +00:00
if acc . CanSign ( ) {
2021-08-02 08:10:26 +00:00
return acc , nil
2020-03-11 18:11:51 +00:00
}
2022-06-23 13:50:21 +00:00
if pass == nil {
rawPass , err := input . ReadPassword (
fmt . Sprintf ( "Enter account %s password > " , address . Uint160ToString ( addr ) ) )
if err != nil {
return nil , fmt . Errorf ( "Error reading password: %w" , err )
}
trimmed := strings . TrimRight ( string ( rawPass ) , "\n" )
pass = & trimmed
2020-03-11 18:11:51 +00:00
}
2022-06-23 13:50:21 +00:00
err := acc . Decrypt ( * pass , wall . Scrypt )
2019-11-29 15:59:55 +00:00
if err != nil {
2022-06-23 13:50:21 +00:00
return nil , err
2019-11-29 15:59:55 +00:00
}
2021-08-02 08:10:26 +00:00
return acc , nil
2019-11-29 15:59:55 +00:00
}
2019-11-20 13:07:43 +00:00
// contractDeploy deploys contract.
func contractDeploy ( ctx * cli . Context ) error {
2021-08-02 10:47:19 +00:00
nefFile , f , err := readNEFFile ( ctx . String ( "in" ) )
2019-11-20 13:07:43 +00:00
if err != nil {
return cli . NewExitError ( err , 1 )
}
2020-06-30 11:24:07 +00:00
2022-08-22 10:41:57 +00:00
m , manifestBytes , err := readManifest ( ctx . String ( "manifest" ) , util . Uint160 { } )
2020-06-30 11:24:07 +00:00
if err != nil {
2020-08-06 14:44:08 +00:00
return cli . NewExitError ( fmt . Errorf ( "failed to read manifest file: %w" , err ) , 1 )
2020-06-30 11:24:07 +00:00
}
2019-11-20 13:07:43 +00:00
2021-04-22 12:14:02 +00:00
appCallParams := [ ] smartcontract . Parameter {
{
Type : smartcontract . ByteArrayType ,
Value : f ,
} ,
{
Type : smartcontract . ByteArrayType ,
Value : manifestBytes ,
} ,
2021-04-16 15:04:19 +00:00
}
2021-10-12 09:55:56 +00:00
signOffset , data , err := cmdargs . ParseParams ( ctx . Args ( ) , true )
2021-04-22 12:14:02 +00:00
if err != nil {
return cli . NewExitError ( fmt . Errorf ( "unable to parse 'data' parameter: %w" , err ) , 1 )
}
if len ( data ) > 1 {
return cli . NewExitError ( "'data' should be represented as a single parameter" , 1 )
}
if len ( data ) != 0 {
appCallParams = append ( appCallParams , data [ 0 ] )
2021-04-16 15:04:19 +00:00
}
2021-08-02 10:42:15 +00:00
acc , w , err := getAccFromContext ( ctx )
if err != nil {
return cli . NewExitError ( fmt . Errorf ( "can't get sender address: %w" , err ) , 1 )
}
2022-09-01 18:44:49 +00:00
defer w . Close ( )
2022-09-08 12:57:27 +00:00
sender := acc . ScriptHash ( )
2021-08-02 10:42:15 +00:00
2021-10-12 09:55:56 +00:00
cosigners , sgnErr := cmdargs . GetSignersFromContext ( ctx , signOffset )
if sgnErr != nil {
return err
} else if len ( cosigners ) == 0 {
cosigners = [ ] transaction . Signer { {
Account : acc . Contract . ScriptHash ( ) ,
Scopes : transaction . CalledByEntry ,
} }
}
2021-08-02 10:42:15 +00:00
2022-09-08 12:57:27 +00:00
extErr := invokeWithArgs ( ctx , acc , w , management . Hash , "deploy" , appCallParams , cosigners )
2021-04-22 12:14:02 +00:00
if extErr != nil {
return extErr
2020-07-02 13:22:49 +00:00
}
2019-11-29 14:59:07 +00:00
2021-01-22 09:22:48 +00:00
hash := state . CreateContractHash ( sender , nefFile . Checksum , m . Name )
2020-11-18 20:10:48 +00:00
fmt . Fprintf ( ctx . App . Writer , "Contract: %s\n" , hash . StringLE ( ) )
2019-11-20 13:07:43 +00:00
return nil
}
compiler: add ability to generate .abi.json file
A part of integration with NEO Blockchain Toolkit (see #902). To be
able to deploy smart-contract compiled with neo-go compiler via NEO
Express, we have to generate additional .abi.json file. This file
contains the following information:
- hash of the compiled contract
- smart-contract metadata (title, description, version, author,
email, has-storage, has-dynamic-invoke, is-payable)
- smart-contract entry point
- functions
- events
However, this .abi.json file is slightly different from the one,
described in manifest.go, so we have to add auxilaury stractures for
json marshalling. The .abi.json format used by NEO-Express is described
[here](https://github.com/neo-project/neo-devpack-dotnet/blob/master/src/Neo.Compiler.MSIL/FuncExport.cs#L66).
2020-04-28 16:39:01 +00:00
2021-03-22 09:21:48 +00:00
// ParseContractConfig reads contract configuration file (.yaml) and returns unmarshalled ProjectConfig.
func ParseContractConfig ( confFile string ) ( ProjectConfig , error ) {
compiler: add ability to generate .abi.json file
A part of integration with NEO Blockchain Toolkit (see #902). To be
able to deploy smart-contract compiled with neo-go compiler via NEO
Express, we have to generate additional .abi.json file. This file
contains the following information:
- hash of the compiled contract
- smart-contract metadata (title, description, version, author,
email, has-storage, has-dynamic-invoke, is-payable)
- smart-contract entry point
- functions
- events
However, this .abi.json file is slightly different from the one,
described in manifest.go, so we have to add auxilaury stractures for
json marshalling. The .abi.json format used by NEO-Express is described
[here](https://github.com/neo-project/neo-devpack-dotnet/blob/master/src/Neo.Compiler.MSIL/FuncExport.cs#L66).
2020-04-28 16:39:01 +00:00
conf := ProjectConfig { }
2022-02-22 16:27:32 +00:00
confBytes , err := os . ReadFile ( confFile )
compiler: add ability to generate .abi.json file
A part of integration with NEO Blockchain Toolkit (see #902). To be
able to deploy smart-contract compiled with neo-go compiler via NEO
Express, we have to generate additional .abi.json file. This file
contains the following information:
- hash of the compiled contract
- smart-contract metadata (title, description, version, author,
email, has-storage, has-dynamic-invoke, is-payable)
- smart-contract entry point
- functions
- events
However, this .abi.json file is slightly different from the one,
described in manifest.go, so we have to add auxilaury stractures for
json marshalling. The .abi.json format used by NEO-Express is described
[here](https://github.com/neo-project/neo-devpack-dotnet/blob/master/src/Neo.Compiler.MSIL/FuncExport.cs#L66).
2020-04-28 16:39:01 +00:00
if err != nil {
return conf , cli . NewExitError ( err , 1 )
}
err = yaml . Unmarshal ( confBytes , & conf )
if err != nil {
2020-08-06 16:09:57 +00:00
return conf , cli . NewExitError ( fmt . Errorf ( "bad config: %w" , err ) , 1 )
compiler: add ability to generate .abi.json file
A part of integration with NEO Blockchain Toolkit (see #902). To be
able to deploy smart-contract compiled with neo-go compiler via NEO
Express, we have to generate additional .abi.json file. This file
contains the following information:
- hash of the compiled contract
- smart-contract metadata (title, description, version, author,
email, has-storage, has-dynamic-invoke, is-payable)
- smart-contract entry point
- functions
- events
However, this .abi.json file is slightly different from the one,
described in manifest.go, so we have to add auxilaury stractures for
json marshalling. The .abi.json format used by NEO-Express is described
[here](https://github.com/neo-project/neo-devpack-dotnet/blob/master/src/Neo.Compiler.MSIL/FuncExport.cs#L66).
2020-04-28 16:39:01 +00:00
}
return conf , nil
}