From f008c61f3c561ef9f8da889d97db5379c6bf00ad Mon Sep 17 00:00:00 2001 From: Spencer Corwin Date: Mon, 1 Feb 2021 22:46:58 -0800 Subject: [PATCH 1/2] feat(compiler): update compiler and client for neo3-preview3 --- .../compiler-work_2021-02-02-07-08.json | 11 + .../cli/compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../node/compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../compiler-work_2021-02-02-07-08.json | 11 + .../utils/compiler-work_2021-02-02-07-08.json | 11 + global.json | 5 + .../neo-one-cli-common/src/deployContract.ts | 14 +- packages/neo-one-cli-common/src/getClients.ts | 5 +- .../neo-one-cli-common/src/setupWallets.ts | 4 + .../neo-one-cli/src/__tests__/compile.test.ts | 71 ++ packages/neo-one-cli/src/build/createTasks.ts | 19 +- .../neo-one-cli/src/build/deployContract.ts | 6 +- .../neo-one-cli/src/build/generateCode.ts | 16 +- .../neo-one-cli/src/build/setupWallets.ts | 6 +- packages/neo-one-cli/src/cmd/init.ts | 41 +- packages/neo-one-cli/src/cmd/start/network.ts | 8 +- packages/neo-one-cli/src/common/paths.ts | 4 +- .../src/compile/compileContract.ts | 2 +- packages/neo-one-cli/src/compile/interop.ts | 6 +- .../neo-one-cli/src/compile/writeContract.ts | 43 +- .../neo-one-cli/src/deploy/actionResult.ts | 23 +- .../neo-one-cli/src/deploy/loadContracts.ts | 2 +- .../neo-one-cli/src/deploy/printAction.ts | 18 +- .../neo-one-cli/src/deploy/runMigration.ts | 23 +- .../neo-one-client-common/src/BinaryWriter.ts | 19 + .../src/ScriptBuilder.ts | 1 + .../src/StackItemType.ts | 41 + .../src/__tests__/models/vm.test.ts | 34 +- .../src/contractParameters.ts | 15 +- packages/neo-one-client-common/src/crypto.ts | 3 +- packages/neo-one-client-common/src/index.ts | 1 + .../src/models/AccountContract.ts | 2 +- .../src/models/trigger.ts | 2 + .../neo-one-client-common/src/models/types.ts | 160 ++-- .../neo-one-client-common/src/models/vm.ts | 82 ++ packages/neo-one-client-common/src/types.ts | 701 +++++++++-------- packages/neo-one-client-core/package.json | 1 - packages/neo-one-client-core/src/Client.ts | 155 +--- .../__snapshots__/NEOProvider.test.ts.snap | 3 - packages/neo-one-client-core/src/args.ts | 93 ++- .../neo-one-client-core/src/clientUtils.ts | 24 +- packages/neo-one-client-core/src/index.ts | 3 +- packages/neo-one-client-core/src/nep17.ts | 14 +- .../src/provider/NEOONEDataProvider.ts | 15 +- .../src/provider/NEOONEProvider.ts | 5 + .../src/provider/convert.ts | 142 ++-- packages/neo-one-client-core/src/sc/common.ts | 85 ++- .../src/sc/createSmartContract.ts | 283 +++---- packages/neo-one-client-core/src/sc/params.ts | 4 + packages/neo-one-client-core/src/types.ts | 8 +- .../src/user/DapiUserAccountProvider.ts | 9 +- .../src/user/LocalUserAccountProvider.ts | 201 ++--- .../src/user/RemoteUserAccountProvider.ts | 3 +- .../src/user/UserAccountProviderBase.ts | 286 +------ .../models/manifest/ContractManifestModel.ts | 3 +- .../ContractPermissionDescriptorModel.ts | 13 +- packages/neo-one-client-full-core/src/args.ts | 2 +- .../neo-one-client-full-core/src/types.ts | 2 +- .../src/user/LocalUserAccountProvider.ts | 135 ++-- packages/neo-one-client-full/src/index.ts | 159 ++-- .../src/common/createConsoleLogMessages.ts | 50 +- .../src/common/extractErrorTrace.ts | 24 +- .../src/common/processActionsAndMessage.ts | 4 +- packages/neo-one-client/src/index.ts | 36 +- .../neo-one-node-blockchain/src/Blockchain.ts | 10 +- .../neo-one-node-core/src/ApplicationLog.ts | 1 + packages/neo-one-node-core/src/Node.ts | 1 - .../neo-one-node-core/src/Notification.ts | 11 +- .../neo-one-node-core/src/Serializable.ts | 1 + .../src/StackItems/ArrayStackItem.ts | 14 +- .../src/StackItems/BooleanStackItem.ts | 8 +- .../src/StackItems/BufferStackItem.ts | 7 +- .../src/StackItems/ByteStringStackItem.ts | 8 +- .../src/StackItems/IntegerStackItem.ts | 8 +- .../src/StackItems/InteropInterface.ts | 2 +- .../src/StackItems/MapStackItem.ts | 19 +- .../src/StackItems/NullStackItem.ts | 7 +- .../src/StackItems/PointerStackItem.ts | 16 +- .../src/StackItems/StackItemBase.ts | 8 +- .../src/StackItems/StackItemType.ts | 18 +- .../src/StackItems/StackItems.ts | 11 +- .../src/StackItems/StructStackItem.ts | 14 +- .../src/StackItems/errors.ts | 89 +++ .../neo-one-node-core/src/StackItems/index.ts | 6 +- .../src/TransactionVerificationContext.ts | 4 +- .../src/__tests__/disassembleByteCode.test.ts | 384 ++++++++++ .../contractParameter/AnyContractParameter.ts | 30 + .../ArrayContractParameter.ts | 42 + .../BooleanContractParameter.ts | 54 ++ .../ByteArrayContractParameter.ts | 48 ++ .../contractParameter/ContractParameter.ts | 124 +++ .../ContractParameterBase.ts | 54 ++ .../ContractParameterType.ts | 1 + .../Hash160ContractParameter.ts | 56 ++ .../Hash256ContractParameter.ts | 56 ++ .../IntegerContractParameter.ts | 53 ++ .../InteropInterfaceContractParameter.ts | 25 + .../contractParameter/MapContractParameter.ts | 47 ++ .../PublicKeyContractParameter.ts | 56 ++ .../SignatureContractParameter.ts | 49 ++ .../StringContractParameter.ts | 48 ++ .../VoidContractParameter.ts | 29 + .../src/contractParameter/index.ts | 16 + .../src/disassembleByteCode.ts | 142 ++++ packages/neo-one-node-core/src/index.ts | 2 + .../src/utils/deserializeStackItem.ts | 7 +- packages/neo-one-node-core/src/vm.ts | 3 +- .../src/createHandler.ts | 21 +- .../neo-one-node-vm/lib/Dispatcher.Engine.cs | 15 +- packages/neo-one-node-vm/lib/ReturnHelpers.cs | 2 +- packages/neo-one-node-vm/src/Dispatcher.ts | 2 +- .../neo-one-node-vm/src/converters/log.ts | 18 +- packages/neo-one-node/src/startFullNode.ts | 5 +- .../src/__data__/abiFactory.ts | 14 +- .../src/__data__/contractsPaths.ts | 4 +- .../src/__data__/nep17.ts | 20 +- .../src/__data__/testUtils.ts | 10 +- .../src/__tests__/abi/genABI.test.ts | 6 +- .../__tests__/contract/genContract.test.ts | 2 +- .../__tests__/files/genABIEventFiles.test.ts | 2 +- .../src/__tests__/genFiles.test.ts | 4 +- .../types/genSmartContractTypes.test.ts | 2 +- .../src/abi/genABI.ts | 11 - .../src/abi/getABIName.ts | 3 - .../src/abi/index.ts | 2 - .../src/client/genBrowserClient.ts | 9 +- .../src/client/genClient.ts | 13 +- .../src/contract/genContract.ts | 18 +- .../src/genFiles.ts | 20 +- .../src/generated/genGenerated.ts | 8 +- .../src/manifest/genManifest.ts | 11 + .../src/manifest/getManifestName.ts | 3 + .../src/manifest/index.ts | 2 + .../src/type.ts | 2 +- .../src/types/genConstantFunction.ts | 7 +- .../src/types/genEvent.ts | 4 +- .../src/types/genForwardArgsFunction.ts | 4 +- .../src/types/genForwardReturnFunction.ts | 4 +- .../src/types/genFunction.ts | 27 +- .../src/types/genFunctionParameters.ts | 26 +- .../src/types/genMigrationSmartContract.ts | 6 +- .../src/types/genSmartContract.ts | 6 +- .../src/types/genSmartContractBase.ts | 11 +- .../src/types/genSmartContractTypes.ts | 22 +- .../src/types/hasForward.ts | 4 +- .../src/utils/toTypeScriptType.ts | 3 + .../src/DiagnosticMessage.ts | 6 + .../src/__data__/hashes.ts | 4 + .../src/__data__/helpers/compile.ts | 12 +- .../src/__data__/helpers/execute.ts | 2 +- .../src/__data__/helpers/executeScript.ts | 26 +- .../src/__data__/helpers/extractors.ts | 22 +- .../src/__data__/helpers/getClients.ts | 4 +- .../src/__data__/helpers/startNode.ts | 103 +-- .../__data__/helpers/transpileAndExecute.ts | 2 +- .../src/__data__/helpers/utils.ts | 2 +- .../src/__data__/index.ts | 1 + .../src/__data__/keys.ts | 24 +- .../src/__data__/snippets/linked/Bar.ts | 7 +- .../src/__data__/snippets/linked/Foo.ts | 7 +- .../snippets/semantic/single/complex.ts | 65 +- .../snippets/semantic/single/valid.ts | 56 +- .../__snapshots__/index.test.ts.snap | 25 - .../compile/builtins/arguments/index.test.ts | 25 - .../compile/builtins/array/concat.test.ts | 2 +- .../compile/builtins/array/entries.test.ts | 2 +- .../compile/builtins/array/every.test.ts | 13 +- .../compile/builtins/array/filter.test.ts | 4 +- .../compile/builtins/array/forEach.test.ts | 4 +- .../compile/builtins/array/index.test.ts | 12 +- .../compile/builtins/array/iterator.test.ts | 2 +- .../compile/builtins/array/join.test.ts | 2 +- .../compile/builtins/array/length.test.ts | 4 +- .../compile/builtins/array/map.test.ts | 4 +- .../compile/builtins/array/pop.test.ts | 2 +- .../compile/builtins/array/push.test.ts | 2 +- .../compile/builtins/array/reduce.test.ts | 6 +- .../compile/builtins/array/slice.test.ts | 2 +- .../compile/builtins/array/some.test.ts | 4 +- .../compile/builtins/array/toString.test.ts | 2 +- .../compile/builtins/boolean/index.test.ts | 4 +- .../compile/builtins/buffer/concat.test.ts | 6 +- .../compile/builtins/buffer/equals.test.ts | 6 +- .../compile/builtins/buffer/from.test.ts | 6 +- .../compile/builtins/buffer/index.test.ts | 4 +- .../compile/builtins/buffer/length.test.ts | 4 +- .../compile/builtins/buffer/slice.test.ts | 2 +- .../compile/builtins/buffer/toInteger.test.ts | 2 +- .../compile/builtins/buffer/toString.test.ts | 4 +- .../compile/builtins/console/index.test.ts | 4 +- .../compile/builtins/console/log.test.ts | 84 +- .../contract/__snapshots__/asset.test.ts.snap | 47 -- .../__snapshots__/attribute.test.ts.snap | 2 +- .../__snapshots__/contract.test.ts.snap | 2 +- .../__snapshots__/crypto.test.ts.snap | 12 +- .../__snapshots__/header.test.ts.snap | 47 -- .../contract/__snapshots__/input.test.ts.snap | 14 - .../__snapshots__/output.test.ts.snap | 14 - .../__snapshots__/transaction.test.ts.snap | 8 +- .../account/__snapshots__/index.test.ts.snap | 14 - .../builtins/contract/account/index.test.ts | 39 - .../builtins/contract/address/from.test.ts | 8 +- .../builtins/contract/address/index.test.ts | 2 +- .../contract/address/isCaller.test.ts | 11 +- .../builtins/contract/arrayStorage.test.ts | 78 +- .../compile/builtins/contract/asset.test.ts | 71 -- .../builtins/contract/assetType.test.ts | 20 - .../builtins/contract/attribute.test.ts | 2 +- .../builtins/contract/attributeUsage.test.ts | 40 +- .../compile/builtins/contract/block.test.ts | 28 +- .../builtins/contract/blockchain.test.ts | 53 +- .../builtins/contract/contract.test.ts | 17 +- .../contract/createEventNotifier.test.ts | 25 +- .../compile/builtins/contract/crypto.test.ts | 30 +- .../builtins/contract/declareEvent.test.ts | 14 +- .../builtins/contract/deploy/index.test.ts | 2 +- .../contract/deploy/senderAddress.test.ts | 6 +- .../contract/forwardValue/index.test.ts | 15 +- .../builtins/contract/hash256/from.test.ts | 15 +- .../builtins/contract/hash256/index.test.ts | 31 +- .../compile/builtins/contract/header.test.ts | 72 -- .../compile/builtins/contract/input.test.ts | 15 - .../contract/linkedSmartContract/for.test.ts | 9 +- .../builtins/contract/mapStorage.test.ts | 95 +-- .../compile/builtins/contract/output.test.ts | 15 - .../builtins/contract/publicKey/from.test.ts | 8 +- .../builtins/contract/publicKey/index.test.ts | 2 +- .../builtins/contract/scriptBuilder.test.ts | 45 ++ .../builtins/contract/setStorage.test.ts | 79 +- .../__snapshots__/for.test.ts.snap | 18 +- .../contract/smartContract/for.test.ts | 42 +- .../contract/smartContract/upgrade.test.ts | 22 +- .../builtins/contract/transaction.test.ts | 127 +--- .../builtins/contract/transactionType.test.ts | 20 - .../compile/builtins/error/index.test.ts | 8 +- .../compile/builtins/function/index.test.ts | 2 +- .../compile/builtins/iterable/index.test.ts | 2 +- .../builtins/iterableIterator/index.test.ts | 2 +- .../compile/builtins/iterator/index.test.ts | 2 +- .../builtins/iteratorResult/index.test.ts | 2 +- .../compile/builtins/map/forEach.test.ts | 6 +- .../builtins/map/getSetHasDelete.test.ts | 20 +- .../compile/builtins/map/index.test.ts | 2 +- .../compile/builtins/map/iterator.test.ts | 2 +- .../compile/builtins/map/size.test.ts | 4 +- .../compile/builtins/number/index.test.ts | 4 +- .../compile/builtins/object/index.test.ts | 4 +- .../compile/builtins/object/keys.test.ts | 8 +- .../compile/builtins/one/index.test.ts | 12 +- .../compile/builtins/regexp/index.test.ts | 4 +- .../compile/builtins/set/forEach.test.ts | 4 +- .../compile/builtins/set/hasAddDelete.test.ts | 14 +- .../compile/builtins/set/index.test.ts | 2 +- .../compile/builtins/set/iterator.test.ts | 2 +- .../compile/builtins/set/size.test.ts | 4 +- .../compile/builtins/string/index.test.ts | 4 +- .../compile/builtins/symbol/for.test.ts | 4 +- .../compile/builtins/symbol/index.test.ts | 4 +- .../compile/builtins/symbol/iterator.test.ts | 2 +- .../builtins/symbol/toPrimitive.test.ts | 2 +- .../templateStringsArray/index.test.ts | 2 +- .../ClassDeclarationCompiler.test.ts | 8 +- .../EnumDeclarationCompiler.test.ts | 2 +- .../ImportDeclarationCompiler.test.ts | 4 +- .../ArrayLiteralExpressionCompiler.test.ts | 14 +- .../AwaitExpressionCompiler.test.ts | 4 +- .../BinaryExpressionCompiler2.test.ts | 4 +- .../expression/CallExpressionCompiler.test.ts | 3 +- .../DeleteExpressionCompiler.test.ts | 2 +- .../ElementAccessExpressionCompiler.test.ts | 6 +- .../ImportExpressionCompiler.test.ts | 2 +- .../expression/MetaPropertyCompiler.test.ts | 2 +- .../ObjectLiteralExpressionCompiler.test.ts | 4 +- .../RegularExpressionLiteralCompiler.test.ts | 2 +- .../YieldExpressionCompiler.test.ts | 2 +- .../helper/bind/ObjectBindingHelper.test.ts | 32 +- .../ObjectBindingHelper.test.ts.snap | 10 +- .../InvokeSmartContractHelper0.test.ts | 13 +- .../InvokeSmartContractHelper1.test.ts | 11 +- .../InvokeSmartContractHelper10.test.ts | 11 +- .../InvokeSmartContractHelper11.test.ts | 11 +- .../InvokeSmartContractHelper2.test.ts | 11 +- .../InvokeSmartContractHelper3.test.ts | 11 +- .../InvokeSmartContractHelper4.test.ts | 11 +- .../InvokeSmartContractHelper5.test.ts | 11 +- .../InvokeSmartContractHelper6.test.ts | 23 +- .../InvokeSmartContractHelper7.test.ts | 11 +- .../InvokeSmartContractHelper8.test.ts | 11 +- .../InvokeSmartContractHelper9.test.ts | 11 +- .../types/number/ToNumberHelper.test.ts | 8 +- .../types/string/ToStringHelper.test.ts | 2 +- .../statement/BreakStatementCompiler.test.ts | 2 +- .../ContinueStatementCompiler.test.ts | 2 +- .../DebuggerStatementCompiler.test.ts | 2 +- .../LabeledStatementCompiler.test.ts | 2 +- .../statement/SwitchStatementCompiler.test.ts | 10 +- .../statement/WithStatementCompiler.test.ts | 2 +- .../ABISmartContractProcessor.test.ts | 35 +- .../contract/ContractInfoProcessor.test.ts | 223 ++---- .../ABISmartContractProcessor.test.ts.snap | 14 +- .../ContractInfoProcessor.test.ts.snap | 372 ++++----- .../src/api.ts | 6 +- .../src/compile/builtins/arguments/index.ts | 9 - .../src/compile/builtins/array/concat.ts | 5 - .../src/compile/builtins/array/entries.ts | 2 +- .../src/compile/builtins/array/iterator.ts | 2 +- .../src/compile/builtins/array/pop.ts | 4 +- .../src/compile/builtins/array/push.ts | 2 +- .../src/compile/builtins/assertEqual/index.ts | 2 +- .../src/compile/builtins/buffer/equals.ts | 12 + .../contract/BuiltinInstanceIndexValue.ts | 26 + .../builtins/contract/SmartContractForBase.ts | 7 +- .../contract/SysCallInstanceMemberIndex.ts | 30 + .../builtins/contract/account/getBalance.ts | 50 -- .../builtins/contract/account/index.ts | 30 - .../builtins/contract/address/index.ts | 17 + .../builtins/contract/address/isSender.ts | 2 +- .../builtins/contract/arrayStorage/pop.ts | 10 +- .../src/compile/builtins/contract/asset.ts | 64 -- .../compile/builtins/contract/assetType.ts | 19 - .../compile/builtins/contract/attribute.ts | 24 +- .../builtins/contract/attributeUsage.ts | 75 +- .../src/compile/builtins/contract/block.ts | 15 +- .../compile/builtins/contract/blockchain.ts | 8 +- .../src/compile/builtins/contract/contract.ts | 19 +- .../builtins/contract/createEventNotifier.ts | 4 +- .../src/compile/builtins/contract/crypto.ts | 28 +- .../builtins/contract/hash256/index.ts | 12 - .../src/compile/builtins/contract/header.ts | 59 -- .../src/compile/builtins/contract/index.ts | 20 +- .../src/compile/builtins/contract/input.ts | 25 - .../contract/linkedSmartContract/for.ts | 14 +- .../compile/builtins/contract/notification.ts | 41 + .../src/compile/builtins/contract/output.ts | 30 - .../contract/smartContract/address.ts | 2 +- .../contract/smartContract/destroy.ts | 2 +- .../builtins/contract/smartContract/for.ts | 16 +- .../builtins/contract/smartContract/index.ts | 18 - .../compile/builtins/contract/transaction.ts | 97 +-- .../builtins/contract/transactionType.ts | 40 - .../src/compile/builtins/createBuiltins.ts | 2 - .../src/compile/builtins/map/delete.ts | 2 + .../src/compile/builtins/map/forEach.ts | 4 +- .../src/compile/builtins/map/get.ts | 2 + .../src/compile/builtins/map/has.ts | 2 + .../src/compile/builtins/map/iterator.ts | 4 +- .../src/compile/builtins/map/set.ts | 2 + .../src/compile/builtins/map/size.ts | 2 +- .../src/compile/builtins/object/keys.ts | 7 +- .../src/compile/builtins/set/add.ts | 4 +- .../src/compile/builtins/set/forEach.ts | 6 +- .../src/compile/builtins/set/index.ts | 2 + .../src/compile/builtins/set/iterator.ts | 6 +- .../src/compile/compile.ts | 41 +- .../src/compile/constants/Types.ts | 22 +- .../declaration/ClassDeclarationCompiler.ts | 5 - .../ElementAccessExpressionCompiler.ts | 17 +- .../PropertyAccessExpressionCompiler.ts | 7 +- .../expression/TypeOfExpressionCompiler.ts | 5 - .../src/compile/getSmartContractInfo.ts | 92 ++- .../src/compile/helper/arr/ArrConcatHelper.ts | 6 +- .../compile/helper/arr/ArrEveryFuncHelper.ts | 6 +- .../src/compile/helper/arr/ArrEveryHelper.ts | 2 +- .../src/compile/helper/arr/ArrFilterHelper.ts | 4 +- .../src/compile/helper/arr/ArrFindHelper.ts | 2 +- .../helper/arr/ArrForEachFuncHelper.ts | 2 +- .../compile/helper/arr/ArrForEachHelper.ts | 4 +- .../src/compile/helper/arr/ArrLeftHelper.ts | 2 +- .../compile/helper/arr/ArrMapFuncHelper.ts | 46 +- .../src/compile/helper/arr/ArrMapHelper.ts | 4 +- .../src/compile/helper/arr/ArrRangeHelper.ts | 4 +- .../compile/helper/arr/ArrReduceFuncHelper.ts | 8 +- .../src/compile/helper/arr/ArrReduceHelper.ts | 4 +- .../compile/helper/arr/ArrSomeFuncHelper.ts | 6 +- .../src/compile/helper/arr/ArrSomeHelper.ts | 2 +- .../src/compile/helper/arr/ExtendArrHelper.ts | 2 +- .../compile/helper/bind/ArrayBindingHelper.ts | 20 +- .../helper/bind/ObjectBindingHelper.ts | 20 +- .../helper/buffer/BufferSliceHelper.ts | 4 +- .../helper/cache/GetCachedValueHelper.ts | 8 +- .../compile/helper/common/ArrSliceHelper.ts | 8 +- .../compile/helper/common/ConsoleLogHelper.ts | 6 +- .../common/GenericLogSerializeHelper.ts | 7 +- .../helper/completionRecord/BreakHelper.ts | 2 +- .../helper/completionRecord/ContinueHelper.ts | 2 +- .../helper/completionRecord/ReturnHelper.ts | 2 +- .../ThrowCompletionBaseHelper.ts | 6 +- .../completionRecord/ThrowCompletionHelper.ts | 4 +- .../helper/completionRecord/ThrowHelper.ts | 4 +- .../ApplicationMatchesVerificationHelper.ts | 42 +- .../helper/contract/CompleteSendHelper.ts | 147 ---- .../helper/contract/DidReceiveAssetsHelper.ts | 37 - .../DidReceiveNonClaimAssetsHelper.ts | 54 -- .../helper/contract/DidSendAssetsHelper.ts | 37 - .../contract/GetOutputAssetValueMapHelper.ts | 23 - .../helper/contract/HandleNormalHelper.ts | 20 - .../helper/contract/HandleReceiveHelper.ts | 7 - .../helper/contract/HandleSendHelper.ts | 344 --------- .../helper/contract/HandleSendUnsafeHelper.ts | 7 - .../HandleSendUnsafeReceiveHelperBase.ts | 113 --- .../contract/InvocationIsCallerHelper.ts | 4 +- .../contract/InvokeSmartContractHelper.ts | 265 +------ .../compile/helper/contract/IsCallerHelper.ts | 4 +- .../contract/MergeAssetValueMapsHelper.ts | 123 --- .../helper/contract/RefundAssetsHelper.ts | 163 ---- .../contract/SetProcessedTransactionHelper.ts | 44 -- .../compile/helper/contract/UpgradeHelper.ts | 2 +- .../src/compile/helper/contract/index.ts | 11 - .../src/compile/helper/createHelpers.ts | 113 +-- .../helper/function/ArgumentsHelper.ts | 2 + .../helper/function/BindFunctionThisHelper.ts | 2 +- .../src/compile/helper/function/CallHelper.ts | 6 +- .../compile/helper/function/CallLikeHelper.ts | 29 +- .../src/compile/helper/function/NewHelper.ts | 8 +- .../helper/function/ParametersHelper.ts | 8 +- .../helper/global/CreateGlobalObjectHelper.ts | 2 +- .../helper/global/GetArgumentHelper.ts | 2 +- .../CreateEnumeratorIterableIteratorHelper.ts | 9 +- .../CreateIterableIteratorBaseHelper.ts | 4 +- .../CreateIteratorIterableIteratorHelper.ts | 11 +- .../iterator/RawEnumeratorEveryHelper.ts | 2 +- .../iterator/RawEnumeratorFindHelper.ts | 2 +- .../RawEnumeratorForEachFuncHelper.ts | 19 +- .../iterator/RawEnumeratorForEachHelper.ts | 2 +- .../iterator/RawEnumeratorReduceHelper.ts | 2 +- .../iterator/RawEnumeratorSomeHelper.ts | 2 +- .../iterator/RawIteratorEveryBaseHelper.ts | 2 +- .../helper/iterator/RawIteratorEveryHelper.ts | 4 +- .../iterator/RawIteratorForEachBaseHelper.ts | 2 +- .../RawIteratorForEachFuncBaseHelper.ts | 2 +- .../iterator/RawIteratorForEachFuncHelper.ts | 19 +- .../iterator/RawIteratorForEachHelper.ts | 11 +- .../iterator/RawIteratorForEachKeyHelper.ts | 9 +- .../iterator/RawIteratorReduceBaseHelper.ts | 2 +- .../iterator/RawIteratorReduceHelper.ts | 11 +- .../iterator/RawIteratorSomeBaseHelper.ts | 2 +- .../helper/iterator/RawIteratorSomeHelper.ts | 4 +- .../src/compile/helper/map/MapEveryHelper.ts | 2 +- .../src/compile/helper/map/MapFilterHelper.ts | 10 +- .../compile/helper/map/MapForEachHelper.ts | 2 +- .../src/compile/helper/map/MapMapHelper.ts | 10 +- .../src/compile/helper/map/MapReduceHelper.ts | 6 +- .../src/compile/helper/map/MapSomeHelper.ts | 2 +- .../helper/map/UnusedMapDeleteHelper.ts | 72 ++ .../compile/helper/map/UnusedMapGetHelper.ts | 30 + .../helper/map/UnusedMapHasKeyHelper.ts | 105 +++ .../compile/helper/map/UnusedMapSetHelper.ts | 43 ++ .../relational/EqualsEqualsEqualsHelper.ts | 38 +- .../compile/helper/scope/DupScopeHelper.ts | 23 + .../compile/helper/scope/PopScopeHelper.ts | 17 + .../compile/helper/scope/PushScopeHelper.ts | 19 + .../src/compile/helper/scope/index.ts | 3 + .../compile/helper/statement/ForLoopHelper.ts | 6 +- .../src/compile/helper/statement/IfHelper.ts | 6 +- .../storage/AtStructuredStorageHelper.ts | 2 +- .../helper/storage/CacheStorageHelper.ts | 6 +- .../helper/storage/CommonStorageHelper.ts | 20 +- .../storage/CreateStructuredStorageHelper.ts | 33 +- .../storage/DeleteCacheStorageHelper.ts | 6 +- .../storage/GetKeyStructuredStorageHelper.ts | 5 +- .../helper/storage/GetStorageBaseHelper.ts | 8 +- .../storage/GetStructuredStorageHelper.ts | 2 +- ...andlePrefixArrayStructuredStorageHelper.ts | 2 +- .../HandlePrefixKeyStructuredStorageHelper.ts | 2 +- .../HandleValValueStructuredStorageHelper.ts | 6 +- .../HandleValueStructuredStorageHelper.ts | 6 +- .../helper/storage/IterStorageHelper.ts | 8 +- .../helper/storage/SetArrayStorageHelper.ts | 2 +- .../storage/SetStructuredStorageHelper.ts | 5 +- .../UnwrapKeyStructuredStorageHelper.ts | 5 - .../helper/types/ForBuiltinTypeHelper.ts | 75 -- .../helper/types/IsNullOrUndefinedHelper.ts | 5 - .../compile/helper/types/ToPrimitiveHelper.ts | 15 - .../helper/types/UnwrapCopyStructHelper.ts | 24 +- .../compile/helper/types/UnwrapValHelper.ts | 15 - .../helper/types/UnwrapValRecursiveHelper.ts | 27 +- .../src/compile/helper/types/WrapHelper.ts | 27 +- .../src/compile/helper/types/WrapValHelper.ts | 15 - .../helper/types/WrapValRecursiveHelper.ts | 22 +- .../src/compile/helper/types/account.ts | 24 - .../helper/types/array/ArrayLengthHelper.ts | 2 +- .../helper/types/array/GetArrayIndexHelper.ts | 2 +- .../helper/types/array/SetArrayIndexHelper.ts | 8 +- .../src/compile/helper/types/asset.ts | 24 - .../helper/types/attribute/typeTests.ts | 5 +- .../helper/types/boolean/ToBooleanHelper.ts | 5 - .../types/boolean/ToNullishBooleanHelper.ts | 5 - .../compile/helper/types/getHasBuiltins.ts | 10 - .../src/compile/helper/types/header.ts | 24 - .../src/compile/helper/types/index.ts | 2 - .../helper/types/input/IsInputHelper.ts | 8 - .../helper/types/input/UnwrapInputHelper.ts | 5 - .../helper/types/input/WrapInputHelper.ts | 8 - .../src/compile/helper/types/input/index.ts | 5 - .../compile/helper/types/input/typeTests.ts | 12 - .../helper/types/number/ToNumberHelper.ts | 10 +- .../types/object/FindObjectPropertyHelper.ts | 2 +- .../object/FindObjectPropertyHelperBase.ts | 3 + .../object/OmitObjectPropertiesHelperBase.ts | 3 + .../object/PickObjectPropertiesHelper.ts | 8 +- .../object/SetObjectDataPropertyHelperBase.ts | 3 + .../helper/types/object/ToObjectHelper.ts | 5 - .../compile/helper/types/object/typeTests.ts | 6 +- .../helper/types/output/IsOutputHelper.ts | 8 - .../helper/types/output/UnwrapOutputHelper.ts | 5 - .../helper/types/output/WrapOutputHelper.ts | 8 - .../src/compile/helper/types/output/index.ts | 5 - .../compile/helper/types/output/typeTests.ts | 12 - .../helper/types/string/ToStringHelper.ts | 5 - .../helper/types/transaction/typeTests.ts | 12 +- .../src/compile/pc/Call.ts | 2 +- .../src/compile/pc/Jmp.ts | 11 +- .../src/compile/pc/Jump.ts | 3 +- .../src/compile/sb/BaseScriptBuilder.ts | 106 ++- .../src/compile/sb/JumpTable.ts | 2 +- .../src/compile/sb/ScriptBuilder.ts | 4 +- .../src/compile/sb/resolveJumps.ts | 22 +- .../src/compile/scope/ResolvedScope.ts | 44 +- .../compile/statement/DoStatementCompiler.ts | 2 +- .../statement/ForOfStatementCompiler.ts | 12 +- .../compile/statement/TryStatementCompiler.ts | 2 +- .../src/compile/types.ts | 6 - .../src/compileContract.ts | 9 +- .../src/constants.ts | 40 +- .../src/contract/ContractInfoProcessor.ts | 148 +--- .../src/contract/DebugInfoProcessor.ts | 64 +- ...r.ts => ManifestSmartContractProcessor.ts} | 252 ++++-- .../src/contract/getABI.ts | 6 - .../src/contract/getContractProperties.ts | 368 ++++++++- .../src/contract/getManifest.ts | 7 + .../src/contract/index.ts | 2 +- .../src/utils/BinaryReader.ts | 205 +++++ .../src/utils/disassembleByteCode.ts | 142 ++++ .../src/utils/index.ts | 1 + .../src/utils/processMethods.ts | 115 +++ .../src/utils/utils.ts | 249 ++++++ .../src/withContracts.ts | 18 +- .../src/createNode.ts | 6 +- .../neo-one-smart-contract/src/index.d.ts | 716 +++++------------- packages/neo-one-utils/src/constants.ts | 4 + .../0-installation/1-environment-setup.md | 2 + .../1-main-concepts/03-standard-library.md | 102 +++ .../docs/1-main-concepts/12-deployment.md | 2 +- .../docs/3-node/4-build-from-source.md | 4 +- .../docs3/0-installation/0-getting-started.md | 86 +++ .../0-installation/1-environment-setup.md | 94 +++ .../docs3/0-installation/2-cli.md | 103 +++ .../docs3/0-installation/3-playground.md | 63 ++ .../docs3/0-installation/config.json | 4 + .../docs3/1-main-concepts/00-hello-world.md | 48 ++ .../1-main-concepts/01-blockchain-basics.md | 94 +++ .../02-smart-contract-basics.md | 61 ++ .../1-main-concepts/03-standard-library.md | 167 ++++ .../04-properties-and-storage.md | 78 ++ .../docs3/1-main-concepts/05-methods.md | 66 ++ .../1-main-concepts/06-events-and-logs.md | 45 ++ .../07-calling-smart-contracts.md | 71 ++ .../docs3/1-main-concepts/08-client-apis.md | 156 ++++ .../1-main-concepts/09-smart-contract-apis.md | 377 +++++++++ .../docs3/1-main-concepts/10-testing.md | 205 +++++ .../docs3/1-main-concepts/11-dapps.md | 144 ++++ .../docs3/1-main-concepts/12-NEP-5.md | 97 +++ .../docs3/1-main-concepts/13-deployment.md | 175 +++++ .../docs3/1-main-concepts/config.json | 4 + .../2-advanced-guides/00-native-assets.md | 173 +++++ .../2-advanced-guides/01-forward-values.md | 99 +++ .../2-advanced-guides/02-user-accounts.md | 123 +++ .../03-extended-client-apis.md | 8 + .../2-advanced-guides/04-raw-client-apis.md | 8 + .../docs3/2-advanced-guides/05-react.md | 77 ++ .../docs3/2-advanced-guides/06-angular.md | 80 ++ .../docs3/2-advanced-guides/07-vue.md | 76 ++ .../2-advanced-guides/08-dapi-support.md | 59 ++ .../09-configuration-options.md | 140 ++++ .../docs3/2-advanced-guides/config.json | 4 + .../neo-one-website/docs3/3-node/1-docker.md | 143 ++++ .../docs3/3-node/2-kubernetes.md | 401 ++++++++++ .../docs3/3-node/3-docker-compose.md | 102 +++ .../docs3/3-node/4-build-from-source.md | 72 ++ .../neo-one-website/docs3/3-node/5-heroku.md | 52 ++ .../docs3/3-node/6-configuration.md | 261 +++++++ .../neo-one-website/docs3/3-node/config.json | 4 + .../4-contributing/0-how-to-contribute.md | 77 ++ .../4-contributing/1-codebase-overview.md | 272 +++++++ .../2-smart-contract-compiler.md | 62 ++ .../docs3/4-contributing/3-code-of-conduct.md | 74 ++ .../docs3/4-contributing/config.json | 4 + packages/neo-one-website/tutorial/tutorial.md | 2 +- 603 files changed, 12139 insertions(+), 7222 deletions(-) create mode 100644 common/changes/@neo-one/cli-common/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/cli/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/client-common/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/client-core/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/client-full-common/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/client-full-core/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/client-full/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/client-switch/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/client/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/node-blockchain/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/node-core/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/node-neo-settings/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/node-rpc-handler/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/node-vm/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/node/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/smart-contract-codegen/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/smart-contract-compiler/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/smart-contract-test/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/smart-contract/compiler-work_2021-02-02-07-08.json create mode 100644 common/changes/@neo-one/utils/compiler-work_2021-02-02-07-08.json create mode 100644 global.json create mode 100644 packages/neo-one-cli/src/__tests__/compile.test.ts create mode 100644 packages/neo-one-client-common/src/StackItemType.ts delete mode 100644 packages/neo-one-client-core/src/__tests__/provider/__snapshots__/NEOProvider.test.ts.snap create mode 100644 packages/neo-one-node-core/src/StackItems/errors.ts create mode 100644 packages/neo-one-node-core/src/__tests__/disassembleByteCode.test.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/AnyContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/ArrayContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/BooleanContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/ByteArrayContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/ContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/ContractParameterBase.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/ContractParameterType.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/Hash160ContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/Hash256ContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/IntegerContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/InteropInterfaceContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/MapContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/PublicKeyContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/SignatureContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/StringContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/VoidContractParameter.ts create mode 100644 packages/neo-one-node-core/src/contractParameter/index.ts create mode 100644 packages/neo-one-node-core/src/disassembleByteCode.ts delete mode 100644 packages/neo-one-smart-contract-codegen/src/abi/genABI.ts delete mode 100644 packages/neo-one-smart-contract-codegen/src/abi/getABIName.ts delete mode 100644 packages/neo-one-smart-contract-codegen/src/abi/index.ts create mode 100644 packages/neo-one-smart-contract-codegen/src/manifest/genManifest.ts create mode 100644 packages/neo-one-smart-contract-codegen/src/manifest/getManifestName.ts create mode 100644 packages/neo-one-smart-contract-codegen/src/manifest/index.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/__data__/hashes.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/arguments/__snapshots__/index.test.ts.snap delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/arguments/index.test.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/asset.test.ts.snap delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/header.test.ts.snap delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/input.test.ts.snap delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/output.test.ts.snap delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/account/__snapshots__/index.test.ts.snap delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/account/index.test.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/asset.test.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/assetType.test.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/header.test.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/input.test.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/output.test.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/scriptBuilder.test.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/transactionType.test.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/builtins/arguments/index.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/BuiltinInstanceIndexValue.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/SysCallInstanceMemberIndex.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/account/getBalance.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/account/index.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/asset.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/assetType.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/header.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/input.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/notification.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/output.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/transactionType.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/contract/CompleteSendHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/contract/DidReceiveAssetsHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/contract/DidReceiveNonClaimAssetsHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/contract/DidSendAssetsHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/contract/GetOutputAssetValueMapHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleReceiveHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleSendHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleSendUnsafeHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleSendUnsafeReceiveHelperBase.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/contract/MergeAssetValueMapsHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/contract/RefundAssetsHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/contract/SetProcessedTransactionHelper.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapDeleteHelper.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapGetHelper.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapHasKeyHelper.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapSetHelper.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/scope/DupScopeHelper.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/scope/PopScopeHelper.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/scope/PushScopeHelper.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/scope/index.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/types/account.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/types/asset.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/types/header.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/IsInputHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/UnwrapInputHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/WrapInputHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/index.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/typeTests.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/IsOutputHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/UnwrapOutputHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/WrapOutputHelper.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/index.ts delete mode 100644 packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/typeTests.ts rename packages/neo-one-smart-contract-compiler/src/contract/{ABISmartContractProcessor.ts => ManifestSmartContractProcessor.ts} (59%) delete mode 100644 packages/neo-one-smart-contract-compiler/src/contract/getABI.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/contract/getManifest.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/utils/BinaryReader.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/utils/disassembleByteCode.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/utils/processMethods.ts create mode 100644 packages/neo-one-smart-contract-compiler/src/utils/utils.ts create mode 100644 packages/neo-one-website/docs3/0-installation/0-getting-started.md create mode 100644 packages/neo-one-website/docs3/0-installation/1-environment-setup.md create mode 100644 packages/neo-one-website/docs3/0-installation/2-cli.md create mode 100644 packages/neo-one-website/docs3/0-installation/3-playground.md create mode 100644 packages/neo-one-website/docs3/0-installation/config.json create mode 100644 packages/neo-one-website/docs3/1-main-concepts/00-hello-world.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/01-blockchain-basics.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/02-smart-contract-basics.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/03-standard-library.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/04-properties-and-storage.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/05-methods.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/06-events-and-logs.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/07-calling-smart-contracts.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/08-client-apis.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/09-smart-contract-apis.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/10-testing.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/11-dapps.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/12-NEP-5.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/13-deployment.md create mode 100644 packages/neo-one-website/docs3/1-main-concepts/config.json create mode 100644 packages/neo-one-website/docs3/2-advanced-guides/00-native-assets.md create mode 100644 packages/neo-one-website/docs3/2-advanced-guides/01-forward-values.md create mode 100644 packages/neo-one-website/docs3/2-advanced-guides/02-user-accounts.md create mode 100644 packages/neo-one-website/docs3/2-advanced-guides/03-extended-client-apis.md create mode 100644 packages/neo-one-website/docs3/2-advanced-guides/04-raw-client-apis.md create mode 100644 packages/neo-one-website/docs3/2-advanced-guides/05-react.md create mode 100644 packages/neo-one-website/docs3/2-advanced-guides/06-angular.md create mode 100644 packages/neo-one-website/docs3/2-advanced-guides/07-vue.md create mode 100644 packages/neo-one-website/docs3/2-advanced-guides/08-dapi-support.md create mode 100644 packages/neo-one-website/docs3/2-advanced-guides/09-configuration-options.md create mode 100644 packages/neo-one-website/docs3/2-advanced-guides/config.json create mode 100644 packages/neo-one-website/docs3/3-node/1-docker.md create mode 100644 packages/neo-one-website/docs3/3-node/2-kubernetes.md create mode 100644 packages/neo-one-website/docs3/3-node/3-docker-compose.md create mode 100644 packages/neo-one-website/docs3/3-node/4-build-from-source.md create mode 100644 packages/neo-one-website/docs3/3-node/5-heroku.md create mode 100644 packages/neo-one-website/docs3/3-node/6-configuration.md create mode 100644 packages/neo-one-website/docs3/3-node/config.json create mode 100644 packages/neo-one-website/docs3/4-contributing/0-how-to-contribute.md create mode 100644 packages/neo-one-website/docs3/4-contributing/1-codebase-overview.md create mode 100644 packages/neo-one-website/docs3/4-contributing/2-smart-contract-compiler.md create mode 100644 packages/neo-one-website/docs3/4-contributing/3-code-of-conduct.md create mode 100644 packages/neo-one-website/docs3/4-contributing/config.json diff --git a/common/changes/@neo-one/cli-common/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/cli-common/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..0216682402 --- /dev/null +++ b/common/changes/@neo-one/cli-common/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/cli-common" + } + ], + "packageName": "@neo-one/cli-common", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/cli/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/cli/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..bad65e0ff1 --- /dev/null +++ b/common/changes/@neo-one/cli/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/cli" + } + ], + "packageName": "@neo-one/cli", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client-common/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/client-common/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..9ae0960009 --- /dev/null +++ b/common/changes/@neo-one/client-common/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/client-common" + } + ], + "packageName": "@neo-one/client-common", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client-core/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/client-core/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..6312f95640 --- /dev/null +++ b/common/changes/@neo-one/client-core/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/client-core" + } + ], + "packageName": "@neo-one/client-core", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client-full-common/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/client-full-common/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..d9f389dd09 --- /dev/null +++ b/common/changes/@neo-one/client-full-common/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/client-full-common" + } + ], + "packageName": "@neo-one/client-full-common", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client-full-core/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/client-full-core/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..e85ca5b126 --- /dev/null +++ b/common/changes/@neo-one/client-full-core/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/client-full-core" + } + ], + "packageName": "@neo-one/client-full-core", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client-full/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/client-full/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..405e15f641 --- /dev/null +++ b/common/changes/@neo-one/client-full/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/client-full" + } + ], + "packageName": "@neo-one/client-full", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client-switch/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/client-switch/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..e1f4a65a54 --- /dev/null +++ b/common/changes/@neo-one/client-switch/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/client-switch" + } + ], + "packageName": "@neo-one/client-switch", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/client/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..e5a3561556 --- /dev/null +++ b/common/changes/@neo-one/client/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/client" + } + ], + "packageName": "@neo-one/client", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-blockchain/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/node-blockchain/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..5b0a2f8634 --- /dev/null +++ b/common/changes/@neo-one/node-blockchain/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/node-blockchain" + } + ], + "packageName": "@neo-one/node-blockchain", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-core/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/node-core/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..5f1af4c6b8 --- /dev/null +++ b/common/changes/@neo-one/node-core/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/node-core" + } + ], + "packageName": "@neo-one/node-core", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-neo-settings/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/node-neo-settings/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..0613c9f11e --- /dev/null +++ b/common/changes/@neo-one/node-neo-settings/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/node-neo-settings" + } + ], + "packageName": "@neo-one/node-neo-settings", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-rpc-handler/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/node-rpc-handler/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..15058383d0 --- /dev/null +++ b/common/changes/@neo-one/node-rpc-handler/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/node-rpc-handler" + } + ], + "packageName": "@neo-one/node-rpc-handler", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-vm/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/node-vm/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..012adc449f --- /dev/null +++ b/common/changes/@neo-one/node-vm/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/node-vm" + } + ], + "packageName": "@neo-one/node-vm", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/node/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..a33bd610b0 --- /dev/null +++ b/common/changes/@neo-one/node/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/node" + } + ], + "packageName": "@neo-one/node", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/smart-contract-codegen/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/smart-contract-codegen/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..67173cc739 --- /dev/null +++ b/common/changes/@neo-one/smart-contract-codegen/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/smart-contract-codegen" + } + ], + "packageName": "@neo-one/smart-contract-codegen", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/smart-contract-compiler/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/smart-contract-compiler/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..7cbe745cf0 --- /dev/null +++ b/common/changes/@neo-one/smart-contract-compiler/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/smart-contract-compiler" + } + ], + "packageName": "@neo-one/smart-contract-compiler", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/smart-contract-test/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/smart-contract-test/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..0fc130f846 --- /dev/null +++ b/common/changes/@neo-one/smart-contract-test/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/smart-contract-test" + } + ], + "packageName": "@neo-one/smart-contract-test", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/smart-contract/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/smart-contract/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..d3d010d70e --- /dev/null +++ b/common/changes/@neo-one/smart-contract/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/smart-contract" + } + ], + "packageName": "@neo-one/smart-contract", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/utils/compiler-work_2021-02-02-07-08.json b/common/changes/@neo-one/utils/compiler-work_2021-02-02-07-08.json new file mode 100644 index 0000000000..13c0138df2 --- /dev/null +++ b/common/changes/@neo-one/utils/compiler-work_2021-02-02-07-08.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Update for Preview3, primarily in compiler, client, and CLI.", + "type": "patch", + "packageName": "@neo-one/utils" + } + ], + "packageName": "@neo-one/utils", + "email": "spencercorwin@icloud.com" +} \ No newline at end of file diff --git a/global.json b/global.json new file mode 100644 index 0000000000..f5efc4a530 --- /dev/null +++ b/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "3.1.401" + } +} diff --git a/packages/neo-one-cli-common/src/deployContract.ts b/packages/neo-one-cli-common/src/deployContract.ts index a6eb8413a4..36e1262484 100644 --- a/packages/neo-one-cli-common/src/deployContract.ts +++ b/packages/neo-one-cli-common/src/deployContract.ts @@ -2,7 +2,7 @@ import { AddressString, common, ContractManifestClient, crypto, SourceMaps } fro import { NEOONEDataProvider } from '@neo-one/client-core'; import { ContractRegister } from '@neo-one/client-full-core'; import { constants } from '@neo-one/utils'; -import BigNumber from 'bignumber.js'; +import { BigNumber } from 'bignumber.js'; import { getClients } from './getClients'; export const deployContract = async ( @@ -18,17 +18,23 @@ export const deployContract = async ( try { const existing = await client.read(provider.network).getContract(common.uInt160ToString(hash)); - return common.uInt160ToString(existing.manifest.hash); + return common.uInt160ToString(existing.hash); } catch { // do nothing } - const result = await client.publishAndDeploy(contract, manifest, [], { systemFee: new BigNumber(-1) }, sourceMaps); + const result = await client.publishAndDeploy( + contract, + manifest, + ['deploy', []], // TODO: for now this has to be ['deploy', []] ? + { maxSystemFee: new BigNumber(-1), maxNetworkFee: new BigNumber(-1) }, + sourceMaps, + ); const [receipt] = await Promise.all([result.confirmed(), developerClient.runConsensusNow()]); if (receipt.result.state === 'FAULT') { throw new Error(receipt.result.message); } - return common.uInt160ToString(receipt.result.value.manifest.hash); + return common.uInt160ToString(receipt.result.value.manifest.abi.hash); }; diff --git a/packages/neo-one-cli-common/src/getClients.ts b/packages/neo-one-cli-common/src/getClients.ts index aad257325a..7d6f2d6d6f 100644 --- a/packages/neo-one-cli-common/src/getClients.ts +++ b/packages/neo-one-cli-common/src/getClients.ts @@ -15,9 +15,10 @@ export const getClients = async (provider: NEOONEDataProvider, masterPrivateKey: }), }); const developerClient = new DeveloperClient(provider); - const masterWallet = await client.providers.memory.keystore.addUserAccount({ + // TODO: this is for private net only right? + const masterWallet = await client.providers.memory.keystore.addMultiSigUserAccount({ network: provider.network, - privateKey: masterPrivateKey, + privateKeys: [masterPrivateKey], }); return { client, developerClient, masterWallet }; diff --git a/packages/neo-one-cli-common/src/setupWallets.ts b/packages/neo-one-cli-common/src/setupWallets.ts index 787817cfdb..9529a98d14 100644 --- a/packages/neo-one-cli-common/src/setupWallets.ts +++ b/packages/neo-one-cli-common/src/setupWallets.ts @@ -128,6 +128,10 @@ export const setupWallets = async ( ) { const result = await client.transfer( WALLETS.reduce((acc, wallet) => acc.concat(createWalletTransfers(wallet)), []), + { + maxNetworkFee: new BigNumber(-1), + maxSystemFee: new BigNumber(-1), + }, ); await Promise.all([result.confirmed(), developerClient.runConsensusNow()]); } diff --git a/packages/neo-one-cli/src/__tests__/compile.test.ts b/packages/neo-one-cli/src/__tests__/compile.test.ts new file mode 100644 index 0000000000..159f6f46f4 --- /dev/null +++ b/packages/neo-one-cli/src/__tests__/compile.test.ts @@ -0,0 +1,71 @@ +import fs from 'fs-extra'; +import path from 'path'; +import { compileContract } from '../compile/compileContract'; + +const folder = '/Users/spencercorwin/Desktop/compiler-tests'; +const scPath = path.join(folder, 'test.ts'); + +const writeFile = async (source: string) => { + await fs.writeFile(scPath, source, 'utf-8'); +}; + +const compileContractLocal = async () => compileContract(scPath, 'test', {}, {}); + +// TODO: move or udpate or delete these tests +describe('example compiles', () => { + beforeEach(async () => { + await fs.emptyDir(folder); + }); + + test.only('basic contract', async () => { + const source = ` + import { SmartContract } from '@neo-one/smart-contract'; + + export class Token extends SmartContract { + public readonly properties = { + groups: [], + permissions: [{ methods: ['himethod'], contract: { hash: '0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc', group: '0248be3c070df745a60f3b8b494efcc6caf90244d803a9a72fe95d9bae2120ec70' } }], + trusts: ['0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc'], + }; + public readonly name = 'One'; + public readonly symbol = 'ONE'; + public readonly decimals = 8; + } + `; + + await writeFile(source); + const result = await compileContractLocal(); + + console.log(result.contract.contract.manifest); + result.contract.contract.manifest.abi.methods.forEach((method) => { + console.log(method); + }); + // expect(result).toBeDefined(); + }); + + test('contract with getter', async () => { + const source = ` + import { SmartContract } from '@neo-one/smart-contract'; + + export class Token extends SmartContract { + public readonly properties = { + codeVersion: '1.0', + author: 'dicarlo2', + email: 'alex.dicarlo@neotracker.io', + description: 'NEO•ONE Token', + }; + public readonly name = 'One'; + public readonly symbol = 'ONE'; + public readonly decimals = 8; + private mutableSupply: Fixed<8> = 0; + + @constant + public get totalSupply(): Fixed<8> { + return this.mutableSupply; + } + } + `; + + await writeFile(source); + }); +}); diff --git a/packages/neo-one-cli/src/build/createTasks.ts b/packages/neo-one-cli/src/build/createTasks.ts index 8132e7a291..52787a94d7 100644 --- a/packages/neo-one-cli/src/build/createTasks.ts +++ b/packages/neo-one-cli/src/build/createTasks.ts @@ -11,7 +11,7 @@ import { findContracts } from './findContracts'; import { generateCode } from './generateCode'; import { generateCommonCode } from './generateCommonCode'; import { setupWallets } from './setupWallets'; -import { startNeotracker } from './startNeotracker'; +// import { startNeotracker } from './startNeotracker'; import { startNetwork } from './startNetwork'; export const createTasks = (cmd: Command, config: Configuration, reset: boolean) => @@ -45,7 +45,7 @@ export const createTasks = (cmd: Command, config: Configuration, reset: boolean) (ctx.foundContracts as Contracts).map((contract) => ({ title: `Deploy ${contract.name}`, task: async (innerCtx) => { - const { linked, sourceMaps, abi, address, sourceMap } = await deployContract( + const { linked, sourceMaps, manifest, address, sourceMap } = await deployContract( config, contract.filePath, contract.name, @@ -67,7 +67,7 @@ export const createTasks = (cmd: Command, config: Configuration, reset: boolean) config, contract.filePath, contract.name, - abi, + manifest, _.merge( {}, { @@ -96,10 +96,11 @@ export const createTasks = (cmd: Command, config: Configuration, reset: boolean) await generateCommonCode(config, ctx.contracts, networks, ctx.sourceMaps); }, }, - { - title: 'Start NEO Tracker instance', - task: async (_ctx, task) => { - config.neotracker.skip ? task.skip('NEO Tracker instance skipped.') : await startNeotracker(cmd, config, reset); - }, - }, + // TODO: add this back + // { + // title: 'Start NEO Tracker instance', + // task: async (_ctx, task) => { + // config.neotracker.skip ? task.skip('NEO Tracker instance skipped.') : await startNeotracker(cmd, config, reset); + // }, + // }, ]); diff --git a/packages/neo-one-cli/src/build/deployContract.ts b/packages/neo-one-cli/src/build/deployContract.ts index 756f0b6c5c..06616b68c7 100644 --- a/packages/neo-one-cli/src/build/deployContract.ts +++ b/packages/neo-one-cli/src/build/deployContract.ts @@ -13,7 +13,7 @@ export const deployContract = async ( linked: LinkedContracts, sourceMaps: SourceMaps, ) => { - const contract = compileContract(filePath, name, createCompilerHost(), linked); + const contract = await compileContract(filePath, name, createCompilerHost(), linked); if (contract.diagnostics.some((diagnostic) => diagnostic.category === DiagnosticCategory.Error)) { throw new Error('Compilation error.'); } @@ -32,13 +32,13 @@ export const deployContract = async ( await deployContractBase( provider, contract.contract, - contract.abi, + contract.contract.manifest, nextSourceMaps, common.privateKeyToString(getPrimaryKeys().privateKey), ); return { - abi: contract.abi, + manifest: contract.contract.manifest, address, sourceMap, sourceMaps: nextSourceMaps, diff --git a/packages/neo-one-cli/src/build/generateCode.ts b/packages/neo-one-cli/src/build/generateCode.ts index d08ae22924..2d159cf778 100644 --- a/packages/neo-one-cli/src/build/generateCode.ts +++ b/packages/neo-one-cli/src/build/generateCode.ts @@ -1,5 +1,5 @@ import { Configuration } from '@neo-one/cli-common'; -import { ABI, SmartContractNetworksDefinition } from '@neo-one/client-common'; +import { ContractManifestClient, SmartContractNetworksDefinition } from '@neo-one/client-common'; import { genFiles } from '@neo-one/smart-contract-codegen'; import * as fs from 'fs-extra'; import * as nodePath from 'path'; @@ -10,20 +10,20 @@ export const generateCode = async ( config: Configuration, filePath: string, name: string, - abi: ABI, + manifest: ContractManifestClient, networksDefinition: SmartContractNetworksDefinition, ) => { const base = nodePath.resolve(config.codegen.path, name); const { sourceMapsPath } = getCommonPaths(config); - const { typesPath, abiPath, createContractPath } = getContractPaths(config, name); - const { abi: abiFile, contract, types } = genFiles({ + const { typesPath, manifestPath, createContractPath } = getContractPaths(config, name); + const { manifest: manifestFile, contract, types } = genFiles({ name, networksDefinition, contractPath: filePath, typesPath, - abiPath, + manifestPath, createContractPath, - abi, + manifest, sourceMapsPath, browserify: config.codegen.browserify, }); @@ -34,11 +34,11 @@ export const generateCode = async ( await fs.ensureDir(base); if (config.codegen.language === 'typescript') { await Promise.all([ - writeFile(getTSPath(abiPath), abiFile.ts), + writeFile(getTSPath(manifestPath), manifestFile.ts), writeFile(getTSPath(createContractPath), contract.ts), writeFile(getTSPath(typesPath), types.ts), ]); } else { - await Promise.all([writeFile(abiPath, abiFile.js), writeFile(createContractPath, contract.js)]); + await Promise.all([writeFile(manifestPath, manifestFile.js), writeFile(createContractPath, contract.js)]); } }; diff --git a/packages/neo-one-cli/src/build/setupWallets.ts b/packages/neo-one-cli/src/build/setupWallets.ts index 48fbd7a86b..cf892e74bd 100644 --- a/packages/neo-one-cli/src/build/setupWallets.ts +++ b/packages/neo-one-cli/src/build/setupWallets.ts @@ -5,7 +5,7 @@ import { WALLETS as WALLETS_BASE, } from '@neo-one/cli-common'; import { common, crypto, privateKeyToAddress, wifToPrivateKey } from '@neo-one/client-common'; -import { NEOONEDataProvider } from '@neo-one/client-core'; +import { Hash160, NEOONEDataProvider } from '@neo-one/client-core'; import { constants } from '@neo-one/utils'; import BigNumber from 'bignumber.js'; import { getPrimaryKeys } from '../common'; @@ -18,8 +18,8 @@ const hasBalance = async (provider: NEOONEDataProvider, wallet: BootstrapWallet) const account = await provider.getAccount(privateKeyToAddress(privateKey)); return ( - (account.balances[common.NEO_ASSET_HASH] as BigNumber | undefined) !== undefined || - (account.balances[common.GAS_ASSET_HASH] as BigNumber | undefined) + (account.balances[Hash160.NEO] as BigNumber | undefined) !== undefined || + (account.balances[Hash160.GAS] as BigNumber | undefined) ); }; diff --git a/packages/neo-one-cli/src/cmd/init.ts b/packages/neo-one-cli/src/cmd/init.ts index 10d0fa9e79..a6c4363e26 100644 --- a/packages/neo-one-cli/src/cmd/init.ts +++ b/packages/neo-one-cli/src/cmd/init.ts @@ -36,7 +36,13 @@ export const builder = (yargsBuilder: typeof yargs) => yargsBuilder .boolean('react') .describe('react', 'Generate an example react component that uses the HelloWorld smart contract.') - .default('react', false); + .default('react', false) + .boolean('typescript') + .describe( + 'typescript', + 'Initialize a NEO•ONE project with TypeScript. If no tsconfig is found a default one will be generated.', + ) + .default('typescript', false); export const handler = (argv: Yarguments>) => { start(async (_cmd, config) => { const tsconfigPath = nodePath.resolve(config.contracts.path, 'tsconfig.json'); @@ -155,8 +161,37 @@ export const ExampleHelloWorld = () => { argv.react ? writeFile(reactPath, reactContents) : Promise.resolve(), ]); - if (rootTSConfigContents) { - const rootTSConfig = JSON.parse(rootTSConfigContents); + if (rootTSConfigContents !== undefined || argv.typescript) { + // This acts as a default if there's an unparsable tsconfig present. This is taken from create-react-app tsconfig + let rootTSConfig = { + compilerOptions: { + target: 'es5', + lib: ['dom', 'dom.iterable', 'esnext'], + allowJs: true, + skipLibCheck: true, + esModuleInterop: true, + allowSyntheticDefaultImports: true, + strict: true, + forceConsistentCasingInFileNames: true, + module: 'esnext', + moduleResolution: 'node', + resolveJsonModule: true, + isolatedModules: true, + noEmit: true, + jsx: 'react-jsx', + }, + // tslint:disable-next-line: no-any + } as any; + + if (rootTSConfigContents !== undefined) { + try { + rootTSConfig = JSON.parse(rootTSConfigContents); + } catch (e) { + console.log( + `Problem parsing the root tsconfig found at ${rootTSConfigPath}. Using NEO•ONE defaults. Make sure your tsconfig is JSON and try again. Parse error: ${e.message}`, + ); + } + } const exclude = rootTSConfig.exclude === undefined ? [] : rootTSConfig.exclude; const excludePath = normalizePath(nodePath.relative(process.cwd(), nodePath.join(config.contracts.path, '*.ts'))); if (!new Set(exclude).has(excludePath)) { diff --git a/packages/neo-one-cli/src/cmd/start/network.ts b/packages/neo-one-cli/src/cmd/start/network.ts index 420440d191..cba8c97143 100644 --- a/packages/neo-one-cli/src/cmd/start/network.ts +++ b/packages/neo-one-cli/src/cmd/start/network.ts @@ -1,7 +1,7 @@ -import { common, crypto } from '@neo-one/client-common'; +import { common } from '@neo-one/client-common'; import { cliLogger } from '@neo-one/logger'; import { FullNode } from '@neo-one/node'; -import { createMain } from '@neo-one/node-neo-settings'; +import { createPriv } from '@neo-one/node-neo-settings'; import yargs from 'yargs'; import { getPrimaryKeys, isRunning, start } from '../../common'; import { writePidFile } from './writePidFile'; @@ -23,10 +23,10 @@ export const handler = () => { const fullNode = new FullNode({ options: { path: config.network.path, - blockchain: createMain({ + blockchain: createPriv({ standbyValidators: [common.ecPointToString(publicKey)], extraCommitteeMembers: [], - privateNet: true, + // privateNet: true, }), node: { consensus: { diff --git a/packages/neo-one-cli/src/common/paths.ts b/packages/neo-one-cli/src/common/paths.ts index 51a523e17e..68ab8688c1 100644 --- a/packages/neo-one-cli/src/common/paths.ts +++ b/packages/neo-one-cli/src/common/paths.ts @@ -15,12 +15,12 @@ export const getCommonPaths = (config: Configuration) => ({ export const getContractPaths = (config: Configuration, name: string) => { const base = nodePath.resolve(config.codegen.path, name); const typesPath = nodePath.resolve(base, 'types.js'); - const abiPath = nodePath.resolve(base, 'abi.js'); + const manifestPath = nodePath.resolve(base, 'manifest.js'); const createContractPath = nodePath.resolve(base, 'contract.js'); return { typesPath, - abiPath, + manifestPath, createContractPath, }; }; diff --git a/packages/neo-one-cli/src/compile/compileContract.ts b/packages/neo-one-cli/src/compile/compileContract.ts index 8104bc81ab..368a1628a3 100644 --- a/packages/neo-one-cli/src/compile/compileContract.ts +++ b/packages/neo-one-cli/src/compile/compileContract.ts @@ -9,7 +9,7 @@ export const compileContract = async ( linked: LinkedContracts, sourceMaps: SourceMaps, ) => { - const contract = compileContractInternal(filePath, name, createCompilerHost(), linked); + const contract = await compileContractInternal(filePath, name, createCompilerHost(), linked); if (contract.diagnostics.some((diagnostic) => diagnostic.category === DiagnosticCategory.Error)) { throw new Error('Compilation error.'); } diff --git a/packages/neo-one-cli/src/compile/interop.ts b/packages/neo-one-cli/src/compile/interop.ts index 362ee538b5..b3084ba9ba 100644 --- a/packages/neo-one-cli/src/compile/interop.ts +++ b/packages/neo-one-cli/src/compile/interop.ts @@ -1,4 +1,4 @@ -import { ContractABI } from '@neo-one/client'; +import { ContractABIClient } from '@neo-one/client'; import { common, crypto } from '@neo-one/client-common'; const jmpABI = { @@ -47,7 +47,7 @@ const getDispatcherMethodDefinition = (contractName: string, jumpAddress: number 'sequence-points': [], }); -interface NEOONEContractMetadata { +export interface NEOONEContractMetadata { readonly name: string; readonly description: string; readonly codeVersion: string; @@ -69,7 +69,7 @@ const convertABIMetadata = (metadata: NEOONEContractMetadata) => ({ 'is-payable': metadata.payable, }); -const convertABI = (abi: ContractABI, metadata: NEOONEContractMetadata, script: Buffer) => ({ +const convertABI = (abi: ContractABIClient, metadata: NEOONEContractMetadata, script: Buffer) => ({ hash: common.uInt160ToHex(crypto.toScriptHash(script)), entrypoint: '@Jmp', functions: [ diff --git a/packages/neo-one-cli/src/compile/writeContract.ts b/packages/neo-one-cli/src/compile/writeContract.ts index 26a45f39b6..578493f698 100644 --- a/packages/neo-one-cli/src/compile/writeContract.ts +++ b/packages/neo-one-cli/src/compile/writeContract.ts @@ -6,7 +6,7 @@ import JSZip from 'jszip'; import _ from 'lodash'; import path from 'path'; import { SourceMapConsumer } from 'source-map'; -import { convertABI, getDispatcherMethodDefinition, getJmpMethodDefinition } from './interop'; +import { convertABI, getDispatcherMethodDefinition, getJmpMethodDefinition, NEOONEContractMetadata } from './interop'; export interface CompileWriteOptions { readonly json: boolean; @@ -18,7 +18,7 @@ export interface CompileWriteOptions { const getJumpLength = (value: string): number => { const [, unknownOp] = value.split(':'); const [op, arg] = unknownOp.split(' '); - if (op !== 'JMP') { + if (op !== 'JMP' && op !== 'JMP_L') { throw new Error(`${unknownOp} is not a JMP call`); } @@ -34,14 +34,31 @@ export const writeContract = async ( await fs.ensureDir(outDir); const outputPath = path.resolve(outDir, `${contractIn.contract.name}.contract.json`); - const { sourceMap: sourceMapPromise, debugInfo, contract, abi } = contractIn; + const { sourceMap: sourceMapPromise, debugInfo, contract } = contractIn; + + const manifest = contract.manifest; + + // TODO: get this from compiler? Or change properties expected + const metadata: NEOONEContractMetadata = { + name: contract.name, + description: 'A NEO•ONE Smart Contract', + codeVersion: '1.0', + author: 'NEO•ONE', + email: 'contact@neo-one.io', + storage: true, + dynamicInvoke: true, + payable: true, + }; const sourceMap = await sourceMapPromise; if (jsonFlag) { const contractJSON = JSON.stringify(contract, undefined, 2); await Promise.all([ - fs.writeFile(outputPath.replace('.contract.json', '.neoone.abi.json'), JSON.stringify(abi, undefined, 2)), + fs.writeFile( + outputPath.replace('.contract.json', '.neoone.manifest.json'), + JSON.stringify(manifest, undefined, 2), + ), fs.writeFile(outputPath, contractJSON), ]); } @@ -52,7 +69,7 @@ export const writeContract = async ( fs.writeFile(outputPath.replace('.contract.json', '.avm'), byteCode), fs.writeFile( outputPath.replace('.contract.json', '.abi.json'), - JSON.stringify(convertABI(abi, contract, byteCode), undefined, 2), + JSON.stringify(convertABI(manifest.abi, metadata, byteCode), undefined, 2), ), ]); } @@ -63,7 +80,7 @@ export const writeContract = async ( } const disassembled = disassembleByteCode(byteCode); - const jmpAddress = getJumpLength(disassembled[0].value); + const jmpAddress = getJumpLength(disassembled[3].value); // TODO: abstract this index from compiler package. FIRST_JMP_IDX = 3; const endAddress = disassembled[disassembled.length - 1].pc; const jmpMethod = getJmpMethodDefinition(contract.name); @@ -75,7 +92,7 @@ export const writeContract = async ( source: filePath, line, column: undefined, - // tslint:disable-next-line: no-any column doesn't have to be defined + // tslint:disable-next-line: no-any } as any) .map(({ line: lineOut }) => { if (lineOut !== null) { @@ -130,13 +147,11 @@ export const writeContract = async ( entrypoint: '0', documents: debugInfo.documents, methods: [jmpMethod, dispatcherMethod, ...methods], - events: abi.events - ? abi.events.map((event, index) => ({ - id: `${lastID + index}`, - name: `${contract.name}-${event.name}`, - params: event.parameters.map((param) => `${param.name},${param.type}`), - })) - : [], + events: manifest.abi.events.map((event, index) => ({ + id: `${lastID + index}`, + name: `${contract.name}-${event.name}`, + params: event.parameters.map((param) => `${param.name},${param.type}`), + })), }; if (avmFlag) { diff --git a/packages/neo-one-cli/src/deploy/actionResult.ts b/packages/neo-one-cli/src/deploy/actionResult.ts index f3fb8e09ad..872745cef2 100644 --- a/packages/neo-one-cli/src/deploy/actionResult.ts +++ b/packages/neo-one-cli/src/deploy/actionResult.ts @@ -11,6 +11,7 @@ import { Log, RawAction, RawInvocationResult, + RawInvokeReceipt, serializeParam, } from '@neo-one/client-common'; import { PublishReceipt } from '@neo-one/client-full-core'; @@ -69,7 +70,6 @@ const serializeInvocationResult = ( const commonObj = { ...result, gasConsumed: result.gasConsumed.toString(10), - gasCost: result.gasCost.toString(10), }; if (result.state === 'HALT') { @@ -133,10 +133,15 @@ const deserializeContractParameter = (param: ContractParameter) => const serializeRawInvocationResult = (result: RawInvocationResult) => ({ ...result, gasConsumed: result.gasConsumed.toString(10), - gasCost: result.gasCost.toString(10), stack: result.stack.map(serializeContractParameter), }); +const serializeRawInvokeReceipt = (result: RawInvokeReceipt) => ({ + ...result, + gasConsumed: result.gasConsumed.toString(10), + stack: typeof result.stack === 'string' ? [] : result.stack.map(serializeContractParameter), +}); + const deserializeRawInvocationResult = (result: any): RawInvocationResult => ({ ...result, gasConsumed: new BigNumber(result.gasConsumed), @@ -148,12 +153,12 @@ const serializeRawAction = (action: RawAction) => action.type === 'Notification' ? { ...action, - args: action.args.map(serializeContractParameter), - globalIndex: action.globalIndex.toString(10), + args: typeof action.state === 'string' ? [] : action.state.map(serializeContractParameter), + // globalIndex: action.globalIndex.toString(10), } : { ...action, - globalIndex: action.globalIndex.toString(10), + // globalIndex: action.globalIndex.toString(10), }; const deserializeRawAction = (action: any): RawAction => @@ -170,7 +175,7 @@ const deserializeRawAction = (action: any): RawAction => const serializeLog = (log: Log) => ({ ...log, - globalIndex: log.globalIndex.toString(10), + // globalIndex: log.globalIndex.toString(10), }); const deserializeLog = (log: any): Log => ({ @@ -180,7 +185,7 @@ const deserializeLog = (log: any): Log => ({ const serializeEvent = (event: Event) => ({ ...event, - globalIndex: new BigNumber(event.globalIndex), + // globalIndex: new BigNumber(event.globalIndex), parameters: _.fromPairs(Object.entries(event.parameters).map(([k, v]) => [k, serializeParam(v)])), }); @@ -199,8 +204,8 @@ const serializeInvokeReceipt = (receipt: InvokeReceipt) => ({ raw: { ...receipt.raw, globalIndex: receipt.raw.globalIndex.toString(10), - actions: receipt.raw.actions.map(serializeRawAction), - result: serializeRawInvocationResult(receipt.raw.result), + actions: [...receipt.raw.logs, ...receipt.raw.notifications].map(serializeRawAction), + result: serializeRawInvokeReceipt(receipt.raw), }, }); diff --git a/packages/neo-one-cli/src/deploy/loadContracts.ts b/packages/neo-one-cli/src/deploy/loadContracts.ts index ca20f18c21..4187cf5dbe 100644 --- a/packages/neo-one-cli/src/deploy/loadContracts.ts +++ b/packages/neo-one-cli/src/deploy/loadContracts.ts @@ -8,7 +8,7 @@ import { findContracts } from '../build'; import { Print } from '../common'; const compile = async (filePath: string, name: string, linked: LinkedContracts, sourceMaps: SourceMaps) => { - const contract = compileContract(filePath, name, createCompilerHost(), linked); + const contract = await compileContract(filePath, name, createCompilerHost(), linked); if (contract.diagnostics.some((diagnostic) => diagnostic.category === DiagnosticCategory.Error)) { throw new Error('Compilation error.'); } diff --git a/packages/neo-one-cli/src/deploy/printAction.ts b/packages/neo-one-cli/src/deploy/printAction.ts index 237c20793a..1658c42cd1 100644 --- a/packages/neo-one-cli/src/deploy/printAction.ts +++ b/packages/neo-one-cli/src/deploy/printAction.ts @@ -1,4 +1,4 @@ -import { Attribute, paramTo, TransactionOptions, Transfer } from '@neo-one/client-common'; +import { Attribute, paramTo, toJSONAttributeType, TransactionOptions, Transfer } from '@neo-one/client-common'; import { Print } from '../common'; import { Action, MigrationParam } from './types'; @@ -25,9 +25,7 @@ const paramToString = (paramIn: MigrationParam): string => { }); }; -const attributeToString = (attribute: Attribute) => - ` - Usage: ${attribute.usage} - Data: ${attribute.data}`; +const attributeToString = (attribute: Attribute) => ` - Type: ${toJSONAttributeType(attribute.type)}`; const transferToString = (transfer: Transfer) => ` Amount: ${transfer.amount.toString(10)} Asset: ${transfer.asset} @@ -46,14 +44,14 @@ ${options.attributes.map(attributeToString).join('\n')}`; From: ${options.from}`; } - if (options.networkFee !== undefined) { + if (options.maxNetworkFee !== undefined) { str += ` -Network Fee: ${options.networkFee.toString(10)}`; +Network Fee: ${options.maxNetworkFee.toString(10)}`; } - if (options.systemFee !== undefined) { + if (options.maxSystemFee !== undefined) { str += ` -System Fee: ${options.systemFee.toString(10)}`; +System Fee: ${options.maxSystemFee.toString(10)}`; } return str; @@ -66,8 +64,8 @@ export const printAction = (action: Action, print: Print) => { action.options !== undefined && (action.options.attributes !== undefined || action.options.from !== undefined || - action.options.networkFee !== undefined || - action.options.systemFee !== undefined) + action.options.maxNetworkFee !== undefined || + action.options.maxSystemFee !== undefined) ) { rest += ` Transaction Options:${transactionOptionsToString(action.options)}`; diff --git a/packages/neo-one-cli/src/deploy/runMigration.ts b/packages/neo-one-cli/src/deploy/runMigration.ts index 06da26ac80..9b4b90792f 100644 --- a/packages/neo-one-cli/src/deploy/runMigration.ts +++ b/packages/neo-one-cli/src/deploy/runMigration.ts @@ -1,6 +1,6 @@ // tslint:disable promise-function-async no-any no-loop-statement import { Configuration } from '@neo-one/cli-common'; -import { SourceMaps } from '@neo-one/client-common'; +import { scriptHashToAddress, SourceMaps } from '@neo-one/client-common'; import { getParamAndOptionsResults, SmartContractAny } from '@neo-one/client-core'; import { Client } from '@neo-one/client-full-core'; import { CompileContractResult } from '@neo-one/smart-contract-compiler'; @@ -37,7 +37,7 @@ export const runMigration = async ( let contracts: Contracts = _.fromPairs( Object.entries(nameToContract).map(([name, contract]) => [ name, - client.smartContract({ manifest: contract.manifest, networks: {} }), + client.smartContract({ manifest: contract.contract.manifest, networks: {} }), ]), ); @@ -46,15 +46,12 @@ export const runMigration = async ( Object.entries(nameToContract).map(([name, contract]) => [ name, _.fromPairs( - contract.manifest.abi.methods.map((func) => [ + contract.contract.manifest.abi.methods.map((func) => [ func.name, (...args: any[]) => { const { requiredArgs, forwardOptions, options, transfer, hash } = getParamAndOptionsResults({ parameters: func.parameters === undefined ? [] : func.parameters, args, - send: !!func.send, - completeSend: !!func.completeSend, - refundAssets: !!func.refundAssets, }); const deferred = createDeferred(); @@ -125,12 +122,12 @@ export const runMigration = async ( const params = await Promise.all(action.params); const result = await client.publishAndDeploy( contract.contract, - contract.manifest, + contract.contract.manifest, params, { ...(action.options === undefined ? {} : action.options), - systemFee: new BigNumber(1000), - networkFee: new BigNumber(1), + maxSystemFee: new BigNumber(1000), + maxNetworkFee: new BigNumber(1), }, sourceMaps, ); @@ -139,15 +136,15 @@ export const runMigration = async ( throw new Error(receipt.result.message); } - print(`Deployed ${action.contract} at ${receipt.result.value.address}`); + print(`Deployed ${action.contract} at ${scriptHashToAddress(receipt.result.value.hash)}`); contracts = { ...contracts, [action.contract]: client.smartContract({ - manifest: contract.manifest, + manifest: contract.contract.manifest, networks: { [network]: { - address: receipt.result.value.address, + address: scriptHashToAddress(receipt.result.value.hash), }, }, }), @@ -157,7 +154,7 @@ export const runMigration = async ( ...deployed, [action.contract]: { [network]: { - address: receipt.result.value.address, + address: scriptHashToAddress(receipt.result.value.hash), }, }, }; diff --git a/packages/neo-one-client-common/src/BinaryWriter.ts b/packages/neo-one-client-common/src/BinaryWriter.ts index 36113bd958..877db835f3 100644 --- a/packages/neo-one-client-common/src/BinaryWriter.ts +++ b/packages/neo-one-client-common/src/BinaryWriter.ts @@ -253,6 +253,16 @@ export class BinaryWriter { }); } + public writeVarBytesLEWithoutVar(value: Buffer): this { + return this.push({ + fn: (val: Buffer, buffer: Buffer, pos: number) => { + writeFromBuffer(val, buffer, pos); + }, + length: value.length, + value, + }); + } + public writeVarUIntLE(valueIn: number | BN): this { const value = new BN(valueIn); if (value.lt(utils.ZERO)) { @@ -284,6 +294,15 @@ export class BinaryWriter { return this.writeVarBytesLE(buffer); } + public writeVarStringWithoutVar(value: string, max?: number): this { + let buffer = Buffer.from(value, 'utf8'); + if (max !== undefined) { + buffer = buffer.slice(0, max); + } + + return this.writeVarBytesLEWithoutVar(buffer); + } + public writeECPoint(value: ECPoint): this { if (common.ecPointIsInfinity(value)) { return this.push({ diff --git a/packages/neo-one-client-common/src/ScriptBuilder.ts b/packages/neo-one-client-common/src/ScriptBuilder.ts index faf8958fec..34d72a5d89 100644 --- a/packages/neo-one-client-common/src/ScriptBuilder.ts +++ b/packages/neo-one-client-common/src/ScriptBuilder.ts @@ -72,6 +72,7 @@ export class ScriptBuilder extends BaseScriptBuilder { return this.emitSysCall('System.Contract.Call'); } + // TODO: need to fix how we call contracts later // tslint:disable-next-line readonly-array public emitAppCall(scriptHash: UInt160, operation: string, ...params: ScriptBuilderParam[]): this { this.emitAppCallInvocation(operation, ...params); diff --git a/packages/neo-one-client-common/src/StackItemType.ts b/packages/neo-one-client-common/src/StackItemType.ts new file mode 100644 index 0000000000..1572b3d8f0 --- /dev/null +++ b/packages/neo-one-client-common/src/StackItemType.ts @@ -0,0 +1,41 @@ +import { InvalidFormatError } from './common'; + +export enum StackItemType { + Any = 0x00, + Pointer = 0x10, + Boolean = 0x20, + Integer = 0x21, + ByteString = 0x28, + Buffer = 0x30, + Array = 0x40, + Struct = 0x41, + Map = 0x48, + InteropInterface = 0x60, +} + +// tslint:disable-next-line: strict-type-predicates +export const isStackItemType = (value: number): value is StackItemType => StackItemType[value] !== undefined; + +export const assertStackItemType = (value: number): StackItemType => { + if (isStackItemType(value)) { + return value; + } + + throw new InvalidFormatError(`Expected StackItemType, found: ${value}`); +}; + +export type StackItemTypeJSON = keyof typeof StackItemType; + +export const isStackItemTypeJSON = (type: string): type is StackItemTypeJSON => + // tslint:disable-next-line: strict-type-predicates no-any + StackItemType[type as any] !== undefined; + +export const assertStackItemTypeJSON = (type: string): StackItemTypeJSON => { + if (isStackItemTypeJSON(type)) { + return type; + } + + throw new InvalidFormatError(); +}; + +export const toStackItemTypeJSON = (type: StackItemType) => assertStackItemTypeJSON(StackItemType[type]); diff --git a/packages/neo-one-client-common/src/__tests__/models/vm.test.ts b/packages/neo-one-client-common/src/__tests__/models/vm.test.ts index 0c76d6a6da..1ce955ad7d 100644 --- a/packages/neo-one-client-common/src/__tests__/models/vm.test.ts +++ b/packages/neo-one-client-common/src/__tests__/models/vm.test.ts @@ -1,4 +1,4 @@ -import { assertByteCode, assertSysCall, assertVMState } from '../../models'; +import { assertByteCode, assertSysCall, assertVMState, getSysCallHash, SysCall, SysCallHashNum } from '../../models'; describe('VM Unit Tests - Functions', () => { test('Assert ByteCode', () => { @@ -14,6 +14,7 @@ describe('VM Unit Tests - Functions', () => { expect(assertVMState(goodVMState)).toEqual(goodVMState); }); }); + describe('VM Unit Tests - Errors', () => { test('Assert ByteCode - Bad Byte', () => { const badByte = 0xff; @@ -28,3 +29,34 @@ describe('VM Unit Tests - Errors', () => { expect(() => assertVMState(badVMState)).toThrowError(`Invalid VM State: ${badVMState}`); }); }); + +const createHexString = (bytes: Buffer): string => { + let mutableResult = ''; + bytes.forEach((byte) => { + mutableResult += `${byte.toString(16).padStart(2, '0')}`; + }); + + return `0x${mutableResult}`; +}; + +describe('SysCall Hashes', () => { + test('Get SysCall hashes', () => { + const result: { [key: string]: string } = {}; + // tslint:disable-next-line: no-loop-statement forin no-for-in + for (const item in SysCall) { + // tslint:disable-next-line: no-any no-object-mutation + result[item] = createHexString(getSysCallHash(item as any)); + } + // tslint:disable-next-line: no-console + console.log(result); + }); + + // tslint:disable-next-line: no-loop-statement forin no-for-in + for (const syscall in SysCall) { + test(syscall, () => { + const hash = getSysCallHash(syscall as SysCall); + + expect(SysCallHashNum[hash.readUInt32BE(0)]).toEqual(syscall); + }); + } +}); diff --git a/packages/neo-one-client-common/src/contractParameters.ts b/packages/neo-one-client-common/src/contractParameters.ts index b845915e00..858e07f036 100644 --- a/packages/neo-one-client-common/src/contractParameters.ts +++ b/packages/neo-one-client-common/src/contractParameters.ts @@ -1,6 +1,6 @@ -import { utils as commonUtils, JSONObject } from '@neo-one/utils'; +import { utils as commonUtils } from '@neo-one/utils'; import BigNumber from 'bignumber.js'; -import { common, InvalidFormatError } from './common'; +import { common } from './common'; import { crypto } from './crypto'; import { InvalidContractParameterError } from './errors'; import { JSONHelper } from './JSONHelper'; @@ -29,18 +29,12 @@ import { VoidABI, } from './types'; import { utils } from './utils'; -import { - assertContractParameterType, - toContractParameterType, - assertContractParameterTypeJSON, - ContractParameterTypeModel, -} from './models'; const toBufferBuffer = (contractParameter: ContractParameter): Buffer => { let value; switch (contractParameter.type) { case 'Any': - value = Buffer.from([]); // TODO: check + value = Buffer.alloc(0, 0); break; case 'Signature': value = JSONHelper.readBuffer(contractParameter.value); @@ -323,10 +317,11 @@ const toVoidNullable = wrapNullable(toVoid) as (param: ContractParameter) => und const toForwardValueNullable = wrapNullable(toForwardValue) as (param: ContractParameter) => undefined | undefined; export const contractParameters = { - // TODO: check Any: (_contractParameter: ContractParameter, _parameter: AnyABI): Return | undefined => undefined, String: (contractParameter: ContractParameter, parameter: StringABI): Return | undefined => parameter.optional ? toStringNullable(contractParameter) : toString(contractParameter), + Address: (contractParameter: ContractParameter, parameter: Hash160ABI): Return | undefined => + parameter.optional ? toAddressNullable(contractParameter) : toAddress(contractParameter), Hash160: (contractParameter: ContractParameter, parameter: Hash160ABI): Return | undefined => parameter.optional ? toAddressNullable(contractParameter) : toAddress(contractParameter), Hash256: (contractParameter: ContractParameter, parameter: Hash256ABI): Return | undefined => diff --git a/packages/neo-one-client-common/src/crypto.ts b/packages/neo-one-client-common/src/crypto.ts index fdb684dd72..cfe61bf601 100644 --- a/packages/neo-one-client-common/src/crypto.ts +++ b/packages/neo-one-client-common/src/crypto.ts @@ -42,7 +42,7 @@ const sha1 = (value: Buffer): Buffer => createHash('sha1').update(value).digest( const sha256 = sha256In; const rmd160 = (value: Buffer): Buffer => - createHash(process.versions.hasOwnProperty('electron') ? 'ripemd160' : 'rmd160') + createHash(process?.versions.hasOwnProperty('electron') ? 'ripemd160' : 'rmd160') .update(value) .digest(); @@ -892,6 +892,7 @@ const serializeHDNode = (node: HDNode, privateNode = true): string => { export const crypto = { addPublicKey, + rmd160, sha1, sha256, hash160, diff --git a/packages/neo-one-client-common/src/index.ts b/packages/neo-one-client-common/src/index.ts index a44456a45b..6c8da434ab 100644 --- a/packages/neo-one-client-common/src/index.ts +++ b/packages/neo-one-client-common/src/index.ts @@ -13,3 +13,4 @@ export * from './BaseScriptBuilder'; export * from './ScriptBuilder'; export * from './types'; export * from './utils'; +export * from './StackItemType'; diff --git a/packages/neo-one-client-common/src/models/AccountContract.ts b/packages/neo-one-client-common/src/models/AccountContract.ts index 2e641b5bee..b346fe1593 100644 --- a/packages/neo-one-client-common/src/models/AccountContract.ts +++ b/packages/neo-one-client-common/src/models/AccountContract.ts @@ -1,8 +1,8 @@ import _ from 'lodash'; -import { JSONHelper } from '../JSONHelper'; import { common, ECPoint, UInt160 } from '../common'; import { crypto } from '../crypto'; import { scriptHashToAddress } from '../helpers'; +import { JSONHelper } from '../JSONHelper'; import { utils } from '../utils'; import { ContractParameterTypeModel, diff --git a/packages/neo-one-client-common/src/models/trigger.ts b/packages/neo-one-client-common/src/models/trigger.ts index fd8a6b923f..3a4f8fab89 100644 --- a/packages/neo-one-client-common/src/models/trigger.ts +++ b/packages/neo-one-client-common/src/models/trigger.ts @@ -5,7 +5,9 @@ export enum TriggerType { PostPersist = 0x02, Verification = 0x20, Application = 0x40, + // tslint:disable-next-line: no-bitwise System = OnPersist | PostPersist, + // tslint:disable-next-line: no-bitwise All = OnPersist | PostPersist | Verification | Application, } diff --git a/packages/neo-one-client-common/src/models/types.ts b/packages/neo-one-client-common/src/models/types.ts index e57892139a..fcf3891506 100644 --- a/packages/neo-one-client-common/src/models/types.ts +++ b/packages/neo-one-client-common/src/models/types.ts @@ -9,71 +9,66 @@ import { VerifyResultModel } from './VerifyResultModel'; import { VMState, VMStateJSON } from './vm'; import { WitnessScopeModel } from './WitnessScopeModel'; -export interface ContractParameterDefinitionJSON { - readonly type: keyof typeof ContractParameterTypeModel; - readonly name: string; -} - -export interface AnyContractParameterJSON extends ContractParameterDefinitionJSON { +export interface AnyContractParameterJSON { readonly type: 'Any'; readonly value: undefined; } -export interface ArrayContractParameterJSON extends ContractParameterDefinitionJSON { +export interface ArrayContractParameterJSON { readonly type: 'Array'; readonly value: readonly ContractParameterJSON[]; } -export interface BooleanContractParameterJSON extends ContractParameterDefinitionJSON { +export interface BooleanContractParameterJSON { readonly type: 'Boolean'; readonly value: boolean; } -export interface ByteArrayContractParameterJSON extends ContractParameterDefinitionJSON { +export interface ByteArrayContractParameterJSON { readonly type: 'ByteArray'; readonly value: string; } -export interface Hash160ContractParameterJSON extends ContractParameterDefinitionJSON { +export interface Hash160ContractParameterJSON { readonly type: 'Hash160'; readonly value: string; } -export interface Hash256ContractParameterJSON extends ContractParameterDefinitionJSON { +export interface Hash256ContractParameterJSON { readonly type: 'Hash256'; readonly value: string; } -export interface IntegerContractParameterJSON extends ContractParameterDefinitionJSON { +export interface IntegerContractParameterJSON { readonly type: 'Integer'; readonly value: string; } -export interface InteropInterfaceContractParameterJSON extends ContractParameterDefinitionJSON { +export interface InteropInterfaceContractParameterJSON { readonly type: 'InteropInterface'; } -export interface MapContractParameterJSON extends ContractParameterDefinitionJSON { +export interface MapContractParameterJSON { readonly type: 'Map'; readonly value: ReadonlyArray; } -export interface PublicKeyContractParameterJSON extends ContractParameterDefinitionJSON { +export interface PublicKeyContractParameterJSON { readonly type: 'PublicKey'; readonly value: string; } -export interface SignatureContractParameterJSON extends ContractParameterDefinitionJSON { +export interface SignatureContractParameterJSON { readonly type: 'Signature'; readonly value: string; } -export interface StringContractParameterJSON extends ContractParameterDefinitionJSON { +export interface StringContractParameterJSON { readonly type: 'String'; readonly value: string; } -export interface VoidContractParameterJSON extends ContractParameterDefinitionJSON { +export interface VoidContractParameterJSON { readonly type: 'Void'; } @@ -94,12 +89,62 @@ export type ContractParameterJSON = export type ContractParameterTypeJSON = keyof typeof ContractParameterTypeModel; +export interface AnyStackItemJSON { + readonly type: 'Any'; + readonly value: undefined; +} + +export interface PointerStackItemJSON { + readonly type: 'Pointer'; + readonly value: number; +} + +export interface BooleanStackItemJSON { + readonly type: 'Boolean'; + readonly value: boolean; +} + +export interface IntegerStackItemJSON { + readonly type: 'Integer'; + readonly value: string; +} + +export interface ByteStringStackItemJSON { + readonly type: 'ByteString'; + readonly value: string; +} + +export interface BufferStackItemJSON { + readonly type: 'Buffer'; + readonly value: string; +} + +export interface ArrayStackItemJSON { + readonly type: 'Array'; + readonly value: readonly StackItemJSON[]; +} + +export interface MapStackItemJSON { + readonly type: 'Map'; + readonly value: ReadonlyArray<{ readonly key: PrimitiveStackItemJSON; readonly value: StackItemJSON }>; +} + +export type PrimitiveStackItemJSON = BooleanStackItemJSON | IntegerStackItemJSON | ByteStringStackItemJSON; + +export type StackItemJSON = + | AnyStackItemJSON + | PointerStackItemJSON + | PrimitiveStackItemJSON + | BufferStackItemJSON + | ArrayStackItemJSON + | MapStackItemJSON; + export type WitnessScopeJSON = keyof typeof WitnessScopeModel; +// TODO: delete export interface TransactionResultErrorJSON { readonly state: 'FAULT'; readonly gas_consumed: string; - readonly gas_cost: string; readonly stack: readonly ContractParameterJSON[]; readonly script: string; readonly message: string; @@ -108,7 +153,6 @@ export interface TransactionResultErrorJSON { export interface TransactionResultSuccessJSON { readonly state: 'HALT'; readonly gas_consumed: string; - readonly gas_cost: string; // TODO: not sure if this is redundant or not readonly stack: readonly ContractParameterJSON[]; readonly script: string; } @@ -217,10 +261,8 @@ export type AttributeTypeJSON = keyof typeof AttributeTypeModel; export type VerifyResultJSON = keyof typeof VerifyResultModel; -// TODO: what extra invocation data are we going to include now? export interface InvocationDataJSON { readonly result: InvocationResultJSON; - // readonly asset?: AssetJSON; readonly contracts: readonly ContractJSON[]; readonly deletedContractHashes: readonly string[]; readonly migratedContractHashes: ReadonlyArray; @@ -234,60 +276,6 @@ export interface UnclaimedGASJSON { readonly address: string; } -export interface StackItemJSONBase { - readonly type: StackItemJSON['type']; -} - -export interface AnyStackItemJSON extends StackItemJSONBase { - readonly type: 'Any'; - readonly value: undefined; -} - -export interface PointerStackItemJSON extends StackItemJSONBase { - readonly type: 'Pointer'; - readonly value: number; -} - -export interface BooleanStackItemJSON extends StackItemJSONBase { - readonly type: 'Boolean'; - readonly value: boolean; -} - -export interface IntegerStackItemJSON extends StackItemJSONBase { - readonly type: 'Integer'; - readonly value: string; -} - -export interface ByteStringStackItemJSON extends StackItemJSONBase { - readonly type: 'ByteString'; - readonly value: string; -} - -export interface BufferStackItemJSON extends StackItemJSONBase { - readonly type: 'Buffer'; - readonly value: string; -} - -export interface ArrayStackItemJSON extends StackItemJSONBase { - readonly type: 'Array'; - readonly value: readonly StackItemJSON[]; -} - -export interface MapStackItemJSON extends StackItemJSONBase { - readonly type: 'Map'; - readonly value: ReadonlyArray<{ readonly key: PrimitiveStackItemJSON; readonly value: StackItemJSON }>; -} - -export type PrimitiveStackItemJSON = BooleanStackItemJSON | IntegerStackItemJSON | ByteStringStackItemJSON; - -export type StackItemJSON = - | AnyStackItemJSON - | PointerStackItemJSON - | PrimitiveStackItemJSON - | BufferStackItemJSON - | ArrayStackItemJSON - | MapStackItemJSON; - export interface ExecutionResultJSON { readonly trigger: keyof typeof TriggerType; readonly contract: string; @@ -304,6 +292,7 @@ export interface ApplicationLogJSON { readonly gasconsumed: string; readonly stack: readonly StackItemJSON[] | string; readonly notifications: readonly NotificationJSON[]; + readonly logs: readonly LogJSON[]; } export interface AccountContractJSON { @@ -379,7 +368,10 @@ export interface ContractGroupJSON { readonly signature: string; } -export type ContractPermissionDescriptorJSON = string; +export interface ContractPermissionDescriptorJSON { + readonly hash?: string; + readonly group?: string; +} export interface ContractPermissionJSON { readonly contract: ContractPermissionDescriptorJSON; @@ -481,26 +473,26 @@ export interface NetworkSettingsJSON { readonly memorypoolmaxtransactions: number; } -// export interface CallReceiptJSON { -// readonly result: InvocationResultJSON; -// readonly actions: readonly ActionJSON[]; -// } - export interface NotificationJSON { readonly scripthash: string; readonly eventname: string; - readonly state: readonly StackItemJSON[] | string; + readonly state: readonly ContractParameterJSON[] | string; } export interface LogJSON { + readonly containerhash?: string; + readonly callingscripthash: string; readonly message: string; + // readonly position: number; } + export interface CallReceiptJSON { readonly script: string; readonly state: keyof typeof VMState; readonly gasconsumed: string; - readonly stack: readonly StackItemJSON[] | string; + readonly stack: readonly ContractParameterJSON[] | string; readonly notifications: readonly NotificationJSON[]; + readonly logs: readonly LogJSON[]; } export interface VerifyScriptResultJSON { diff --git a/packages/neo-one-client-common/src/models/vm.ts b/packages/neo-one-client-common/src/models/vm.ts index a318c74b94..124497d988 100644 --- a/packages/neo-one-client-common/src/models/vm.ts +++ b/packages/neo-one-client-common/src/models/vm.ts @@ -185,6 +185,7 @@ export enum Op { REVERSEITEMS = 0xd1, REMOVE = 0xd2, CLEARITEMS = 0xd3, + POPITEM = 0xd4, ISNULL = 0xd8, ISTYPE = 0xd9, CONVERT = 0xdb, @@ -280,6 +281,71 @@ export enum SysCall { 'System.Binary.Atoi' = 'System.Binary.Atoi', } +export enum SysCallHashNum { + 'System.Binary.Serialize' = 0x3f1c0124, + 'System.Binary.Deserialize' = 0x527cd0df, + 'System.Binary.Base64Encode' = 0xacbf5376, + 'System.Binary.Base64Decode' = 0xdba384c3, + 'System.Blockchain.GetHeight' = 0x7ef5721f, + 'System.Blockchain.GetBlock' = 0x8347922d, + 'System.Blockchain.GetTransaction' = 0xe6558d48, + 'System.Blockchain.GetTransactionHeight' = 0x4a3288b1, + 'System.Blockchain.GetTransactionFromBlock' = 0x7e56fd69, + 'System.Blockchain.GetContract' = 0xa9c54b41, + 'System.Callback.Create' = 0xd6a52d2a, + 'System.Callback.CreateFromMethod' = 0x7c507485, + 'System.Callback.CreateFromSyscall' = 0xd46efa70, + 'System.Callback.Invoke' = 0xd42b3dad, + 'System.Contract.Create' = 0xce352c85, + 'System.Contract.Update' = 0x31c6331d, + 'System.Contract.Destroy' = 0xc69f1df0, + 'System.Contract.Call' = 0x627d5b52, + 'System.Contract.CallEx' = 0xeef40cdb, + 'System.Contract.IsStandard' = 0xd76b9d85, + 'System.Contract.GetCallFlags' = 0x95da3a81, + 'System.Contract.CreateStandardAccount' = 0xcf998702, + 'Neo.Crypto.RIPEMD160' = 0x26d1d6d2, + 'Neo.Crypto.SHA256' = 0xd7ac7411, + 'Neo.Crypto.VerifyWithECDsaSecp256r1' = 0x95440d78, + 'Neo.Crypto.VerifyWithECDsaSecp256k1' = 0x7e3c53b7, + 'Neo.Crypto.CheckMultisigWithECDsaSecp256r1' = 0x138defaf, + 'Neo.Crypto.CheckMultisigWithECDsaSecp256k1' = 0x57c6efb2, + 'System.Enumerator.Create' = 0xbbaa607a, + 'System.Enumerator.Next' = 0x926d4cf0, + 'System.Enumerator.Value' = 0xbd20202c, + 'System.Enumerator.Concat' = 0xd406e5e1, + 'System.Iterator.Create' = 0xed64f727, + 'System.Iterator.Key' = 0x0e9488ba, + 'System.Iterator.Keys' = 0xfd9096e9, + 'System.Iterator.Values' = 0xbeee30ad, + 'System.Iterator.Concat' = 0xe5870a81, + 'System.Json.Serialize' = 0x248d264b, + 'System.Json.Deserialize' = 0xa79c470e, + 'Neo.Native.Deploy' = 0x123e7fe8, + 'Neo.Native.Call' = 0x6b67780b, + 'System.Runtime.Platform' = 0xb279fcf6, + 'System.Runtime.GetTrigger' = 0xe97d38a0, + 'System.Runtime.GetTime' = 0xb7c38803, + 'System.Runtime.GetScriptContainer' = 0x2d510830, + 'System.Runtime.GetExecutingScriptHash' = 0xdbfea874, + 'System.Runtime.GetCallingScriptHash' = 0x39536e3c, + 'System.Runtime.GetEntryScriptHash' = 0xf9b4e238, + 'System.Runtime.CheckWitness' = 0xf827ec8c, + 'System.Runtime.GetInvocationCounter' = 0x84271143, + 'System.Runtime.Log' = 0xcfe74796, + 'System.Runtime.Notify' = 0x95016f61, + 'System.Runtime.GetNotifications' = 0x274335f1, + 'System.Runtime.GasLeft' = 0x1488d8ce, + 'System.Storage.GetContext' = 0x9bf667ce, + 'System.Storage.GetReadOnlyContext' = 0xf6b46be2, + 'System.Storage.AsReadOnly' = 0x764cbfe9, + 'System.Storage.Get' = 0x925de831, + 'System.Storage.Find' = 0xdf30b89a, + 'System.Storage.Put' = 0xe63f1884, + 'System.Storage.PutEx' = 0x73e19b3a, + 'System.Storage.Delete' = 0x2f58c5ed, +} + export type SysCallName = keyof typeof SysCall; const isSysCall = (value: string): value is SysCall => @@ -293,6 +359,20 @@ export const assertSysCall = (value: string): SysCall => { throw new InvalidSysCallError(value); }; +export type SysCallHashName = keyof typeof SysCallHashNum; + +const isSysCallHash = (value: string): value is SysCallHashName => + // tslint:disable-next-line: strict-type-predicates + SysCallHashNum[value as SysCallHashName] !== undefined; + +export const assertSysCallHash = (value: string): SysCallHashName => { + if (isSysCallHash(value)) { + return value; + } + + throw new InvalidFormatError(); +}; + /** * if we do this with less lines TS will complain about the return type; * we could still look into another form of storing these syscalls, should test @@ -359,3 +439,5 @@ export const toSysCallHash = (value: SysCall): SysCallHash => { return hash; }; + +export const toSysCallName = (hash: SysCallHashNum): SysCallHashName => assertSysCallHash(SysCallHashNum[hash]); diff --git a/packages/neo-one-client-common/src/types.ts b/packages/neo-one-client-common/src/types.ts index 081dcba952..ea9f11b8a9 100644 --- a/packages/neo-one-client-common/src/types.ts +++ b/packages/neo-one-client-common/src/types.ts @@ -123,7 +123,7 @@ export interface Witness { } /** - * TODO: document this + * `Signer` is the description of an `Address` and `WitnessScope` that "signs" a transaction. */ export interface Signer { /** @@ -146,7 +146,6 @@ export interface Signer { /** * Interface for `Transaction`s - * TODO: should some of these be optional now? */ export interface Transaction { /** @@ -199,14 +198,6 @@ export interface Transaction { readonly witnesses: readonly Witness[]; } -// For Neo node returns -export interface VerboseTransaction extends Transaction { - readonly blockHash: UInt256; - readonly confirmations: number; - readonly blockTime: BigNumber; - readonly state: VMState; -} - /** * `Transaction` that has been confirmed on the blockchain. Includes all of the same properties as a `Transaction` as well as the `TransactionReceipt` of the confirmation. */ @@ -263,17 +254,9 @@ export interface Header { readonly size: number; } -export interface HeaderVerbose extends Header { - readonly confirmations: number; - readonly nextblockhash: Hash256String; -} - -/** - * TODO: document - */ export interface ConsensusData { /** - * TODO: document + * Primary index of the `ConsensusData`. */ readonly primaryIndex: number; /** @@ -330,14 +313,11 @@ export interface TransactionReceipt { /** * The result of a successful relay of a `Transaction`. */ -export interface TransactionResult< - TTransactionReceipt extends TransactionReceipt = TransactionReceipt, - TTransaction extends Transaction = Transaction -> { +export interface TransactionResult { /** * `Transaction` that was relayed. */ - readonly transaction: TTransaction; + readonly transaction: Transaction; /** * Waits for the `Transaction` to be confirmed on the blockchain. * @@ -348,43 +328,33 @@ export interface TransactionResult< } /** - * Common `InvocationResult` and `RawInvocationResult` properties. + * Result of a successful invocation. */ -export interface RawTransactionResultBase { +export interface InvocationResultSuccess { /** - * GAS consumed by the operation. This is the total GAS consumed after the free GAS is subtracted. + * GAS consumed by the operation. */ readonly gasConsumed: BigNumber; /** - * The total GAS cost before subtracting the free GAS. - */ - readonly gasCost: BigNumber; - /** - * Script run by the invocation. - */ - readonly script: BufferString; -} - -/** - * Result of a successful transaction. - */ -export interface TransactionResultSuccess extends RawTransactionResultBase { - /** - * Indicates a successful transaction. + * Indicates a successful invocation. */ readonly state: 'HALT'; /** - * The return value of the transaction. + * The return value of the invocation. */ readonly value: TValue; } /** - * Result of a failed transaction. + * Result of a failed invocation. */ -export interface TransactionResultError extends RawTransactionResultBase { +export interface InvocationResultError { + /** + * GAS consumed by the operation. + */ + readonly gasConsumed: BigNumber; /** - * Indicates a failed transaction. + * Indicates a failed invocation. */ readonly state: 'FAULT'; /** @@ -394,10 +364,9 @@ export interface TransactionResultError extends RawTransactionResultBase { } /** - * Either a successful or error result, `TransactionResultSuccess` and `TransactionResultError`, respectively. + * Either a successful or error result, `InvocationResultSuccess` and `InvocationResultError`, respectively. */ -export type InvocationResult = TransactionResultSuccess | TransactionResultError; - +export type InvocationResult = InvocationResultSuccess | InvocationResultError; /** * The receipt for a smart contract method invocation. */ @@ -416,7 +385,7 @@ export interface InvokeReceipt, paramsZipped: ReadonlyArray, verify: boolean, - options?: InvokeSendUnsafeReceiveTransactionOptions, - sourceMaps?: SourceMaps, - ) => Promise>; - /** - * Relays a transaction that is the first step of a two-step send process. The `Transfer`'s `to` property represents the ultimate destination of the funds, but this transaction will be constructed such that those funds are marked for transfer, not actually transferred. - * - * Otherwise, parameters are the same as `invoke`. - */ - readonly invokeSend: ( - contract: AddressString, - method: string, - params: ReadonlyArray, - paramsZipped: ReadonlyArray, - transfer: Transfer, options?: TransactionOptions, sourceMaps?: SourceMaps, ) => Promise>; - /** - * Relays a transaction that is the second step of a two-step send process. The `hash` is the transaction hash of the first step in the process and is used to determine the amount to transfer to the `from` address. - * - * Otherwise, parameters are the same as `invoke`. - */ - readonly invokeCompleteSend: ( - contract: AddressString, - method: string, - params: ReadonlyArray, - paramsZipped: ReadonlyArray, - hash: Hash256String, - options?: TransactionOptions, - sourceMaps?: SourceMaps, - ) => Promise>; - /** - * Refunds native assets that were not processed by the contract. The `hash` is the transaction hash that should be refunded and is used to construct the transfers for this transaction. - * - * Otherwise, parameters are the same as `invoke`. - */ - readonly invokeRefundAssets: ( - contract: AddressString, - method: string, - params: ReadonlyArray, - paramsZipped: ReadonlyArray, - hash: Hash256String, - options?: TransactionOptions, - sourceMaps?: SourceMaps, - ) => Promise>; - /** - * Claims GAS. Currently only supports claiming all unclaimed GAS to the contract address. - * - * Otherwise, parameters are the same as `invoke`. - */ - readonly invokeClaim: ( - contract: AddressString, - method: string, - params: ReadonlyArray, - paramsZipped: ReadonlyArray, - options?: TransactionOptions, - sourceMaps?: SourceMaps, - ) => Promise; /** * Invokes the constant `method` on `contract` with `params` on `network`. */ @@ -724,7 +638,7 @@ export interface EventParameters { /** * Structured data emitted by a smart contract during a method invocation. Typically emitted in response to state changes within the contract and to notify contract listeners of an action happening within the contract. */ -export interface Event extends RawActionBase { +export interface Event { /** * `type` differentiates the `Event` object from other `Action` objects, i.e. `Log`. */ @@ -747,7 +661,7 @@ export interface Event = readonly T[] | Wildcard; * If it specifies a contract hash, then that contract will be invoked. If it specifies the public key of a group, * then any contract in that group will be invoked. If it specifies a wildcard, then any contract will be invoked. */ -export type ContractPermissionDescriptor = UInt160Hex | PublicKeyString | Wildcard; +export interface ContractPermissionDescriptor { + /** + * If defined then this permission descriptor is for a contract. + */ + readonly hash?: UInt160Hex; + /** + * If defined then this permission descriptor is for a contract group. + */ + readonly group?: PublicKeyString; +} /** * Describes which contracts may be invoked and which methods are called. @@ -1518,7 +1661,7 @@ export interface ContractManifestClient { */ readonly hash: UInt160Hex; /** - * Set of mutually trusted contracts. + * A group represents a set of mutually trusted contracts. A contract will trust and allow any contract in the same group to invoke it, and the user interface will not give any warnings. */ readonly groups: readonly ContractGroup[]; /** @@ -1526,17 +1669,17 @@ export interface ContractManifestClient { */ readonly supportedStandards: readonly string[]; /** - * TODO: description * Full specification of the functions and events of a smart contract. Used by the Client APIs * to generate the smart contract interface. */ readonly abi: ContractABIClient; /** - * Describes which contracts may be invoked and which methods are called. + * The permissions field is an array containing a set of `ContractPermission` objects. It describes which contracts may be invoked and which methods are called. */ readonly permissions: readonly ContractPermission[]; /** - * The trusts field is an array containing a set of contract hashes or group of public keys. + * The trusts field is an array containing a set of contract hashes or group public keys. It can also be assigned with a wildcard *. If it is a wildcard *, then it means that it trusts any contract. + * If a contract is trusted, the user interface will not give any warnings when called by the contract. */ readonly trusts: WildcardContainer; /** @@ -1551,7 +1694,7 @@ export interface ContractManifestClient { */ export interface ContractManifest { /** - * Set of mutually trusted contracts. + * A group represents a set of mutually trusted contracts. A contract will trust and allow any contract in the same group to invoke it, and the user interface will not give any warnings. */ readonly groups: readonly ContractGroup[]; /** @@ -1564,11 +1707,12 @@ export interface ContractManifest { */ readonly abi: ContractABI; /** - * Describes which contracts may be invoked and which methods are called. + * The permissions field is an array containing a set of `ContractPermission` objects. It describes which contracts may be invoked and which methods are called. */ readonly permissions: readonly ContractPermission[]; /** - * The trusts field is an array containing a set of contract hashes or group of public keys. + * The trusts field is an array containing a set of contract hashes or group public keys. It can also be assigned with a wildcard *. If it is a wildcard *, then it means that it trusts any contract. + * If a contract is trusted, the user interface will not give any warnings when called by the contract. */ readonly trusts: WildcardContainer; /** @@ -1596,7 +1740,7 @@ export interface ScriptBuilderParamObject { readonly [key: string]: ScriptBuilderParam; } /** - * `Param` is converted internally via the `ABI` definition into a `ScriptBuilderParam` which is used to actually invoke the method on the smart contract. + * `Param` is converted internally via the `ContractABI` definition into a `ScriptBuilderParam` which is used to actually invoke the method on the smart contract. */ export type ScriptBuilderParam = | undefined @@ -1705,26 +1849,12 @@ export interface Contract { /* BEGIN LOW-LEVEL API */ -/** - * Describes the details of a contract parameter. - */ -export interface ContractParameterDefinition { - /** - * The type of the contract parameter. See `ContractParameterType` for information on possible contract parameter types. - */ - readonly type: ContractParameter['type']; - // /** - // * The name of the contract parameter. - // */ - readonly name: string; -} - /** * Invocation stack item for an `Any`. * * @see ContractParameter */ -export interface AnyContractParameter extends ContractParameterDefinition { +export interface AnyContractParameter { /** * `type` distinguishes `AnyContractParemeter` from other `ContractParameter` object types. */ @@ -1740,7 +1870,7 @@ export interface AnyContractParameter extends ContractParameterDefinition { * @see ContractParameter * @see SignatureString */ -export interface SignatureContractParameter extends ContractParameterDefinition { +export interface SignatureContractParameter { /** * `type` distinguishes `SignatureContractParameter` from other `ContractParameter` object types. */ @@ -1756,7 +1886,7 @@ export interface SignatureContractParameter extends ContractParameterDefinition * * @see ContractParameter */ -export interface BooleanContractParameter extends ContractParameterDefinition { +export interface BooleanContractParameter { /** * `type` distinguishes `BooleanContractParameter` from other `ContractParameter` object types. */ @@ -1775,7 +1905,7 @@ export interface BooleanContractParameter extends ContractParameterDefinition { * * @see ContractParameter */ -export interface IntegerContractParameter extends ContractParameterDefinition { +export interface IntegerContractParameter { /** * `type` distinguishes `IntegerContractParameter` from other `ContractParameter` object types. */ @@ -1786,13 +1916,30 @@ export interface IntegerContractParameter extends ContractParameterDefinition { readonly value: BN; } +/** + * Invocation stack item for an `Address`. + * + * @see ContractParameter + * @see UInt160 + */ +export interface AddressContractParameter { + /** + * `type` distinguishes `AddressContractParameter` from other `ContractParameter` object types. + */ + readonly type: 'Address'; + /** + * NEO address in base58 encoded string format. + */ + readonly value: AddressString; +} + /** * Invocation stack item for a `Hash160`. * * @see ContractParameter * @see UInt160 */ -export interface Hash160ContractParameter extends ContractParameterDefinition { +export interface Hash160ContractParameter { /** * `type` distinguishes `Hash160ContractParameter` from other `ContractParameter` object types. */ @@ -1809,7 +1956,7 @@ export interface Hash160ContractParameter extends ContractParameterDefinition { * @see ContractParameter * @see Hash256String */ -export interface Hash256ContractParameter extends ContractParameterDefinition { +export interface Hash256ContractParameter { /** * `type` distinguishes `Hash256ContractParameter` from other `ContractParameter` object types. */ @@ -1826,7 +1973,7 @@ export interface Hash256ContractParameter extends ContractParameterDefinition { * @see ContractParameter * @see BufferString */ -export interface BufferContractParameter extends ContractParameterDefinition { +export interface BufferContractParameter { /** * `type` distinguishes `BufferContractParameter` from other `ContractParameter` object types. */ @@ -1843,7 +1990,7 @@ export interface BufferContractParameter extends ContractParameterDefinition { * @see ContractParameter * @see PublicKeyString */ -export interface PublicKeyContractParameter extends ContractParameterDefinition { +export interface PublicKeyContractParameter { /** * `type` distinguishes `PublicKeyContractParameter` from other `ContractParameter` object types. */ @@ -1859,7 +2006,7 @@ export interface PublicKeyContractParameter extends ContractParameterDefinition * * @see ContractParameter */ -export interface StringContractParameter extends ContractParameterDefinition { +export interface StringContractParameter { /** * `type` distinguishes `StringContractParameter` from other `ContractParameter` object types. */ @@ -1875,7 +2022,7 @@ export interface StringContractParameter extends ContractParameterDefinition { * * @see ContractParameter */ -export interface ArrayContractParameter extends ContractParameterDefinition { +export interface ArrayContractParameter { /** * `type` distinguishes `ArrayContractParameter` from other `ContractParameter` object types. */ @@ -1891,7 +2038,7 @@ export interface ArrayContractParameter extends ContractParameterDefinition { * * @see ContractParameter */ -export interface MapContractParameter extends ContractParameterDefinition { +export interface MapContractParameter { /** * `type` distinguishes `MapContractParameter` from other `ContractParameter` object types. */ @@ -1909,7 +2056,7 @@ export interface MapContractParameter extends ContractParameterDefinition { * * @see ContractParameter */ -export interface InteropInterfaceContractParameter extends ContractParameterDefinition { +export interface InteropInterfaceContractParameter { /** * `type` distinguishes `InteropInterfaceContractParameter` from other `ContractParameter` object types. */ @@ -1921,7 +2068,7 @@ export interface InteropInterfaceContractParameter extends ContractParameterDefi * * @see ContractParameter */ -export interface VoidContractParameter extends ContractParameterDefinition { +export interface VoidContractParameter { /** * `type` distinguishes `VoidContractParameter` from other `ContractParameter` object types. */ @@ -1938,6 +2085,7 @@ export type ContractParameter = | SignatureContractParameter | BooleanContractParameter | IntegerContractParameter + | AddressContractParameter | Hash160ContractParameter | Hash256ContractParameter | BufferContractParameter @@ -1950,54 +2098,27 @@ export type ContractParameter = /** * All of the possible `type`s that a `ContractParameter` may have. - * Can be either: `Any`, `Boolean`, `Integer`, `ByteArray`, `String`, `Hash160`, `Hash256`, `PublicKey`, `Signature`, + * Can be either: `Any`, `Boolean`, `Integer`, `Buffer`, `String`, `Hash160`, `Hash256`, `PublicKey`, `Signature`, * `Array`, `Map`, `InteropInterface`, or `Void`. */ export type ContractParameterType = ContractParameter['type']; -/** - * Raw result of a successful invocation. - * - * Low-level API for advanced usage only. - */ -export interface RawTransactionResultSuccess extends RawTransactionResultBase { +// TODO: fix this +export interface RawInvocationResult { /** - * Indicates a successful invocation. + * Result of transaction execution. */ - readonly state: 'HALT'; + readonly state: 'FAULT' | 'HALT'; /** * The state of the NEO VM after execution. Typically has one `ContractParameter` which is the return value of the method invoked. */ readonly stack: readonly ContractParameter[]; -} - -/** - * Raw result of a failed invocation. - * - * Low-level API for advanced usage only. - */ -export interface RawTransactionResultError extends RawTransactionResultBase { - /** - * Indicates a failed invocation. - */ - readonly state: 'FAULT'; /** - * The state of the NEO VM after execution. Typically has one `ContractParameter` which is the return value of the method invoked. + * Total GAS consumed by the operation. */ - readonly stack: readonly ContractParameter[]; - /** - * A descriptive message indicating why the invocation failed. - */ - readonly message: string; + readonly gasConsumed: BigNumber; } -/** - * Raw result of an invocation. - * - * Low-level API for advanced usage only. - */ -export type RawInvocationResult = RawTransactionResultSuccess | RawTransactionResultError; - /** * Base properties of `Event`s and `Log`s as well as their raw counterparts, `RawNotification` and `RawLog`, respectively. */ @@ -2036,38 +2157,6 @@ export interface RawActionBase { readonly address: AddressString; } -/** - * Raw notification emitted during an invocation. This is the unprocessed counterpart to an `Event`. - * - * Low-level API for advanced usage only. - */ -export interface RawNotification extends RawActionBase { - /** - * `type` differentiates the `RawNotification` object from other `RawAction` objects, i.e. `RawLog`. - */ - readonly type: 'Notification'; - /** - * The raw arguments of the notifications. These are processed into the `parameters` parameter of the `Event` object using the `ABI`. - */ - readonly args: readonly ContractParameter[]; -} - -/** - * Raw log emitted during an invocation. - * - * Low-level API for advanced usage only. - */ -export interface RawLog extends RawActionBase { - /** - * `type` differentiates the `RawLog` object from other `RawAction` objects, i.e. `RawNotification`. - */ - readonly type: 'Log'; - /** - * The raw message. This is unprocessed in the `message`. - */ - readonly message: string; -} - /** * Raw action emitted during an invocation. * @@ -2151,8 +2240,23 @@ export interface RawCallReceipt { readonly state: keyof typeof VMState; readonly script: Buffer; readonly gasConsumed: BigNumber; - readonly stack: readonly RawStackItem[] | string; - readonly notifications: readonly NewRawNotification[]; + readonly stack: readonly ContractParameter[] | string; + readonly notifications: readonly RawNotification[]; + readonly logs: readonly RawLog[]; +} + +/** + * Raw receipt of an invocation. + * + * Low-level API for advanced usage only. + */ +export interface RawInvokeReceipt extends TransactionReceipt { + readonly state: keyof typeof VMState; + readonly script: Buffer; + readonly gasConsumed: BigNumber; + readonly stack: readonly ContractParameter[] | string; + readonly notifications: readonly RawNotification[]; + readonly logs: readonly RawLog[]; } /** @@ -2219,20 +2323,49 @@ export interface RawMapStackItem extends RawStackItemBase { * * Low-level API for advanced usage only. */ -export interface NewRawNotification { +export interface RawNotification { + /** + * `type` differentiates the `RawNotification` object from other `RawAction` objects, i.e. `RawLog`. + */ + readonly type: 'Notification'; + /** + * The script hash of the contract that created the notification. + */ readonly scriptHash: UInt160; + /** + * The event name of the notification. + */ readonly eventName: string; - readonly state: readonly RawStackItem[] | string; + /** + * The raw arguments of the notification. + */ + readonly state: readonly ContractParameter[] | string; } /** - * Raw receipt of an invocation. + * Raw log emitted from VM execution. * * Low-level API for advanced usage only. */ -export interface RawInvokeReceipt extends TransactionReceipt { - readonly result: RawInvocationResult; - readonly actions: readonly RawAction[]; +export interface RawLog { + /** + * `type` differentiates the `RawLog` object from other `RawAction` objects, i.e. `RawNotification`. + */ + readonly type: 'Log'; + /** + * The hash of the container that emitted the log. + */ + readonly containerHash?: UInt256; + /** + * The script hash of the transaction that called the invocation that emitted the log. + */ + readonly callingScriptHash: UInt160; + /** + * The raw message. This is unprocessed in the `message`. + */ + readonly message: string; + // TODO: implement + // readonly position: number; } /** @@ -2286,17 +2419,7 @@ export interface VerifyScriptResult { } /** - * Interface which describes the result of verification invocation. - */ -export interface VerifyTransactionResult { - /** - * All verifications that happened during the relay of the `Transaction`. - */ - readonly verifications: readonly VerifyScriptResult[]; -} - -/** - * Raw result of relaying a `Transaction`. Further consumed and processed by `LocalUserAccountProvider` and `ABI`. + * Raw result of relaying a `Transaction`. Further consumed and processed by `LocalUserAccountProvider` and `ContractABI`. */ export interface RelayTransactionResult { /** @@ -2309,36 +2432,6 @@ export interface RelayTransactionResult { readonly verifyResult?: VerifyResultModel; } -/** - * Additional raw data that is typically processed by an `ABI` for the client APIs. - */ -export interface RawInvocationData { - /** - * `Contract`s created by the invocation. - */ - readonly contracts: readonly Contract[]; - /** - * `Contract`s deleted by the invocation. - */ - readonly deletedContractAddresses: readonly AddressString[]; - /** - * `Contract`s migrated (upgraded) by the invocation. - */ - readonly migratedContractAddresses: ReadonlyArray; - /** - * Raw result of an invocation. - */ - readonly result: RawInvocationResult; - /** - * Raw actions emitted by the invocation. - */ - readonly actions: readonly RawAction[]; - /** - * Storage changes that occurred during this invocation - */ - readonly storageChanges: readonly RawStorageChange[]; -} - /** * Additional raw data that is typically used for the client APIs. */ @@ -2366,7 +2459,11 @@ export interface RawApplicationLogData { /** * The `Notification`s that came from the `Transaction`'s script execution. */ - readonly notifications: readonly NewRawNotification[]; + readonly notifications: readonly RawNotification[]; + /** + * The `Log`s that came from the `Transaction`'s script execution. + */ + readonly logs: readonly RawLog[]; } export interface ParamJSONArray extends ReadonlyArray {} diff --git a/packages/neo-one-client-core/package.json b/packages/neo-one-client-core/package.json index 75bff8eda1..7195db0191 100644 --- a/packages/neo-one-client-core/package.json +++ b/packages/neo-one-client-core/package.json @@ -28,7 +28,6 @@ "lodash": "^4.17.15", "rxjs": "^6.5.3", "safe-stable-stringify": "^1.1.0", - "synchronized-promise": "^0.3.1", "tapable": "^1.1.3", "tslib": "^1.10.0" }, diff --git a/packages/neo-one-client-core/src/Client.ts b/packages/neo-one-client-core/src/Client.ts index d83b65228f..b639981aaa 100644 --- a/packages/neo-one-client-core/src/Client.ts +++ b/packages/neo-one-client-core/src/Client.ts @@ -5,12 +5,10 @@ import { AddressString, Block, GetOptions, - Hash256String, - InvokeSendUnsafeReceiveTransactionOptions, - IterOptions, + // IterOptions, NetworkType, Param, - RawAction, + // RawAction, RawCallReceipt, RawInvokeReceipt, ScriptBuilderParam, @@ -27,8 +25,8 @@ import { UserAccountProvider, UserAccountProviders, } from '@neo-one/client-common'; -import { AsyncIterableX } from '@reactivex/ix-es2015-cjs/asynciterable/asynciterablex'; -import { flatMap } from '@reactivex/ix-es2015-cjs/asynciterable/pipe/flatmap'; +// import { AsyncIterableX } from '@reactivex/ix-es2015-cjs/asynciterable/asynciterablex'; +// import { flatMap } from '@reactivex/ix-es2015-cjs/asynciterable/pipe/flatmap'; import { toObservable } from '@reactivex/ix-es2015-cjs/asynciterable/toobservable'; import BigNumber from 'bignumber.js'; import _ from 'lodash'; @@ -473,22 +471,23 @@ export class Client< /** * @internal */ - public __iterActionsRaw(network: NetworkType, optionsIn?: IterOptions): AsyncIterable { - args.assertString('network', network); - const options = args.assertNullableIterOptions('iterOptions', optionsIn); - const provider = this.getNetworkProvider(network); - if (provider.iterActionsRaw !== undefined) { - return provider.iterActionsRaw(network, options); - } + // TODO: reimplement + // public __iterActionsRaw(network: NetworkType, optionsIn?: IterOptions): AsyncIterable { + // args.assertString('network', network); + // const options = args.assertNullableIterOptions('iterOptions', optionsIn); + // const provider = this.getNetworkProvider(network); + // if (provider.iterActionsRaw !== undefined) { + // return provider.iterActionsRaw(network, options); + // } - return AsyncIterableX.from(provider.iterBlocks(network, options)).pipe( - flatMap(async (block) => { - const actions = _.flatten(block.transactions.map((transaction) => [...transaction.invocationData.actions])); + // return AsyncIterableX.from(provider.iterBlocks(network, options)).pipe( + // flatMap(async (block) => { + // const actions = _.flatten(block.transactions.map((transaction) => [...transaction.invocationData.actions])); - return AsyncIterableX.of(...actions); - }), - ); - } + // return AsyncIterableX.of(...actions); + // }), + // ); + // } /** * @internal @@ -499,7 +498,7 @@ export class Client< params: ReadonlyArray, paramsZipped: ReadonlyArray, verify: boolean, - optionsIn?: InvokeSendUnsafeReceiveTransactionOptions, + optionsIn?: TransactionOptions, sourceMaps: SourceMaps = {}, ): Promise> { args.assertAddress('contract', contract); @@ -520,120 +519,6 @@ export class Client< ); } - /** - * @internal - */ - public async __invokeSend( - contract: AddressString, - method: string, - params: ReadonlyArray, - paramsZipped: ReadonlyArray, - transfer: Transfer, - optionsIn?: TransactionOptions, - sourceMaps: SourceMaps = {}, - ): Promise> { - args.assertAddress('contract', contract); - args.assertString('method', method); - args.assertArray('params', params).forEach((param) => args.assertNullableScriptBuilderParam('params.param', param)); - paramsZipped.forEach(([tupleString, tupleParam]) => [ - args.assertString('tupleString', tupleString), - args.assertNullableParam('tupleParam', tupleParam), - ]); - const options = args.assertTransactionOptions('options', optionsIn); - args.assertTransfer('transfer', transfer); - args.assertSourceMaps('sourceMaps', sourceMaps); - await this.applyBeforeRelayHook(options); - - return this.addTransactionHooks( - this.getProvider(options).invokeSend(contract, method, params, paramsZipped, transfer, options, sourceMaps), - ); - } - - /** - * @internal - */ - public async __invokeCompleteSend( - contract: AddressString, - method: string, - params: ReadonlyArray, - paramsZipped: ReadonlyArray, - hash: Hash256String, - optionsIn?: TransactionOptions, - sourceMaps: SourceMaps = {}, - ): Promise> { - args.assertAddress('contract', contract); - args.assertString('method', method); - args.assertArray('params', params).forEach((param) => args.assertNullableScriptBuilderParam('params.param', param)); - paramsZipped.forEach(([tupleString, tupleParam]) => [ - args.assertString('tupleString', tupleString), - args.assertNullableParam('tupleParam', tupleParam), - ]); - args.assertHash256('hash', hash); - const options = args.assertTransactionOptions('options', optionsIn); - args.assertSourceMaps('sourceMaps', sourceMaps); - await this.applyBeforeRelayHook(options); - - return this.addTransactionHooks( - this.getProvider(options).invokeCompleteSend(contract, method, params, paramsZipped, hash, options, sourceMaps), - ); - } - - /** - * @internal - */ - public async __invokeRefundAssets( - contract: AddressString, - method: string, - params: ReadonlyArray, - paramsZipped: ReadonlyArray, - hash: Hash256String, - optionsIn?: TransactionOptions, - sourceMaps: SourceMaps = {}, - ): Promise> { - args.assertAddress('contract', contract); - args.assertString('method', method); - args.assertArray('params', params).forEach((param) => args.assertNullableScriptBuilderParam('params.param', param)); - paramsZipped.forEach(([tupleString, tupleParam]) => [ - args.assertString('tupleString', tupleString), - args.assertNullableParam('tupleParam', tupleParam), - ]); - args.assertHash256('hash', hash); - const options = args.assertTransactionOptions('options', optionsIn); - args.assertSourceMaps('sourceMaps', sourceMaps); - await this.applyBeforeRelayHook(options); - - return this.addTransactionHooks( - this.getProvider(options).invokeRefundAssets(contract, method, params, paramsZipped, hash, options, sourceMaps), - ); - } - - /** - * @internal - */ - public async __invokeClaim( - contract: AddressString, - method: string, - params: ReadonlyArray, - paramsZipped: ReadonlyArray, - optionsIn?: TransactionOptions, - sourceMaps: SourceMaps = {}, - ): Promise { - args.assertAddress('contract', contract); - args.assertString('method', method); - args.assertArray('params', params).forEach((param) => args.assertNullableScriptBuilderParam('params.param', param)); - paramsZipped.forEach(([tupleString, tupleParam]) => [ - args.assertString('tupleString', tupleString), - args.assertNullableParam('tupleParam', tupleParam), - ]); - const options = args.assertTransactionOptions('options', optionsIn); - args.assertSourceMaps('sourceMaps', sourceMaps); - await this.applyBeforeRelayHook(options); - - return this.addTransactionHooks( - this.getProvider(options).invokeClaim(contract, method, params, paramsZipped, options, sourceMaps), - ); - } - /** * @internal */ diff --git a/packages/neo-one-client-core/src/__tests__/provider/__snapshots__/NEOProvider.test.ts.snap b/packages/neo-one-client-core/src/__tests__/provider/__snapshots__/NEOProvider.test.ts.snap deleted file mode 100644 index 47b3649c4b..0000000000 --- a/packages/neo-one-client-core/src/__tests__/provider/__snapshots__/NEOProvider.test.ts.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`NEOONEProvider getBlockCount - unknown network 1`] = `[Error [UNKNOWN_NETWORK]: Unknown network unknown]`; diff --git a/packages/neo-one-client-core/src/args.ts b/packages/neo-one-client-core/src/args.ts index 80e64786cd..b08297a569 100644 --- a/packages/neo-one-client-core/src/args.ts +++ b/packages/neo-one-client-core/src/args.ts @@ -21,6 +21,7 @@ import { ContractMethodDescriptor, ContractMethodDescriptorClient, ContractParameter, + ContractParameterDefinition, ContractPermission, ContractPermissionDescriptor, ForwardValue, @@ -147,6 +148,14 @@ export const assertBuffer = (name: string, buffer?: unknown): BufferString => { return value; }; +const assertNullablePublicKey = (name: string, publicKey?: unknown): PublicKeyString | undefined => { + if (publicKey == undefined) { + return undefined; + } + + return assertPublicKey(name, publicKey); +}; + export const assertPublicKey = (name: string, publicKey?: unknown): PublicKeyString => { const value = assertBuffer(name, publicKey); try { @@ -156,6 +165,14 @@ export const assertPublicKey = (name: string, publicKey?: unknown): PublicKeyStr } }; +const assertNullableUInt160Hex = (name: string, value?: unknown): UInt160Hex | undefined => { + if (value == undefined) { + return undefined; + } + + return assertUInt160Hex(name, value); +}; + const assertUInt160Hex = (name: string, value?: unknown): UInt160Hex => { const valueIn = assertString(name, value); @@ -291,14 +308,14 @@ const CONTRACT_PARAMETER_TYPES = new Set([ 'ForwardValue', ]); -const assertContractParameterType = (name: string, valueIn?: unknown): ContractParameter['type'] => { +const assertContractParameterType = (name: string, valueIn?: unknown): ContractParameterDefinition['type'] => { const value = assertString(name, valueIn); if (!CONTRACT_PARAMETER_TYPES.has(value)) { throw new InvalidArgumentError('ContractParameterType', name, value); } - return value as ContractParameter['type']; + return value as ContractParameterDefinition['type']; }; const assertMapProperty = ( @@ -321,9 +338,11 @@ const assertMapProperty = ( }; const ABI_TYPES = new Set([ + 'Any', 'Signature', 'Boolean', 'Hash160', + 'Address', 'Hash256', 'Buffer', 'PublicKey', @@ -352,29 +371,29 @@ const assertContractParameter = (paramName: string, value?: unknown): ContractPa } const type = assertProperty(value, 'ContractParameter', 'type', assertContractParameterType); - const name = assertProperty(value, 'ContractParameter', 'name', assertString); switch (type) { case 'Any': - return { type, name, value: undefined }; + return { type, value: undefined }; case 'Signature': - return { type, name, value: assertProperty(value, 'ContractParameter', 'value', assertString) }; + return { type, value: assertProperty(value, 'ContractParameter', 'value', assertString) }; case 'Boolean': - return { type, name, value: assertProperty(value, 'ContractParameter', 'value', assertBoolean) }; + return { type, value: assertProperty(value, 'ContractParameter', 'value', assertBoolean) }; + case 'Address': + return { type, value: assertProperty(value, 'ContractParameter', 'value', assertAddress) }; case 'Hash160': - return { type, name, value: assertProperty(value, 'ContractParameter', 'value', assertAddress) }; + return { type, value: assertProperty(value, 'ContractParameter', 'value', assertAddress) }; case 'Hash256': - return { type, name, value: assertProperty(value, 'ContractParameter', 'value', assertHash256) }; + return { type, value: assertProperty(value, 'ContractParameter', 'value', assertHash256) }; case 'Buffer': - return { type, name, value: assertProperty(value, 'ContractParameter', 'value', assertBuffer) }; + return { type, value: assertProperty(value, 'ContractParameter', 'value', assertBuffer) }; case 'PublicKey': - return { type, name, value: assertProperty(value, 'ContractParameter', 'value', assertPublicKey) }; + return { type, value: assertProperty(value, 'ContractParameter', 'value', assertPublicKey) }; case 'String': - return { type, name, value: assertProperty(value, 'ContractParameter', 'value', assertString) }; + return { type, value: assertProperty(value, 'ContractParameter', 'value', assertString) }; case 'Array': return { type, - name, value: assertProperty(value, 'ContractParameter', 'value', assertArray).map((param) => assertContractParameter('Array', param), ), @@ -382,22 +401,17 @@ const assertContractParameter = (paramName: string, value?: unknown): ContractPa case 'Map': return { type, - name, value: assertMapProperty(value, 'ContractParameter', 'value', assertContractParameter), }; case 'Void': - return { type, name }; + return { type }; case 'Integer': return { type, - name, value: assertProperty(value, 'ContractParameter', 'value', assertBN), }; case 'InteropInterface': - return { - type, - name, - }; + return { type }; default: /* istanbul ignore next */ utils.assertNever(type); @@ -454,6 +468,7 @@ const assertABIParameter = (propName: string, value?: unknown): ABIParameter => case 'Boolean': return { type, name, optional, default: defaultValue, forwardedValue, rest }; case 'Hash160': + case 'Address': return { type, name, optional, default: defaultValue, forwardedValue, rest }; case 'Hash256': return { type, name, optional, default: defaultValue, forwardedValue, rest }; @@ -539,6 +554,7 @@ const assertABIReturn = (name: string, value?: unknown): ABIReturn => { case 'Boolean': return { type, optional, forwardedValue }; case 'Hash160': + case 'Address': return { type, optional, forwardedValue }; case 'Hash256': return { type, optional, forwardedValue }; @@ -594,12 +610,6 @@ const assertContractMethodDescriptorClient = (name: string, value?: unknown): Co ).map((parameter) => assertABIParameter('ContractMethodDescriptorClient.parameters', parameter)), returnType: assertProperty(value, 'ContractMethodDescriptorClient', 'returnType', assertABIReturn), constant: assertProperty(value, 'ContractMethodDescriptorClient', 'constant', assertNullableBoolean), - send: assertProperty(value, 'ContractMethodDescriptorClient', 'send', assertNullableBoolean), - sendUnsafe: assertProperty(value, 'ContractMethodDescriptorClient', 'sendUnsafe', assertNullableBoolean), - receive: assertProperty(value, 'ContractMethodDescriptorClient', 'receive', assertNullableBoolean), - claim: assertProperty(value, 'ContractMethodDescriptorClient', 'claim', assertNullableBoolean), - refundAssets: assertProperty(value, 'ContractMethodDescriptorClient', 'refundAssets', assertNullableBoolean), - completeSend: assertProperty(value, 'ContractMethodDescriptorClient', 'completeSend', assertNullableBoolean), offset: assertProperty(value, 'ContractMethodDescriptorClient', 'offset', assertNumber), }; }; @@ -758,27 +768,6 @@ export const assertNullableJSON = (name: string, value?: unknown): JSONObject => return value; }; -const assertHashOrGroup = (name: string, value?: unknown): PublicKeyString | UInt160Hex | Wildcard => { - const valueIn = assertString(name, value); - if (valueIn === '*') { - return '*'; - } - - try { - return assertUInt160Hex(name, valueIn); - } catch { - // do nothing - } - - try { - return assertPublicKey(name, valueIn); - } catch { - // do nothing - } - - throw new InvalidArgumentError('HashOrGroup', name, value); -}; - export const assertContractManifestClient = (name: string, value?: unknown): ContractManifestClient => { if (!isObject(value)) { throw new InvalidArgumentError('ContractManifest', name, value); @@ -837,12 +826,16 @@ const assertContractPermissionDescriptor = (name: string, value?: unknown): Cont if (!isObject(value)) { throw new InvalidArgumentError('ContractPermissionDescriptor', name, value); } + const hash = assertProperty(value, 'ContractPermissionDescriptor', 'hash', assertNullableUInt160Hex); + const group = assertProperty(value, 'ContractPermissionDescriptor', 'group', assertNullablePublicKey); + + if (hash === undefined && group === undefined) { + throw new InvalidArgumentError('ContractPermissionDescriptor', name, value); + } return { - hashOrGroup: assertProperty(value, 'ContractPermissionDescriptor', 'hashOrGroup', assertHashOrGroup), - isHash: assertProperty(value, 'ContractPermissionDescriptor', 'isHash', assertBoolean), - isGroup: assertProperty(value, 'ContractPermissionDescriptor', 'isGroup', assertBoolean), - isWildcard: assertProperty(value, 'ContractPermissionDescriptor', 'isWildcard', assertBoolean), + hash, + group, }; }; diff --git a/packages/neo-one-client-core/src/clientUtils.ts b/packages/neo-one-client-core/src/clientUtils.ts index a06aebd9f0..6591bb8674 100644 --- a/packages/neo-one-client-core/src/clientUtils.ts +++ b/packages/neo-one-client-core/src/clientUtils.ts @@ -1,15 +1,4 @@ -import { - AddressString, - addressToScriptHash, - BufferString, - common, - NetworkType, - ScriptBuilder, - ScriptBuilderParam, - UInt160Hex, -} from '@neo-one/client-common'; -import sp from 'synchronized-promise'; -import { LocalKeyStore } from './user'; +import { common, ScriptBuilder, ScriptBuilderParam, UInt160Hex } from '@neo-one/client-common'; const getInvokeMethodInvocationScript = ({ method, @@ -39,17 +28,6 @@ const getInvokeMethodScript = ({ return sb.build(); }; -export const addLocalKeysSync = ( - wallets: ReadonlyArray<{ - readonly network: NetworkType; - readonly privateKey?: BufferString; - readonly name?: string; - readonly password?: string; - readonly nep2?: string; - }>, - keyStore: LocalKeyStore, -) => sp(async () => Promise.all(wallets.map((wallet) => keyStore.addUserAccount(wallet))))(); - export const clientUtils = { getInvokeMethodInvocationScript, getInvokeMethodScript, diff --git a/packages/neo-one-client-core/src/index.ts b/packages/neo-one-client-core/src/index.ts index 5cb6bb7070..e51a892c14 100644 --- a/packages/neo-one-client-core/src/index.ts +++ b/packages/neo-one-client-core/src/index.ts @@ -1,5 +1,4 @@ import * as args from './args'; -import { addLocalKeysSync } from './clientUtils'; import * as nep17 from './nep17'; export * from './AsyncBlockIterator'; @@ -12,4 +11,4 @@ export * from './sc'; export * from './trace'; export * from './types'; export * from './user'; -export { args, nep17, addLocalKeysSync }; +export { args, nep17 }; diff --git a/packages/neo-one-client-core/src/nep17.ts b/packages/neo-one-client-core/src/nep17.ts index 3a68367979..e6c0999dcf 100644 --- a/packages/neo-one-client-core/src/nep17.ts +++ b/packages/neo-one-client-core/src/nep17.ts @@ -1,4 +1,5 @@ import { + ABIParameter, AddressString, common, ContractABIClient, @@ -41,10 +42,15 @@ export interface NEP17SmartContract extends Sma ) => TransactionResult>; } +const defaultNEOONEParams: ReadonlyArray = [ + { type: 'String', name: 'method' }, + { type: 'Array', value: { type: 'Any' }, name: 'params' }, +]; + const decimalsFunction: ContractMethodDescriptorClient = { name: 'decimals', constant: true, - parameters: [], + parameters: [...defaultNEOONEParams], returnType: { type: 'Integer', decimals: 0 }, offset: 0, safe: true, @@ -60,7 +66,7 @@ export const abi = (decimals: number): ContractABIClient => ({ { name: 'name', constant: true, - parameters: [], + parameters: [...defaultNEOONEParams], returnType: { type: 'String' }, offset: 0, safe: true, @@ -68,7 +74,7 @@ export const abi = (decimals: number): ContractABIClient => ({ { name: 'symbol', constant: true, - parameters: [], + parameters: [...defaultNEOONEParams], returnType: { type: 'String' }, offset: 0, safe: true, @@ -77,7 +83,7 @@ export const abi = (decimals: number): ContractABIClient => ({ { name: 'totalSupply', constant: true, - parameters: [], + parameters: [...defaultNEOONEParams], returnType: { type: 'Integer', decimals }, offset: 0, safe: true, diff --git a/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts b/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts index 8c5548bed9..7f966781d0 100644 --- a/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts +++ b/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts @@ -23,7 +23,7 @@ import { ContractMethodDescriptorJSON, ContractParameterDefinition, ContractParameterDefinitionJSON, - ContractParameterType, + ContractParameterDefinitionType, ContractParameterTypeJSON, ContractPermission, ContractPermissionJSON, @@ -67,7 +67,7 @@ import BigNumber from 'bignumber.js'; import debug from 'debug'; import { AsyncBlockIterator } from '../AsyncBlockIterator'; import { clientUtils } from '../clientUtils'; -import { convertCallReceipt, convertNotification, convertStackItem } from './convert'; +import { convertCallReceipt, convertLog, convertNotification, convertStackItem } from './convert'; import { JSONRPCClient } from './JSONRPCClient'; import { JSONRPCHTTPProvider } from './JSONRPCHTTPProvider'; import { JSONRPCProvider, JSONRPCProviderManager } from './JSONRPCProvider'; @@ -423,22 +423,22 @@ export class NEOONEDataProvider implements DeveloperProvider { private convertContractABI(abi: ContractABIJSON): ContractABI { return { hash: abi.hash, - methods: abi.methods.map(this.convertContractMethodDescriptor), - events: abi.events.map(this.convertContractEventDescriptor), + methods: abi.methods.map(this.convertContractMethodDescriptor.bind(this)), + events: abi.events.map(this.convertContractEventDescriptor.bind(this)), }; } private convertContractEventDescriptor(event: ContractEventDescriptorJSON): ContractEventDescriptor { return { name: event.name, - parameters: event.parameters.map(this.convertContractParameterDefinition), + parameters: event.parameters.map(this.convertContractParameterDefinition.bind(this)), }; } private convertContractMethodDescriptor(method: ContractMethodDescriptorJSON): ContractMethodDescriptor { return { name: method.name, - parameters: method.parameters.map(this.convertContractParameterDefinition), + parameters: method.parameters.map(this.convertContractParameterDefinition.bind(this)), returnType: this.convertContractParameterType(method.returntype), offset: method.offset, }; @@ -451,7 +451,7 @@ export class NEOONEDataProvider implements DeveloperProvider { }; } - private convertContractParameterType(param: ContractParameterTypeJSON): ContractParameterType { + private convertContractParameterType(param: ContractParameterTypeJSON): ContractParameterDefinitionType { switch (param) { case 'Any': return 'Any'; @@ -494,6 +494,7 @@ export class NEOONEDataProvider implements DeveloperProvider { gasConsumed: new BigNumber(data.gasconsumed), stack: typeof data.stack === 'string' ? data.stack : data.stack.map(convertStackItem), notifications: data.notifications.map(convertNotification), + logs: data.logs.map(convertLog), }; } diff --git a/packages/neo-one-client-core/src/provider/NEOONEProvider.ts b/packages/neo-one-client-core/src/provider/NEOONEProvider.ts index a49661024b..5f21abfbd4 100644 --- a/packages/neo-one-client-core/src/provider/NEOONEProvider.ts +++ b/packages/neo-one-client-core/src/provider/NEOONEProvider.ts @@ -2,6 +2,7 @@ import { Account, AddressString, Block, + Contract, GetOptions, Hash256String, IterOptions, @@ -132,6 +133,10 @@ export class NEOONEProvider implements Provider { return this.getProvider(network).getAccount(address); } + public async getContract(network: NetworkType, address: AddressString): Promise { + return this.getProvider(network).getContract(address); + } + public iterBlocks(network: NetworkType, options: IterOptions = {}): AsyncIterable { return this.getProvider(network).iterBlocks(options); } diff --git a/packages/neo-one-client-core/src/provider/convert.ts b/packages/neo-one-client-core/src/provider/convert.ts index c4e4351195..ae0512cd6b 100644 --- a/packages/neo-one-client-core/src/provider/convert.ts +++ b/packages/neo-one-client-core/src/provider/convert.ts @@ -1,16 +1,17 @@ import { - ActionJSON, + // ActionJSON, CallReceiptJSON, common, ContractParameter, ContractParameterJSON, - InvocationResultJSON, + // InvocationResultJSON, JSONHelper, - NewRawNotification, + LogJSON, NotificationJSON, - RawAction, + // RawAction, RawCallReceipt, - RawInvocationResult, + RawLog, + RawNotification, RawStackItem, scriptHashToAddress, StackItemJSON, @@ -24,8 +25,19 @@ export function convertCallReceipt(receipt: CallReceiptJSON): RawCallReceipt { script: JSONHelper.readBuffer(receipt.script), state: receipt.state, gasConsumed: common.fixedToDecimal(new BN(receipt.gasconsumed), 0), - stack: typeof receipt.stack === 'string' ? receipt.stack : receipt.stack.map(convertStackItem), + stack: typeof receipt.stack === 'string' ? receipt.stack : receipt.stack.map(convertContractParameter), notifications: receipt.notifications.map(convertNotification), + logs: receipt.logs.map(convertLog), + }; +} + +export function convertLog(log: LogJSON): RawLog { + return { + type: 'Log', + containerHash: log.containerhash ? common.stringToUInt256(log.containerhash) : undefined, + callingScriptHash: common.stringToUInt160(log.callingscripthash), + message: log.message, + // position: log.position, }; } @@ -59,71 +71,71 @@ export function convertStackItem(item: StackItemJSON): RawStackItem { } } -export function convertNotification(notification: NotificationJSON): NewRawNotification { +export function convertNotification(notification: NotificationJSON): RawNotification { return { + type: 'Notification', scriptHash: common.stringToUInt160(notification.scripthash), eventName: notification.eventname, - state: typeof notification.state === 'string' ? notification.state : notification.state.map(convertStackItem), + state: typeof notification.state === 'string' ? notification.state : convertContractParameters(notification.state), }; } -export function convertAction( - blockHash: string, - blockIndex: number, - transactionHash: string, - transactionIndex: number, - index: number, - action: ActionJSON, -): RawAction { - if (action.type === 'Log') { - return { - type: 'Log', - version: action.version, - blockIndex, - blockHash, - transactionIndex, - transactionHash, - index, - globalIndex: JSONHelper.readUInt64(action.index), - address: scriptHashToAddress(action.scriptHash), - message: action.message, - }; - } +// TODO: delete or re-implement +// export function convertAction( +// blockHash: string, +// blockIndex: number, +// transactionHash: string, +// transactionIndex: number, +// index: number, +// action: ActionJSON, +// ): RawAction { +// if (action.type === 'Log') { +// return { +// type: 'Log', +// version: action.version, +// blockIndex, +// blockHash, +// transactionIndex, +// transactionHash, +// index, +// globalIndex: JSONHelper.readUInt64(action.index), +// address: scriptHashToAddress(action.scriptHash), +// message: action.message, +// }; +// } - return { - type: 'Notification', - version: action.version, - blockIndex, - blockHash, - transactionIndex, - transactionHash, - index, - globalIndex: JSONHelper.readUInt64(action.index), - address: scriptHashToAddress(action.scriptHash), - args: convertContractParameters(action.args), - }; -} +// return { +// type: 'Notification', +// version: action.version, +// blockIndex, +// blockHash, +// transactionIndex, +// transactionHash, +// index, +// globalIndex: JSONHelper.readUInt64(action.index), +// address: scriptHashToAddress(action.scriptHash), +// args: convertContractParameters(action.args), +// }; +// } -export function convertInvocationResult(result: InvocationResultJSON): RawInvocationResult { - if (result.state === 'FAULT') { - return { - state: 'FAULT', - gasConsumed: new BigNumber(result.gas_consumed), - gasCost: new BigNumber(result.gas_cost), - stack: convertContractParameters(result.stack), - message: result.message, - script: result.script, - }; - } +// export function convertInvocationResult(result: InvocationResultJSON): RawInvocationResult { +// if (result.state === 'FAULT') { +// return { +// state: 'FAULT', +// gasConsumed: new BigNumber(result.gas_consumed), +// stack: convertContractParameters(result.stack), +// message: result.message, +// script: result.script, +// }; +// } - return { - state: 'HALT', - gasConsumed: new BigNumber(result.gas_consumed), - gasCost: new BigNumber(result.gas_cost), - stack: convertContractParameters(result.stack), - script: result.script, - }; -} +// return { +// state: 'HALT', +// gasConsumed: new BigNumber(result.gas_consumed), +// stack: convertContractParameters(result.stack), +// script: result.script, +// }; +// } export function convertContractParameters(parameters: readonly ContractParameterJSON[]): readonly ContractParameter[] { return parameters.map(convertContractParameter); @@ -135,13 +147,11 @@ export function convertContractParameter(parameter: ContractParameterJSON): Cont return { type: 'Any', value: undefined, - name: parameter.name, }; case 'Array': return { type: 'Array', value: convertContractParameters(parameter.value), - name: parameter.name, }; case 'Boolean': return parameter; @@ -149,13 +159,11 @@ export function convertContractParameter(parameter: ContractParameterJSON): Cont return { type: 'Buffer', value: parameter.value, - name: parameter.name, }; case 'Hash160': return { type: 'Hash160', value: scriptHashToAddress(parameter.value), - name: parameter.name, }; case 'Hash256': return parameter; @@ -163,7 +171,6 @@ export function convertContractParameter(parameter: ContractParameterJSON): Cont return { type: 'Integer', value: new BN(parameter.value, 10), - name: parameter.name, }; case 'InteropInterface': return parameter; @@ -174,7 +181,6 @@ export function convertContractParameter(parameter: ContractParameterJSON): Cont convertContractParameter(key), convertContractParameter(val), ]), - name: parameter.name, }; case 'PublicKey': return parameter; diff --git a/packages/neo-one-client-core/src/sc/common.ts b/packages/neo-one-client-core/src/sc/common.ts index 6b9016a582..0b5d6e140c 100644 --- a/packages/neo-one-client-core/src/sc/common.ts +++ b/packages/neo-one-client-core/src/sc/common.ts @@ -16,10 +16,10 @@ import { Log, Param, RawAction, + RawCallReceipt, RawInvocationResult, Return, ScriptBuilderParam, - smartContractConverters, SourceMaps, } from '@neo-one/client-common'; import { processActionsAndMessage, processConsoleLogMessages } from '@neo-one/client-switch'; @@ -228,31 +228,34 @@ export const convertAction = ({ return action; } - const { args } = action; - if (args.length === 0) { + const { state, eventName: event } = action; + if (state.length === 0) { throw new InvalidEventError('Notification had no arguments'); } - const event = smartContractConverters.toString(args[0]); + if (typeof state === 'string') { + throw new InvalidEventError(`Notification serialization failed: ${state}`); + } + const eventSpec = events[event]; if (eventSpec === undefined) { return event; } return { - version: action.version, - blockIndex: action.blockIndex, - blockHash: action.blockHash, - transactionIndex: action.transactionIndex, - transactionHash: action.transactionHash, - index: action.index, - globalIndex: action.globalIndex, - address: action.address, + // version: action.version, + // blockIndex: action.blockIndex, + // blockHash: action.blockHash, + // transactionIndex: action.transactionIndex, + // transactionHash: action.transactionHash, + // index: action.index, + // globalIndex: action.globalIndex, + // address: action.address, type: 'Event', name: event, parameters: getParametersObject({ abiParameters: eventSpec.parameters, - parameters: args.slice(1), + parameters: state.slice(1), }), }; }; @@ -268,20 +271,17 @@ export const convertInvocationResult = async ({ readonly actions: readonly RawAction[]; readonly sourceMaps?: SourceMaps; }): Promise> => { - const { gasConsumed, gasCost, script } = result; + const { gasConsumed } = result; if (result.state === 'FAULT') { const message = await processActionsAndMessage({ actions, - message: result.message, sourceMaps, }); return { state: result.state, gasConsumed, - gasCost, message, - script, }; } @@ -293,21 +293,60 @@ export const convertInvocationResult = async ({ parameter: contractParameter, }); - return { state: result.state, gasConsumed, gasCost, value, script }; + return { state: result.state, gasConsumed, value }; +}; + +export const convertCallReceipt = async ({ + returnType, + receipt, + sourceMaps, +}: { + readonly returnType: ABIReturn; + readonly receipt: RawCallReceipt; + readonly sourceMaps?: SourceMaps; +}): Promise> => { + const actions = [...receipt.logs, ...receipt.notifications]; + const { gasConsumed } = receipt; + if (receipt.state === 'FAULT') { + const message = await processActionsAndMessage({ + actions, + sourceMaps, + }); + + return { + state: receipt.state, + gasConsumed, + message, + }; + } + + await processConsoleLogMessages({ actions, sourceMaps }); + + if (typeof receipt.stack === 'string') { + throw new Error(receipt.stack); + } + if (receipt.state === 'NONE' || receipt.state === 'BREAK') { + throw new Error('Should never return NONE or BREAK'); + } + const contractParameter = receipt.stack[0]; + const value = convertContractParameter({ + type: returnType, + parameter: contractParameter, + }); + + return { state: receipt.state, gasConsumed, value }; }; export const convertCallResult = async ({ returnType, - result: resultIn, - actions, + receipt, sourceMaps, }: { readonly returnType: ABIReturn; - readonly result: RawInvocationResult; - readonly actions: readonly RawAction[]; + readonly receipt: RawCallReceipt; readonly sourceMaps?: SourceMaps; }): Promise => { - const result = await convertInvocationResult({ returnType, result: resultIn, actions, sourceMaps }); + const result = await convertCallReceipt({ returnType, receipt, sourceMaps }); if (result.state === 'FAULT') { throw new InvocationCallError(result.message); } diff --git a/packages/neo-one-client-core/src/sc/createSmartContract.ts b/packages/neo-one-client-core/src/sc/createSmartContract.ts index dbfbac846a..55b575209b 100644 --- a/packages/neo-one-client-core/src/sc/createSmartContract.ts +++ b/packages/neo-one-client-core/src/sc/createSmartContract.ts @@ -1,43 +1,37 @@ /// import { ABIParameter, - Action, + // Action, AddressString, - ContractEventDescriptorClient, + // ContractEventDescriptorClient, ContractMethodDescriptorClient, - Event, + // Event, ForwardOptions, GetOptions, Hash256String, InvokeReceipt, InvokeSendUnsafeReceiveTransactionOptions, - Log, + // Log, NetworkType, Param, - RawAction, + // RawAction, RawInvokeReceipt, Return, ScriptBuilderParam, SmartContractDefinition, - SmartContractIterOptions, + // SmartContractIterOptions, SmartContractNetworkDefinition, TransactionResult, Transfer, } from '@neo-one/client-common'; -import { utils } from '@neo-one/utils'; -import { AsyncIterableX } from '@reactivex/ix-es2015-cjs/asynciterable/asynciterablex'; -import { filter } from '@reactivex/ix-es2015-cjs/asynciterable/pipe/filter'; -import { map } from '@reactivex/ix-es2015-cjs/asynciterable/pipe/map'; +// import { utils } from '@neo-one/utils'; +// import { AsyncIterableX } from '@reactivex/ix-es2015-cjs/asynciterable/asynciterablex'; +// import { filter } from '@reactivex/ix-es2015-cjs/asynciterable/pipe/filter'; +// import { map } from '@reactivex/ix-es2015-cjs/asynciterable/pipe/map'; import * as argAssertions from '../args'; import { Client } from '../Client'; -import { - CannotSendFromContractError, - CannotSendToContractError, - HashArgumentExpectedError, - NoContractDeployedError, - TransferArgumentExpectedError, -} from '../errors'; -import { events as traceEvents } from '../trace'; +import { CannotSendToContractError, NoContractDeployedError } from '../errors'; +// import { events as traceEvents } from '../trace'; import { SmartContractAny } from '../types'; import * as common from './common'; @@ -54,16 +48,10 @@ interface ParamAndOptionsResults { export const getParamAndOptionsResults = ({ parameters, args, - send, - completeSend, - refundAssets, }: { readonly parameters: readonly ABIParameter[]; // tslint:disable-next-line no-any readonly args: readonly any[]; - readonly send: boolean; - readonly completeSend: boolean; - readonly refundAssets: boolean; }): ParamAndOptionsResults => { const hasRest = parameters.length > 0 && parameters[parameters.length - 1].rest; const hasForwardValueOptions = hasRest && parameters[parameters.length - 1].type === 'ForwardValue'; @@ -84,7 +72,8 @@ export const getParamAndOptionsResults = ({ }; } - if (acc.transfer === undefined && send) { + // TODO: this block can almost definitely be removed. also remove transfer return likely + if (acc.transfer === undefined) { try { const maybeTransfer = argAssertions.assertTransfer('transfer', right); @@ -97,7 +86,8 @@ export const getParamAndOptionsResults = ({ } } - if (acc.hash === undefined && (completeSend || refundAssets)) { + // TODO: this block can almost definitely be removed. also remove hash return likely + if (acc.hash === undefined) { try { const maybeHash = argAssertions.assertHash256('hash', right); @@ -129,22 +119,14 @@ export const getParamsAndOptions = ({ definition: { networks }, parameters, args, - sendUnsafe, receive, - send, - completeSend, - refundAssets, client, }: { readonly definition: SmartContractDefinition; readonly parameters: readonly ABIParameter[]; // tslint:disable-next-line no-any readonly args: readonly any[]; - readonly sendUnsafe: boolean; readonly receive: boolean; - readonly send: boolean; - readonly completeSend: boolean; - readonly refundAssets: boolean; readonly client: Client; }): { readonly params: ReadonlyArray; @@ -159,18 +141,8 @@ export const getParamsAndOptions = ({ const { requiredArgs, forwardOptions, options: optionsIn, transfer, hash } = getParamAndOptionsResults({ parameters, args, - send, - completeSend, - refundAssets, }); - if (transfer === undefined && send) { - throw new TransferArgumentExpectedError(); - } - if (hash === undefined && (completeSend || refundAssets)) { - throw new HashArgumentExpectedError(); - } - const currentAccount = client.getCurrentUserAccount(); const options = (optionsIn === undefined || optionsIn.from === undefined) && currentAccount !== undefined @@ -192,9 +164,6 @@ export const getParamsAndOptions = ({ if (contractNetwork === undefined) { throw new NoContractDeployedError(network); } - if (options.sendFrom !== undefined && !sendUnsafe) { - throw new CannotSendFromContractError(contractNetwork.address); - } if (options.sendTo !== undefined && !receive) { throw new CannotSendToContractError(contractNetwork.address); } @@ -220,7 +189,7 @@ export const getParamsAndOptions = ({ const createCall = ({ definition, client, - func: { name, parameters = [], returnType }, + func: { name, parameters = [], returnType, receive = false }, }: { readonly definition: SmartContractDefinition; readonly client: Client; @@ -231,20 +200,16 @@ const createCall = ({ definition, parameters, args, - sendUnsafe: false, - receive: false, - send: false, - completeSend: false, - refundAssets: false, + receive, client, }); - const receipt = await client.__call(network, address, name, params); + // TODO: this needs to be reverted when we change how we call contracts + const receipt = await client.__call(network, address, name, [name, [...params]]); return common.convertCallResult({ returnType, - result: receipt.result, - actions: receipt.actions, + receipt, sourceMaps: definition.sourceMaps, }); }; @@ -252,17 +217,7 @@ const createCall = ({ const createInvoke = ({ definition, client, - func: { - name, - parameters = [], - returnType, - send = false, - refundAssets = false, - completeSend = false, - sendUnsafe = false, - receive = false, - claim = false, - }, + func: { name, parameters = [], returnType, receive = false }, }: { readonly definition: SmartContractDefinition; readonly client: Client; @@ -272,71 +227,24 @@ const createInvoke = ({ // tslint:disable-next-line no-any ...args: any[] ): Promise | TransactionResult> => { - const { params, paramsZipped, options, forwardOptions, address, transfer, hash } = getParamsAndOptions({ + const { params, paramsZipped, options, forwardOptions, address } = getParamsAndOptions({ definition, parameters, args, - sendUnsafe, receive, - send, - completeSend, - refundAssets, client, }); - if (claim) { - return client.__invokeClaim(address, name, params, paramsZipped, options, definition.sourceMaps); - } - - let result: TransactionResult; - if (send) { - /* istanbul ignore next */ - if (transfer === undefined) { - throw new Error('Something went wrong.'); - } - - result = await client.__invokeSend(address, name, params, paramsZipped, transfer, options, definition.sourceMaps); - } else if (refundAssets) { - /* istanbul ignore next */ - if (hash === undefined) { - throw new Error('Something went wrong.'); - } - - result = await client.__invokeRefundAssets( - address, - name, - params, - paramsZipped, - hash, - options, - definition.sourceMaps, - ); - } else if (completeSend) { - /* istanbul ignore next */ - if (hash === undefined) { - throw new Error('Something went wrong.'); - } - - result = await client.__invokeCompleteSend( - address, - name, - params, - paramsZipped, - hash, - options, - definition.sourceMaps, - ); - } else { - result = await client.__invoke( - address, - name, - params, - paramsZipped, - sendUnsafe || receive, - options, - definition.sourceMaps, - ); - } + const result: TransactionResult = await client.__invoke( + address, + name, + // TODO: this needs to be reverted when we change how we call contracts + [name, [...params]], + paramsZipped, + receive, + options, + definition.sourceMaps, + ); return { transaction: result.transaction, @@ -345,14 +253,24 @@ const createInvoke = ({ const { events = [] } = definition.manifest.abi; const { events: forwardEvents = [] } = forwardOptions; const actions = common.convertActions({ - actions: receipt.actions, + actions: [...receipt.logs, ...receipt.notifications], events: events.concat(forwardEvents), }); + // TODO: handle this better. or request that this be changed in the VM + const receiptStack = typeof receipt.stack === 'string' ? [] : receipt.stack; + + // TODO: change how state is handled + const receiptResult = { + gasConsumed: receipt.gasConsumed, + state: receipt.state as 'HALT' | 'FAULT', + stack: receiptStack, + }; + const invocationResult = await common.convertInvocationResult({ returnType, - result: receipt.result, - actions: receipt.actions, + result: receiptResult, + actions: [...receipt.logs, ...receipt.notifications], sourceMaps: definition.sourceMaps, }); @@ -401,56 +319,57 @@ export const createSmartContract = ({ abi: { events: abiEvents = [] }, }, } = definition; - const events = traceEvents.concat(abiEvents).reduce<{ [key: string]: ContractEventDescriptorClient }>( - (acc, event) => ({ - ...acc, - [event.name]: event, - }), - {}, - ); - - const iterActionsRaw = ({ - network = client.getCurrentNetwork(), - ...iterOptions - }: SmartContractIterOptions = {}): AsyncIterable => - AsyncIterableX.from(client.__iterActionsRaw(network, iterOptions)).pipe( - filter((action) => action.address === definition.networks[network].address), - ); - - const convertAction = (action: RawAction): Action | undefined => { - const converted = common.convertAction({ action, events }); - - return typeof converted === 'string' ? undefined : converted; - }; - - const iterActions = (options?: SmartContractIterOptions): AsyncIterable => - AsyncIterableX.from(iterActionsRaw(options)).pipe(map(convertAction), filter(utils.notNull)); - - const iterEvents = (options?: SmartContractIterOptions): AsyncIterable => - AsyncIterableX.from(iterActions(options)).pipe( - map((action) => { - if (action.type === 'Log') { - return undefined; - } - - return action; - }), - filter(utils.notNull), - filter(Boolean), - ); - - const iterLogs = (options?: SmartContractIterOptions): AsyncIterable => - AsyncIterableX.from(iterActions(options)).pipe( - map((action) => { - if (action.type === 'Event') { - return undefined; - } - - return action; - }), - filter(utils.notNull), - filter(Boolean), - ); + // TODO: reimplement this stuff + // const events = traceEvents.concat(abiEvents).reduce<{ [key: string]: ContractEventDescriptorClient }>( + // (acc, event) => ({ + // ...acc, + // [event.name]: event, + // }), + // {}, + // ); + + // const iterActionsRaw = ({ + // network = client.getCurrentNetwork(), + // ...iterOptions + // }: SmartContractIterOptions = {}): AsyncIterable => + // AsyncIterableX.from(client.__iterActionsRaw(network, iterOptions)).pipe( + // filter((action) => action.address === definition.networks[network].address), + // ); + + // const convertAction = (action: RawAction): Action | undefined => { + // const converted = common.convertAction({ action, events }); + + // return typeof converted === 'string' ? undefined : converted; + // }; + + // const iterActions = (options?: SmartContractIterOptions): AsyncIterable => + // AsyncIterableX.from(iterActionsRaw(options)).pipe(map(convertAction), filter(utils.notNull)); + + // const iterEvents = (options?: SmartContractIterOptions): AsyncIterable => + // AsyncIterableX.from(iterActions(options)).pipe( + // map((action) => { + // if (action.type === 'Log') { + // return undefined; + // } + + // return action; + // }), + // filter(utils.notNull), + // filter(Boolean), + // ); + + // const iterLogs = (options?: SmartContractIterOptions): AsyncIterable => + // AsyncIterableX.from(iterActions(options)).pipe( + // map((action) => { + // if (action.type === 'Event') { + // return undefined; + // } + + // return action; + // }), + // filter(utils.notNull), + // filter(Boolean), + // ); return definition.manifest.abi.methods.reduce( (acc, func) => @@ -471,10 +390,10 @@ export const createSmartContract = ({ }), { client, - iterEvents, - iterLogs, - iterActions, - convertAction, + // iterEvents, + // iterLogs, + // iterActions, + // convertAction, definition, }, ); diff --git a/packages/neo-one-client-core/src/sc/params.ts b/packages/neo-one-client-core/src/sc/params.ts index fa522c9f1a..874c234e4f 100644 --- a/packages/neo-one-client-core/src/sc/params.ts +++ b/packages/neo-one-client-core/src/sc/params.ts @@ -27,6 +27,10 @@ export const params = { Any: (_name: string, _param: Param, _parameter: AnyABI): ScriptBuilderParam | undefined => undefined, String: (name: string, param: Param, parameter: StringABI): ScriptBuilderParam | undefined => parameter.optional && param === undefined ? undefined : args.assertString(name, param), + Address: (name: string, param: Param, parameter: Hash160ABI): ScriptBuilderParam | undefined => + parameter.optional && param === undefined + ? undefined + : common.stringToUInt160(addressToScriptHash(args.assertAddress(name, param))), Hash160: (name: string, param: Param, parameter: Hash160ABI): ScriptBuilderParam | undefined => parameter.optional && param === undefined ? undefined diff --git a/packages/neo-one-client-core/src/types.ts b/packages/neo-one-client-core/src/types.ts index 7afdd1760e..bedc66a3ea 100644 --- a/packages/neo-one-client-core/src/types.ts +++ b/packages/neo-one-client-core/src/types.ts @@ -19,25 +19,25 @@ export interface SmartContract AsyncIterable; + // readonly iterEvents: (options?: SmartContractIterOptions) => AsyncIterable; /** * Iterate over the logs emitted by the smart contract. * * @returns an `AsyncIterable` over the logs emitted by the smart contract. */ - readonly iterLogs: (options?: SmartContractIterOptions) => AsyncIterable; + // readonly iterLogs: (options?: SmartContractIterOptions) => AsyncIterable; /** * Iterate over the events and logs emitted by the smart contract. * * @returns an `AsyncIterable` over the events and logs emitted by the smart contract. */ - readonly iterActions: (options?: SmartContractIterOptions) => AsyncIterable; + // readonly iterActions: (options?: SmartContractIterOptions) => AsyncIterable; /** * Converts a `RawAction`, typically from the raw results found in a `Block` to a processed `Action` or `undefined` if the action is not recognized by the ABI. * * @returns `Action` if the `action` parameter is recognized by the `ABI` of the smart contract, `undefined` otherwise. */ - readonly convertAction: (action: RawAction) => TEvent | Log | undefined; + // readonly convertAction: (action: RawAction) => TEvent | Log | undefined; } export interface SmartContractAny extends SmartContract { diff --git a/packages/neo-one-client-core/src/user/DapiUserAccountProvider.ts b/packages/neo-one-client-core/src/user/DapiUserAccountProvider.ts index e1a7d0a287..c01e374f55 100644 --- a/packages/neo-one-client-core/src/user/DapiUserAccountProvider.ts +++ b/packages/neo-one-client-core/src/user/DapiUserAccountProvider.ts @@ -29,7 +29,6 @@ import { TxHashAttribute, } from './Dapi'; import { - ExecuteInvokeClaimOptions, ExecuteInvokeMethodOptions, ExecuteInvokeScriptOptions, Provider, @@ -220,10 +219,6 @@ export class DapiUserAccountProvider throw new NotImplementedError('executeInvokeScript'); } - protected async executeInvokeClaim(_options: ExecuteInvokeClaimOptions): Promise { - throw new NotImplementedError('executeInvokeClaim'); - } - protected async executeInvokeMethod({ invokeMethodOptions, from, @@ -250,7 +245,7 @@ export class DapiUserAccountProvider confirmed: async () => { const [receipt, data] = await Promise.all([ this.provider.getTransactionReceipt(from.network, txid), - this.provider.getInvocationData(from.network, txid), + this.provider.getApplicationLogData(from.network, txid), ]); return onConfirm({ transaction, receipt, data }); @@ -300,7 +295,7 @@ export class DapiUserAccountProvider readonly address: AddressString; readonly label?: string; }) { - const userAccount = { + const userAccount: UserAccount = { id: { address, network, diff --git a/packages/neo-one-client-core/src/user/LocalUserAccountProvider.ts b/packages/neo-one-client-core/src/user/LocalUserAccountProvider.ts index 92cebe99b1..8854e6603c 100644 --- a/packages/neo-one-client-core/src/user/LocalUserAccountProvider.ts +++ b/packages/neo-one-client-core/src/user/LocalUserAccountProvider.ts @@ -1,22 +1,18 @@ import { - AddressString, - addressToScriptHash, Attribute, common, crypto, ECDsaVerifyPrice, getOpCodePrice, GetOptions, - InvalidFormatError, IOHelper, NetworkType, Op, - Param, RelayTransactionResult, ScriptBuilder, - ScriptBuilderParam, SignerModel, SourceMaps, + toVerifyResultJSON, Transaction, TransactionModel, TransactionReceipt, @@ -258,10 +254,14 @@ export class LocalUserAccountProvider({ + protected async sendTransaction({ transaction: transactionUnsigned, from, onConfirm, + // tslint:disable-next-line: no-unused + networkFee, + // tslint:disable-next-line: no-unused + sourceMaps, }: { readonly transaction: TransactionModel; readonly from: UserAccountID; @@ -271,7 +271,7 @@ export class LocalUserAccountProvider Promise; readonly networkFee?: BigNumber; readonly sourceMaps?: SourceMaps; - }): Promise> { + }): Promise> { return this.capture( async () => { const signature = await this.keystore.sign({ @@ -281,63 +281,41 @@ export class LocalUserAccountProvider failureMessage !== undefined); - // if (failures.length > 0) { - // const message = await processActionsAndMessage({ - // actions: failures.reduce((acc, { actions }) => acc.concat(actions), []), - // message: failures - // .map(({ failureMessage }) => failureMessage) - // .filter(commonUtils.notNull) - // .join(' '), - // sourceMaps, - // }); - - // throw new InvokeError(message); - // } + const result = await this.provider.relayTransaction( + from.network, + // TODO: addWitness possibly needs to be fixed/reverted + this.addWitness({ + transaction: transactionUnsigned, + witness, + }), + ); if (result.verifyResult !== undefined && result.verifyResult !== VerifyResultModel.Succeed) { - throw new InvokeError(`Transaction failed to verify with result: ${VerifyResultModel[result.verifyResult]}`); + throw new InvokeError( + `Transaction failed to verify with result: ${toVerifyResultJSON(result.verifyResult)}.`, + ); } const { transaction } = result; return { - transaction: transaction as TTransaction, + transaction, // tslint:disable-next-line no-unnecessary-type-annotation confirmed: async (optionsIn: GetOptions = {}): Promise => { const options = { @@ -356,72 +334,15 @@ export class LocalUserAccountProvider; - readonly paramsZipped: ReadonlyArray; - readonly from: UserAccountID; - readonly sourceMaps?: SourceMaps; - readonly networkFee?: BigNumber; - }): Promise { - const script = new ScriptBuilder() - // TODO: check that this is correct script for claiming gas? - .emitAppCall(common.nativeHashes.GAS, 'transfer', [ - addressToScriptHash(contract), // check this is correct address - common.nativeHashes.GAS, - unclaimedAmount.toString(), - ]) - .build(); - - const [{ gas }, { count, messageMagic }] = await Promise.all([ - this.getSystemFee({ from, script, attributes }), - this.getCountAndMagic(from), - ]); - - const transaction = new TransactionModel({ - systemFee: utils.bigNumberToBN(gas, 8), - networkFee: utils.bigNumberToBN(networkFee ? networkFee : new BigNumber(0), 8), // TODO: check. should it be optional param or no? - // Since the contract address is an input, we must add a witness for it. - witnesses: this.getInvokeScripts(method, params, true), - script, - attributes: this.convertAttributes(attributes), - validUntilBlock: count + 240, - messageMagic, - }); - - return this.sendTransaction({ - from, - transaction, - onConfirm: async ({ receipt }) => receipt, - sourceMaps, - }); - } - protected async executeTransfer( transfers: readonly Transfer[], from: UserAccountID, attributes: readonly Attribute[], maxNetworkFee: BigNumber, maxSystemFee: BigNumber, - validBlockCount: number = TransactionModel.maxValidBlockIncrement, + validBlockCount: number, ): Promise { const sb = new ScriptBuilder(); - if (transfers.length > 1) { - throw new Error('temporary'); - } const { addressVersion, blockCount, messageMagic } = await this.provider.getNetworkSettings(from.network); @@ -483,7 +404,7 @@ export class LocalUserAccountProvider({ + return this.sendTransaction({ from, transaction, onConfirm: async ({ receipt }) => receipt, @@ -506,36 +427,74 @@ export class LocalUserAccountProvider({ script, from, attributes, - systemFee, - networkFee, + maxSystemFee, + maxNetworkFee, + validBlockCount, witnesses, onConfirm, sourceMaps, }: ExecuteInvokeScriptOptions): Promise> { - const { count, messageMagic } = await this.getCountAndMagic(from); - const invokeTransaction = new TransactionModel({ - systemFee: utils.bigNumberToBN(systemFee, 8), // TODO: check - networkFee: utils.bigNumberToBN(networkFee ? networkFee : new BigNumber(0), 8), // TODO: check. should it be optional param or no? + const { blockCount, messageMagic, addressVersion } = await this.provider.getNetworkSettings(from.network); + + const signer = new SignerModel({ + account: crypto.addressToScriptHash({ address: from.address, addressVersion }), + scopes: WitnessScopeModel.Global, + }); + + const nonce = utils.randomUShort(); + const validUntilBlock = blockCount + validBlockCount; + + const feelessTransaction = new TransactionModel({ + version: 0, + nonce, + script, + validUntilBlock, + signers: [signer], + witnesses, attributes: this.convertAttributes(attributes), + systemFee: utils.bigNumberToBN(utils.ZERO_BIG_NUMBER, 8), + networkFee: utils.bigNumberToBN(utils.ZERO_BIG_NUMBER, 8), + messageMagic, + }); + + const [systemFee, networkFee] = await Promise.all([ + this.getSystemFee({ + network: from.network, + transaction: feelessTransaction, + maxFee: maxSystemFee, + }), + this.getNetworkFee({ + network: from.network, + transaction: feelessTransaction, + maxFee: maxNetworkFee, + }), + ]); + + const transaction = new TransactionModel({ + version: 0, + nonce, script, + validUntilBlock, + signers: [signer], witnesses, - validUntilBlock: count + 240, + attributes: this.convertAttributes(attributes), + systemFee: utils.bigNumberToBN(systemFee, 0), + networkFee: utils.bigNumberToBN(networkFee, 0), messageMagic, }); try { - return this.sendTransaction({ + return this.sendTransaction({ from, - transaction: invokeTransaction, - onConfirm: async ({ transaction, receipt }) => { - const data = await this.provider.getApplicationLogData(from.network, transaction.hash); + transaction, + onConfirm: async ({ transaction: transactionIn, receipt }) => { + const data = await this.provider.getApplicationLogData(from.network, transactionIn.hash); - return onConfirm({ transaction, receipt, data }); + return onConfirm({ transaction: transactionIn, receipt, data }); }, sourceMaps, }); diff --git a/packages/neo-one-client-core/src/user/RemoteUserAccountProvider.ts b/packages/neo-one-client-core/src/user/RemoteUserAccountProvider.ts index 650b1c1236..0e622b6240 100644 --- a/packages/neo-one-client-core/src/user/RemoteUserAccountProvider.ts +++ b/packages/neo-one-client-core/src/user/RemoteUserAccountProvider.ts @@ -209,13 +209,12 @@ export class RemoteUserAccountProvider implements UserAccountProvider { method: string, params: ReadonlyArray, paramsZipped: ReadonlyArray, - verify: boolean, options?: InvokeSendUnsafeReceiveTransactionOptions, sourceMaps?: SourceMaps, ): Promise> { return this.handleMethodWithConfirmation({ method: 'invoke', - args: [contract, method, params, paramsZipped, verify, options, sourceMaps], + args: [contract, method, params, paramsZipped, options, sourceMaps], }); } diff --git a/packages/neo-one-client-core/src/user/UserAccountProviderBase.ts b/packages/neo-one-client-core/src/user/UserAccountProviderBase.ts index b0279b5b6c..e38c70567f 100644 --- a/packages/neo-one-client-core/src/user/UserAccountProviderBase.ts +++ b/packages/neo-one-client-core/src/user/UserAccountProviderBase.ts @@ -5,7 +5,7 @@ import { Attribute, AttributeModel, Block, - common, + Contract, ForwardValue, GetOptions, Hash256String, @@ -17,7 +17,6 @@ import { ParamJSON, RawApplicationLogData, RawCallReceipt, - RawInvocationData, RawInvokeReceipt, ScriptBuilderParam, SourceMaps, @@ -34,24 +33,19 @@ import { Witness, WitnessModel, } from '@neo-one/client-common'; +import { processConsoleLogMessages } from '@neo-one/client-switch'; import { Labels, utils as commonUtils } from '@neo-one/utils'; import BigNumber from 'bignumber.js'; import debug from 'debug'; import { Observable } from 'rxjs'; import { clientUtils } from '../clientUtils'; -import { - InsufficientSystemFeeError, - InvokeError, - NoAccountError, - NothingToClaimError, - NotImplementedError, -} from '../errors'; +import { InsufficientSystemFeeError, InvokeError, NoAccountError, NotImplementedError } from '../errors'; import { converters } from './converters'; const logger = debug('NEOONE:LocalUserAccountProvider'); export interface InvokeMethodOptions { - readonly contract: AddressString; + readonly scriptHash: UInt160Hex; readonly params: ReadonlyArray; readonly invokeMethod: string; } @@ -61,31 +55,28 @@ export interface InvokeRawOptions { readonly transfers?: readonly FullTransfer[]; readonly options?: TransactionOptions; readonly verify?: boolean; - // TODO: fix onConfirm type. return type from node is no longer valid readonly onConfirm: (options: { readonly transaction: Transaction; - readonly data: RawInvocationData; + readonly data: RawApplicationLogData; readonly receipt: TransactionReceipt; }) => Promise | T; readonly method: string; readonly witnesses?: readonly WitnessModel[]; readonly labels?: Record; readonly sourceMaps?: SourceMaps; - readonly networkFee?: BigNumber; } export interface ExecuteInvokeScriptOptions { readonly script: Buffer; readonly from: UserAccountID; readonly attributes: readonly Attribute[]; - readonly systemFee: BigNumber; // TODO: is this name change appropriate (from "gas" to "systemFee")? - readonly networkFee?: BigNumber; // TODO: is this addition appropriate? + readonly maxSystemFee: BigNumber; + readonly maxNetworkFee: BigNumber; + readonly validBlockCount: number; readonly witnesses: readonly WitnessModel[]; - readonly verify: boolean; - // TODO: fix onConfirm type. return type from node is no longer valid readonly onConfirm: (options: { readonly transaction: Transaction; - readonly data: RawInvocationData; + readonly data: RawApplicationLogData; readonly receipt: TransactionReceipt; }) => Promise | T; readonly sourceMaps?: SourceMaps; @@ -95,17 +86,6 @@ export interface ExecuteInvokeMethodOptions extend readonly invokeMethodOptions: InvokeMethodOptions; } -export interface ExecuteInvokeClaimOptions { - readonly contract: AddressString; - readonly unclaimedAmount: BigNumber; - readonly attributes: readonly Attribute[]; - readonly method: string; - readonly params: ReadonlyArray; - readonly paramsZipped: ReadonlyArray; - readonly from: UserAccountID; - readonly sourceMaps?: SourceMaps; -} - export interface Provider { readonly networks$: Observable; readonly getNetworks: () => readonly NetworkType[]; @@ -131,6 +111,7 @@ export interface Provider { readonly getTransaction: (network: NetworkType, hash: Hash256String) => Promise; readonly iterBlocks: (network: NetworkType, options?: IterOptions) => AsyncIterable; readonly getAccount: (network: NetworkType, address: AddressString) => Promise; + readonly getContract: (network: NetworkType, address: AddressString) => Promise; readonly getVerificationCost: ( network: NetworkType, hash: UInt160Hex, @@ -232,7 +213,7 @@ export abstract class UserAccountProviderBase { return this.invokeRaw({ invokeMethodOptionsOrScript: { - contract, + scriptHash: addressToScriptHash(contract), invokeMethod: method, params, }, @@ -254,7 +235,7 @@ export abstract class UserAccountProviderBase { ), ), }, - onConfirm: ({ receipt, data }): RawInvokeReceipt => ({ + onConfirm: ({ receipt, data, transaction }): RawInvokeReceipt => ({ blockIndex: receipt.blockIndex, blockHash: receipt.blockHash, blockTime: receipt.blockTime, @@ -262,9 +243,14 @@ export abstract class UserAccountProviderBase { transactionHash: receipt.transactionHash, globalIndex: receipt.globalIndex, confirmations: receipt.confirmations, - result: data.result, - actions: data.actions, + state: data.vmState, + stack: typeof data.stack === 'string' ? [] : data.stack, // TODO: fix + gasConsumed: data.gasConsumed, + script: Buffer.from(transaction.script, 'hex'), + logs: data.logs, + notifications: data.notifications, }), + // TODO: what to do here? Related to attaching transfers to method invocation witnesses: this.getInvokeScripts( method, params, @@ -278,191 +264,6 @@ export abstract class UserAccountProviderBase { }); } - // TODO? - public async invokeSend( - contract: AddressString, - method: string, - paramsIn: ReadonlyArray, - paramsZipped: ReadonlyArray, - transfer: Transfer, - options: TransactionOptions = {}, - sourceMaps: SourceMaps = {}, - ): Promise> { - const transactionOptions = this.getTransactionOptions(options); - const { from, attributes } = transactionOptions; - - const contractID: UserAccountID = { - address: contract, - network: from.network, - }; - - const params = paramsIn.concat([common.stringToUInt160(addressToScriptHash(transfer.to))]); - - return this.invokeRaw({ - invokeMethodOptionsOrScript: { - contract, - invokeMethod: method, - params, - }, - options: { - ...transactionOptions, - attributes: attributes.concat(this.getInvokeAttributes(contract, method, paramsZipped, false, from.address)), - }, - // TODO: fix onConfirm - onConfirm: ({ receipt, data }): RawInvokeReceipt => ({ - blockIndex: receipt.blockIndex, - blockHash: receipt.blockHash, - blockTime: receipt.blockTime, - transactionIndex: receipt.transactionIndex, - transactionHash: receipt.transactionHash, - globalIndex: receipt.globalIndex, - confirmations: receipt.confirmations, - result: data.result, - actions: data.actions, - }), - witnesses: this.getInvokeScripts(method, params, true), - transfers: [ - { - ...transfer, - to: contract, - from: contractID, - }, - ], - method: 'invokeSend', - labels: { - [Labels.INVOKE_METHOD]: method, - }, - sourceMaps, - }); - } - - // TODO: finalize after compiler (need to open issue) - public async invokeCompleteSend( - contract: AddressString, - method: string, - params: ReadonlyArray, - paramsZipped: ReadonlyArray, - hash: Hash256String, - options: TransactionOptions = {}, - sourceMaps: SourceMaps = {}, - ): Promise> { - const transactionOptions = this.getTransactionOptions(options); - const { from, attributes } = transactionOptions; - - const sendTransaction = await this.provider.getTransaction(from.network, hash); - - return this.invokeRaw({ - invokeMethodOptionsOrScript: { - contract, - invokeMethod: method, - params, - }, - options: { - ...transactionOptions, - attributes: attributes.concat(this.getInvokeAttributes(contract, method, paramsZipped, false, from.address)), - }, - // TODO: fix onConfirm - onConfirm: ({ receipt, data }): RawInvokeReceipt => ({ - blockIndex: receipt.blockIndex, - blockHash: receipt.blockHash, - blockTime: receipt.blockTime, - transactionIndex: receipt.transactionIndex, - transactionHash: receipt.transactionHash, - globalIndex: receipt.globalIndex, - confirmations: receipt.confirmations, - result: data.result, - actions: data.actions, - }), - witnesses: this.getInvokeScripts(method, params, true), - method: 'invokeCompleteSend', - labels: { - [Labels.INVOKE_METHOD]: method, - }, - sourceMaps, - }); - } - - // TODO: finalize after compiler (need to open issue) - public async invokeRefundAssets( - contract: AddressString, - method: string, - params: ReadonlyArray, - paramsZipped: ReadonlyArray, - hash: Hash256String, - options: TransactionOptions = {}, - sourceMaps: SourceMaps = {}, - ): Promise> { - const transactionOptions = this.getTransactionOptions(options); - const { from, attributes } = transactionOptions; - - const refundTransaction = await this.provider.getTransaction(from.network, hash); - - return this.invokeRaw({ - invokeMethodOptionsOrScript: { - contract, - invokeMethod: method, - params, - }, - options: { - ...transactionOptions, - attributes: attributes.concat(this.getInvokeAttributes(contract, method, paramsZipped, false, from.address)), - }, - // TODO: fix onConfirm - onConfirm: ({ receipt, data }): RawInvokeReceipt => ({ - blockIndex: receipt.blockIndex, - blockHash: receipt.blockHash, - blockTime: receipt.blockTime, - transactionIndex: receipt.transactionIndex, - transactionHash: receipt.transactionHash, - globalIndex: receipt.globalIndex, - confirmations: receipt.confirmations, - result: data.result, - actions: data.actions, - }), - witnesses: this.getInvokeScripts(method, params, true), - method: 'invokeRefundAssets', - labels: { - [Labels.INVOKE_METHOD]: method, - }, - sourceMaps, - }); - } - - public async invokeClaim( - contract: AddressString, - method: string, - params: ReadonlyArray, - paramsZipped: ReadonlyArray, - options: TransactionOptions = {}, - sourceMaps: SourceMaps = {}, - ): Promise { - const { from, attributes } = this.getTransactionOptions(options); - - return this.capture( - async () => { - const unclaimedAmount = await this.provider.getUnclaimed(from.network, contract); - - if (unclaimedAmount.lte(new BigNumber(0))) { - throw new NothingToClaimError(from); - } - - return this.executeInvokeClaim({ - contract, - unclaimedAmount, - attributes, - from, - method, - params, - paramsZipped, - sourceMaps, - }); - }, - { - name: 'neo_invoke_claim', - }, - ); - } - public async call( network: NetworkType, contract: AddressString, @@ -482,6 +283,9 @@ export abstract class UserAccountProviderBase { readonly maxFee: BigNumber; }): Promise { const callReceipt = await this.provider.testTransaction(network, transaction); + + await processConsoleLogMessages({ actions: [...callReceipt.logs, ...callReceipt.notifications] }); + if (callReceipt.state === 'FAULT') { throw new InvokeError(callReceipt.state); } @@ -557,7 +361,6 @@ export abstract class UserAccountProviderBase { readonly transaction: TransactionModel; readonly witness: WitnessModel; }): TransactionModel { - // TODO: what kind of sorting needs to be done with the existing witnesses? return transaction.clone({ witnesses: [witness] }); } @@ -641,8 +444,6 @@ export abstract class UserAccountProviderBase { options: ExecuteInvokeScriptOptions, ): Promise>; - protected abstract async executeInvokeClaim(options: ExecuteInvokeClaimOptions): Promise; - protected abstract async executeTransfer( transfers: readonly Transfer[], from: UserAccountID, @@ -665,37 +466,27 @@ export abstract class UserAccountProviderBase { options = {}, onConfirm, method, - verify = true, witnesses = [], labels = {}, sourceMaps, - networkFee, + transfers = [], }: InvokeRawOptions) { - const { from, attributes: attributesIn } = this.getTransactionOptions(options); + const { from, attributes, maxSystemFee, maxNetworkFee, validBlockCount } = this.getTransactionOptions(options); + + // TODO: need to pass transfers into here to they are include in the script. must be in front of the actual method call? + // Or are they included as "witnesses" which used to be called scripts? const { script, invokeMethodOptions } = this.getScriptAndInvokeMethodOptions(invokeMethodOptionsOrScript); return this.capture( - async () => { - const { gas: systemFee, attributes } = await this.getSystemFee({ - script, - network: from.network, - attributes: attributesIn, - witnesses, - }); - - // TODO: do we need to use networkFee.plus(gas)? - // where does network fee come in? Note that Spencer just added "networkFee" in here. see how it was used before - // Need to finalize executeInvoke method in LUAP first to know what needs to be passed in here - // and ultimately what needs to be passed into invokeRaw - - return invokeMethodOptions === undefined + async () => + invokeMethodOptions === undefined ? this.executeInvokeScript({ script, from, attributes, - systemFee, - networkFee, - verify, + maxSystemFee, + maxNetworkFee, + validBlockCount, witnesses, onConfirm, sourceMaps, @@ -705,14 +496,13 @@ export abstract class UserAccountProviderBase { invokeMethodOptions, from, attributes, - systemFee, - networkFee, - verify, + maxSystemFee, + maxNetworkFee, + validBlockCount, witnesses, onConfirm, sourceMaps, - }); - }, + }), { name: 'neo_invoke_raw', invoke: true, @@ -733,9 +523,9 @@ export abstract class UserAccountProviderBase { script = invokeMethodOptionsOrScript; } else { invokeMethodOptions = invokeMethodOptionsOrScript; - const { contract, invokeMethod, params } = invokeMethodOptions; + const { scriptHash, invokeMethod, params } = invokeMethodOptions; script = clientUtils.getInvokeMethodScript({ - address: contract, + scriptHash, method: invokeMethod, params, }); diff --git a/packages/neo-one-client-full-common/src/models/manifest/ContractManifestModel.ts b/packages/neo-one-client-full-common/src/models/manifest/ContractManifestModel.ts index ce1ca62f5d..a02225f1a5 100644 --- a/packages/neo-one-client-full-common/src/models/manifest/ContractManifestModel.ts +++ b/packages/neo-one-client-full-common/src/models/manifest/ContractManifestModel.ts @@ -82,6 +82,7 @@ export class ContractManifestModel< } public serializeWireBase(writer: BinaryWriter): void { - writer.writeVarString(JSON.stringify(this.serializeJSON())); + // TODO: fix this. or bring up with Neo team + writer.writeVarStringWithoutVar(JSON.stringify(this.serializeJSON())); } } diff --git a/packages/neo-one-client-full-common/src/models/manifest/ContractPermissionDescriptorModel.ts b/packages/neo-one-client-full-common/src/models/manifest/ContractPermissionDescriptorModel.ts index 386a5919a6..6ba77d22ff 100644 --- a/packages/neo-one-client-full-common/src/models/manifest/ContractPermissionDescriptorModel.ts +++ b/packages/neo-one-client-full-common/src/models/manifest/ContractPermissionDescriptorModel.ts @@ -32,12 +32,19 @@ export class ContractPermissionDescriptorModel implements SerializableJSON { +export const contractRegisterToContractModel = (contractIn: ContractRegister): ContractStateModel => { const abi = new ContractABIModel({ - hash: contractIn.manifest.abi.hash, + hash: common.stringToUInt160(contractIn.manifest.abi.hash), methods: contractIn.manifest.abi.methods.map( (methodIn) => new ContractMethodDescriptorModel({ @@ -106,7 +108,7 @@ const contractRegisterToContractModel = (contractIn: ContractRegister): Contract name: param.name, }), ), - safe: methodIn.safe, + safe: methodIn.safe ?? false, }), ), events: contractIn.manifest.abi.events.map( @@ -119,26 +121,55 @@ const contractRegisterToContractModel = (contractIn: ContractRegister): Contract }), ), }); + const getPermission = ({ hash, group }: ContractPermissionDescriptor): UInt160 | ECPoint | Wildcard => { + if (hash !== undefined && group !== undefined) { + throw new Error('Hash and group should not both be defined.'); + } + + if (hash !== undefined) { + if (!common.isUInt160(hash)) { + throw new Error('Invalid UInt160'); + } + + return common.stringToUInt160(hash); + } + + if (group !== undefined) { + if (!common.isECPoint(group)) { + throw new Error('Invalid ECPoint'); + } + + return common.stringToECPoint(group); + } + + return '*'; + }; const manifest = new ContractManifestModel({ groups: contractIn.manifest.groups.map( - (group) => new ContractGroupModel({ publicKey: group.publicKey, signature: Buffer.from(group.signature, 'hex') }), + (group) => + new ContractGroupModel({ + publicKey: common.stringToECPoint(group.publicKey), + signature: Buffer.from(group.signature, 'hex'), + }), ), supportedStandards: contractIn.manifest.supportedStandards, abi, permissions: contractIn.manifest.permissions.map( (perm) => new ContractPermissionModel({ - contract: new ContractPermissionDescriptorModel(perm.contract), + contract: new ContractPermissionDescriptorModel({ hashOrGroup: getPermission(perm.contract) }), methods: perm.methods, }), ), - trusts: contractIn.manifest.trusts, + trusts: contractIn.manifest.trusts === '*' ? '*' : contractIn.manifest.trusts.map(common.stringToUInt160), extra: contractIn.manifest.extra, }); return new ContractStateModel({ + hash: '', + updateCounter: 1, script: Buffer.from(contractIn.script, 'hex'), - id: contractIn.id, + id: Math.floor(Math.random() * 1000000), // TODO: fix manifest, }); }; @@ -209,9 +240,10 @@ export class LocalUserAccountProvider> { const { from } = this.getTransactionOptions(options); + const bufferScript = Buffer.from(script, 'hex'); return this.invokeRaw({ - invokeMethodOptionsOrScript: Buffer.from(script, 'hex'), + invokeMethodOptionsOrScript: bufferScript, options, transfers: options.transfers === undefined ? [] : options.transfers.map((transfer) => ({ ...transfer, from })), onConfirm: ({ receipt, data }): RawInvokeReceipt => ({ @@ -222,8 +254,12 @@ export class LocalUserAccountProvider => { let result; - if (data.result.state === 'FAULT') { - result = await this.getInvocationResultError(data, data.result, sourceMaps); + // tslint:disable-next-line: prefer-switch + if (data.vmState === 'FAULT') { + result = await this.getInvocationResultError(data, sourceMaps); + } else if (data.vmState === 'NONE' || data.vmState === 'BREAK') { + throw new Error(`Something went wrong. Expected VM state HALT or FAULT. Got: ${data.vmState}`); } else { - const createdContract = data.contracts[0] as Contract | undefined; - if (createdContract === undefined) { - /* istanbul ignore next */ - throw new InvalidTransactionError( - 'Something went wrong! Expected a contract to have been created, but none was found', - ); - } + const address = scriptHashToAddress( + common.uInt160ToString(crypto.toScriptHash(Buffer.from(contractIn.script, 'hex'))), + ); + const contractOut = await this.provider.getContract(from.network, address); - result = await this.getInvocationResultSuccess(data, data.result, createdContract, sourceMaps); + result = await this.getInvocationResultSuccess(data, contractOut, sourceMaps); } return { @@ -280,41 +318,46 @@ export class LocalUserAccountProvider { + ): Promise { const message = await processActionsAndMessage({ - actions: data.actions, - message: result.message, + actions: [...data.logs, ...data.notifications], sourceMaps, }); + // TODO: fix vm states + // tslint:disable-next-line: prefer-switch + if (data.vmState === 'HALT' || data.vmState === 'BREAK' || data.vmState === 'NONE') { + throw new Error(`Expected FAULT state. Got: ${data.vmState}`); + } + return { - state: result.state, - gasConsumed: result.gasConsumed, - gasCost: result.gasCost, - script: result.script, + state: data.vmState, + gasConsumed: data.gasConsumed, message, }; } protected async getInvocationResultSuccess( - data: RawInvocationData, - result: RawTransactionResultSuccess, + data: RawApplicationLogData, value: T, sourceMaps: SourceMaps = {}, - ): Promise> { + ): Promise> { await processConsoleLogMessages({ - actions: data.actions, + actions: [...data.logs, ...data.notifications], sourceMaps, }); + // TODO: fix vm states + // tslint:disable-next-line: prefer-switch + if (data.vmState === 'FAULT' || data.vmState === 'BREAK' || data.vmState === 'NONE') { + throw new Error(`Expected HALT state. Got: ${data.vmState}`); + } + return { - state: result.state, - gasConsumed: result.gasConsumed, - gasCost: result.gasCost, - script: result.script, + state: data.vmState, + gasConsumed: data.gasConsumed, value, }; } diff --git a/packages/neo-one-client-full/src/index.ts b/packages/neo-one-client-full/src/index.ts index e55e0e778b..8bc0e0fad1 100644 --- a/packages/neo-one-client-full/src/index.ts +++ b/packages/neo-one-client-full/src/index.ts @@ -1,71 +1,98 @@ export { - ABI, + Account, ABIDefault, ABIDefaultType, - ABIEvent, - ABIFunction, ABIParameter, + ABIParameterBase, ABIReturn, - Account, + ABIReturnBase, Action, - AddressAttributeUsage, - AddressContractParameter, AddressString, + AnyABI, + AnyABIParameter, + AnyABIReturn, + AnyContractParameter, + AnyContractParameterDefinition, + SignatureContractParameterDefinition, + BooleanContractParameterDefinition, + IntegerContractParameterDefinition, + Hash160ContractParameterDefinition, + Hash256ContractParameterDefinition, + BufferContractParameterDefinition, + PublicKeyContractParameterDefinition, + StringContractParameterDefinition, + ArrayContractParameterDefinition, + MapContractParameterDefinition, + InteropInterfaceContractParameterDefinition, + VoidContractParameterDefinition, + ContractParameterDefinitionType, + ArrayABI, + ArrayABIParameter, + ArrayABIReturn, ArrayContractParameter, - Asset, - AssetType, Attribute, + AttributeBase, Block, + BlockFilter, + BooleanABI, BooleanABIParameter, BooleanABIReturn, BooleanContractParameter, + BufferABI, BufferABIParameter, BufferABIReturn, - BufferAttributeUsage, BufferContractParameter, BufferString, - ClaimTransaction, - ConfirmedClaimTransaction, - ConfirmedContractTransaction, - ConfirmedEnrollmentTransaction, - ConfirmedInvocationTransaction, - ConfirmedIssueTransaction, - ConfirmedMinerTransaction, - ConfirmedPublishTransaction, - ConfirmedRegisterTransaction, - ConfirmedStateTransaction, ConfirmedTransaction, - ConfirmedTransactionBase, + ConsensusData, Contract, + ContractABI, + ContractABIClient, + ContractEventDescriptor, + ContractEventDescriptorClient, + ContractFeatures, + ContractGroup, + ContractManifest, + ContractManifestClient, + ContractMethodDescriptor, + ContractMethodDescriptorClient, ContractParameter, + ContractParameterDefinition, + ContractParameterDefinitionBase, ContractParameterType, - ContractTransaction, + ContractPermission, + ContractPermissionDescriptor, + DeveloperProvider, DeveloperClient, - DeveloperTools, - EnrollmentTransaction, + // DeveloperTools, // TODO: add back Event, + EventParameters, + ForwardOptions, ForwardValue, ForwardValueABI, ForwardValueABIParameter, ForwardValueABIReturn, GetOptions, - Hash256, - Hash256AttributeUsage, + Hash160ABI, + Hash160ABIParameter, + Hash160ABIReturn, + Hash160ContractParameter, + Hash256ABI, + Hash256ABIParameter, + Hash256ABIReturn, Hash256ContractParameter, Hash256String, Header, - Input, + HighPriorityAttribute, + IntegerABI, + IntegerABIParameter, + IntegerABIReturn, IntegerContractParameter, InteropInterfaceContractParameter, InvocationResult, - InvocationResultError, - InvocationResultSuccess, - InvocationTransaction, InvokeReceipt, - InvokeReceiveTransactionOptions, - InvokeSendUnsafeReceiveTransactionOptions, - InvokeSendUnsafeTransactionOptions, - IssueTransaction, + IterOptions, + JSONRPCErrorResponse, JSONRPCProvider, JSONRPCRequest, JSONRPCResponse, @@ -74,54 +101,90 @@ export { LocalStringStore, LocalWallet, Log, - MinerTransaction, + MapABI, + MapABIParameter, + MapABIReturn, + MapContractParameter, + NetworkSettings, + NetworkType, NEOONEDataProvider, - NEODataProvider, NEOONEDataProviderOptions, - NEODataProviderOptions, NEOONEProvider, - NEOProvider, - NetworkType, - Output, + ObjectABI, + ObjectABIParameter, + ObjectABIReturn, Param, Peer, + PrivateKeyString, PrivateNetworkSettings, - PublicKeyAttributeUsage, + PublicKeyABI, + PublicKeyABIParameter, + PublicKeyABIReturn, PublicKeyContractParameter, PublicKeyString, - PublishTransaction, RawAction, RawActionBase, + RawApplicationLogData, + RawCallReceipt, RawInvocationData, RawInvocationResult, - RawInvocationResultError, - RawInvocationResultSuccess, + RawTransactionResultBase, + RawTransactionResultError, + RawTransactionResultSuccess, + RawStackItem, + RawAnyStackItem, + RawPointerStackItem, + RawPrimitiveStackItem, + RawBufferStackItem, + RawArrayStackItem, + RawMapStackItem, + RawInvokeReceipt, RawLog, RawNotification, - RegisterTransaction, + RelayTransactionResult, Return, + ScriptBuilderParam, SenderAddressABIDefault, + Signer, + SignatureABI, + SignatureABIParameter, + SignatureABIReturn, SignatureContractParameter, + SignatureString, SmartContract, SmartContractAny, SmartContractDefinition, + SmartContractIterOptions, SmartContractNetworkDefinition, SmartContractNetworksDefinition, + SmartContractReadOptions, SourceMaps, - StateTransaction, + StorageItem, + StringABI, + StringABIParameter, + StringABIReturn, StringContractParameter, Transaction, - TransactionBase, TransactionOptions, TransactionReceipt, TransactionResult, + TransactionResultSuccess, + TransactionResultError, Transfer, + UpdateAccountNameOptions, UnlockedWallet, UserAccount, UserAccountID, UserAccountProvider, + UserAccountProviders, + VerifyScriptResult, + VerifyTransactionResult, + VoidABI, + VoidABIParameter, + VoidABIReturn, VoidContractParameter, Witness, + WitnessScope, addressToScriptHash, createPrivateKey, decryptNEP2, @@ -136,15 +199,15 @@ export { publicKeyToScriptHash, scriptHashToAddress, wifToPrivateKey, + Wildcard, + WildcardContainer, } from '@neo-one/client'; export { - AssetRegister, Client, ContractRegister, InvokeExecuteTransactionOptions, LocalUserAccountProvider, PublishReceipt, - RegisterAssetReceipt, ReadClient, } from '@neo-one/client-full-core'; diff --git a/packages/neo-one-client-switch/src/common/createConsoleLogMessages.ts b/packages/neo-one-client-switch/src/common/createConsoleLogMessages.ts index 61f471890e..4639e7d908 100644 --- a/packages/neo-one-client-switch/src/common/createConsoleLogMessages.ts +++ b/packages/neo-one-client-switch/src/common/createConsoleLogMessages.ts @@ -1,5 +1,5 @@ -import { RawAction, smartContractConverters as converters } from '@neo-one/client-common'; -// import { BinaryReader, deserializeStackItem, StackItem } from '@neo-one/node-core'; +import { common, RawAction, scriptHashToAddress, smartContractConverters as converters } from '@neo-one/client-common'; +import { assertArrayLikeStackItem, BinaryReader, deserializeStackItem, StackItem } from '@neo-one/node-core'; import { utils } from '@neo-one/utils'; import _ from 'lodash'; import { SourceMaps } from '../common'; @@ -54,9 +54,11 @@ const inspect = (value: any, wrapString = false): any => { return wrapString ? JSON.stringify(value) : value; }; +const getArray = (stackItem: StackItem): readonly StackItem[] => assertArrayLikeStackItem(stackItem).array; + // tslint:disable-next-line no-any const extractValueFromStackItem = (stackItem: StackItem): any => { - const type = stackItem.getArray()[0].getInteger().toNumber(); + const type = getArray(stackItem)[0].getInteger().toNumber(); switch (type) { case 1: @@ -65,35 +67,32 @@ const extractValueFromStackItem = (stackItem: StackItem): any => { // tslint:disable-next-line no-null-keyword return null; case 3: - return stackItem.getArray()[1].getBoolean(); + return getArray(stackItem)[1].getBoolean(); case 4: - return stackItem.getArray()[1].getString(); + return getArray(stackItem)[1].getString(); case 5: - return `Symbol(${stackItem.getArray()[1].getString()})`; + return `Symbol(${getArray(stackItem)[1].getString()})`; case 6: - return stackItem.getArray()[1].getInteger().toString(10); + return getArray(stackItem)[1].getInteger().toString(10); case 7: return _.fromPairs( utils.zip( - stackItem.getArray()[1].getArray()[0].getArray().map(extractValueFromStackItem), - stackItem.getArray()[1].getArray()[1].getArray().map(extractValueFromStackItem), + getArray(getArray(getArray(stackItem)[1])[0]).map(extractValueFromStackItem), + getArray(getArray(getArray(stackItem)[1])[1]).map(extractValueFromStackItem), ), ); case 8: - return stackItem.getArray()[1].getArray().map(extractValueFromStackItem); + return getArray(getArray(stackItem)[1]).map(extractValueFromStackItem); case 9: - return stackItem.getArray()[1].getBuffer().toString('hex'); + return getArray(stackItem)[1].getBuffer().toString('hex'); case 10: // tslint:disable-next-line no-any return new Map( - stackItem - .getArray()[1] - .getArray() - // tslint:disable-next-line no-any - .map((value: any) => value.getArray().map(extractValueFromStackItem)), + // tslint:disable-next-line no-any + getArray(getArray(stackItem)[1]).map((value: any) => getArray(value).map(extractValueFromStackItem)), ); case 11: - return new Set(stackItem.getArray()[1].getArray().map(extractValueFromStackItem)); + return new Set(getArray(getArray(stackItem)[1]).map(extractValueFromStackItem)); default: return ``; } @@ -106,7 +105,7 @@ const extractMessageFromStackItem = (stackItem: StackItem): string => { }; const extractMessage = (value: Buffer): string => { - const stackItems = deserializeStackItem(new BinaryReader(value), 16, 34).getArray()[1].getArray(); + const stackItems = getArray(getArray(deserializeStackItem(new BinaryReader(value), 16, 34))[1]); const messages = stackItems.map(extractMessageFromStackItem); @@ -118,17 +117,21 @@ const extractLog = (action: RawAction): ConsoleLog | undefined => { return undefined; } - const args = action.args; + const address = scriptHashToAddress(common.uInt160ToString(action.scriptHash)); + const args = action.state; try { - const event = converters.toString(args[0]); + const event = action.eventName; if (event !== 'console.log') { return undefined; } + if (typeof args === 'string') { + return { address, line: -1, message: args }; + } const line = converters.toInteger(args[1], { type: 'Integer', decimals: 0 }).toNumber(); const message = extractMessage(Buffer.from(converters.toBuffer(args[2]), 'hex')); - return { address: action.address, line, message }; + return { address, line, message }; } catch { return undefined; } @@ -136,6 +139,11 @@ const extractLog = (action: RawAction): ConsoleLog | undefined => { const extractConsoleLogs = (actions: readonly RawAction[]): readonly ConsoleLog[] => { const mutableLogs: ConsoleLog[] = []; + // TODO: this should be removed when we're more confident in our types + // tslint:disable-next-line: strict-type-predicates + if (actions === undefined) { + return mutableLogs; + } // tslint:disable-next-line no-loop-statement for (const action of actions) { const log = extractLog(action); diff --git a/packages/neo-one-client-switch/src/common/extractErrorTrace.ts b/packages/neo-one-client-switch/src/common/extractErrorTrace.ts index 9d55a739fd..f064769db6 100644 --- a/packages/neo-one-client-switch/src/common/extractErrorTrace.ts +++ b/packages/neo-one-client-switch/src/common/extractErrorTrace.ts @@ -1,4 +1,4 @@ -import { RawAction, smartContractConverters as converters } from '@neo-one/client-common'; +import { common, RawAction, scriptHashToAddress, smartContractConverters as converters } from '@neo-one/client-common'; import _ from 'lodash'; import { ProcessErrorError, ProcessErrorTrace } from './processError'; @@ -7,15 +7,21 @@ const extractError = (action: RawAction): ProcessErrorError | undefined => { return undefined; } - const args = action.args; + const address = scriptHashToAddress(common.uInt160ToString(action.scriptHash)); + const args = action.state; + + if (typeof args === 'string') { + return { address, line: -1, message: args }; + } + try { - const event = converters.toString(args[0]); + const event = action.eventName; if (event !== 'error') { return undefined; } return { - address: action.address, + address, line: converters.toInteger(args[2], { type: 'Integer', decimals: 0 }).toNumber(), message: converters.toString(args[1]), }; @@ -29,7 +35,13 @@ const extractTrace = (action: RawAction): ProcessErrorTrace | undefined => { return undefined; } - const args = action.args; + const address = scriptHashToAddress(common.uInt160ToString(action.scriptHash)); + const args = action.state; + + if (typeof args === 'string') { + return { address, line: -1 }; + } + try { const event = converters.toString(args[0]); if (event !== 'trace') { @@ -37,7 +49,7 @@ const extractTrace = (action: RawAction): ProcessErrorTrace | undefined => { } return { - address: action.address, + address, line: converters.toInteger(args[1], { type: 'Integer', decimals: 0 }).toNumber(), }; } catch { diff --git a/packages/neo-one-client-switch/src/common/processActionsAndMessage.ts b/packages/neo-one-client-switch/src/common/processActionsAndMessage.ts index fbe91c1a9a..85c46582e3 100644 --- a/packages/neo-one-client-switch/src/common/processActionsAndMessage.ts +++ b/packages/neo-one-client-switch/src/common/processActionsAndMessage.ts @@ -10,7 +10,7 @@ export interface SourceMaps { export interface ProcessActionsAndMessageOptions { readonly actions: readonly RawAction[]; - readonly message: string; + readonly message?: string; readonly sourceMaps?: SourceMaps; } @@ -22,8 +22,8 @@ export const processActionsAndMessage = async ({ const [message] = await Promise.all([ processError({ ...extractErrorTrace(actions), - message: messageIn, sourceMaps, + message: messageIn ?? 'Something went wrong', }), processConsoleLogMessages({ actions, sourceMaps }), ]); diff --git a/packages/neo-one-client/src/index.ts b/packages/neo-one-client/src/index.ts index 9912593ea8..37fbbb5f3f 100644 --- a/packages/neo-one-client/src/index.ts +++ b/packages/neo-one-client/src/index.ts @@ -1,4 +1,5 @@ export { + Account, ABIDefault, ABIDefaultType, ABIParameter, @@ -6,15 +7,25 @@ export { ABIReturn, ABIReturnBase, Action, - AddressABI, - AddressABIParameter, - AddressABIReturn, - AddressContractParameter, AddressString, AnyABI, AnyABIParameter, AnyABIReturn, AnyContractParameter, + AnyContractParameterDefinition, + SignatureContractParameterDefinition, + BooleanContractParameterDefinition, + IntegerContractParameterDefinition, + Hash160ContractParameterDefinition, + Hash256ContractParameterDefinition, + BufferContractParameterDefinition, + PublicKeyContractParameterDefinition, + StringContractParameterDefinition, + ArrayContractParameterDefinition, + MapContractParameterDefinition, + InteropInterfaceContractParameterDefinition, + VoidContractParameterDefinition, + ContractParameterDefinitionType, ArrayABI, ArrayABIParameter, ArrayABIReturn, @@ -46,6 +57,7 @@ export { ContractMethodDescriptorClient, ContractParameter, ContractParameterDefinition, + ContractParameterDefinitionBase, ContractParameterType, ContractPermission, ContractPermissionDescriptor, @@ -75,12 +87,7 @@ export { IntegerContractParameter, InteropInterfaceContractParameter, InvocationResult, - InvocationResultError, - InvocationResultSuccess, InvokeReceipt, - InvokeReceiveTransactionOptions, - InvokeSendUnsafeReceiveTransactionOptions, - InvokeSendUnsafeTransactionOptions, IterOptions, JSONRPCErrorResponse, Log, @@ -104,12 +111,20 @@ export { PublicKeyString, RawAction, RawActionBase, + RawApplicationLogData, RawCallReceipt, RawInvocationData, RawInvocationResult, RawTransactionResultBase, RawTransactionResultError, RawTransactionResultSuccess, + RawStackItem, + RawAnyStackItem, + RawPointerStackItem, + RawPrimitiveStackItem, + RawBufferStackItem, + RawArrayStackItem, + RawMapStackItem, RawInvokeReceipt, RawLog, RawNotification, @@ -172,7 +187,6 @@ export { } from '@neo-one/client-common'; export { - addLocalKeysSync, Client, connectRemoteUserAccountProvider, Dapi, @@ -201,4 +215,4 @@ export { nep17, } from '@neo-one/client-core'; -// export { DeveloperTools } from '@neo-one/developer-tools'; +// export { DeveloperTools } from '@neo-one/developer-tools'; // TODO: add back diff --git a/packages/neo-one-node-blockchain/src/Blockchain.ts b/packages/neo-one-node-blockchain/src/Blockchain.ts index 2545f01232..618051c115 100644 --- a/packages/neo-one-node-blockchain/src/Blockchain.ts +++ b/packages/neo-one-node-blockchain/src/Blockchain.ts @@ -27,6 +27,7 @@ import { Nep17Balance, Notification, RunEngineOptions, + SerializeJSONContext, Signers, Storage, Transaction, @@ -204,12 +205,7 @@ export class Blockchain { validatorsCount: this.settings.validatorsCount, }; this.mutableCurrentBlock = options.currentBlock; - this.onPersist = - options.onPersist === undefined - ? () => { - this.vm.updateSnapshots(); - } - : options.onPersist; + this.onPersist = options.onPersist === undefined ? () => this.vm.updateSnapshots() : options.onPersist; this.start(); } @@ -296,7 +292,7 @@ export class Blockchain { // return this.storage.consensusState; // } - public get serializeJSONContext() { + public get serializeJSONContext(): SerializeJSONContext { return { addressVersion: this.settings.addressVersion, messageMagic: this.settings.messageMagic, diff --git a/packages/neo-one-node-core/src/ApplicationLog.ts b/packages/neo-one-node-core/src/ApplicationLog.ts index 898a4aaab1..4e68211903 100644 --- a/packages/neo-one-node-core/src/ApplicationLog.ts +++ b/packages/neo-one-node-core/src/ApplicationLog.ts @@ -72,6 +72,7 @@ export class ApplicationLog implements SerializableWire { gasconsumed: this.gasConsumed.toString(), stack, notifications: this.notifications.map((n) => n.serializeJSON()), + logs: [], // TODO: implement this }; } diff --git a/packages/neo-one-node-core/src/Node.ts b/packages/neo-one-node-core/src/Node.ts index 672c38c557..ec0a9ddfa1 100644 --- a/packages/neo-one-node-core/src/Node.ts +++ b/packages/neo-one-node-core/src/Node.ts @@ -1,7 +1,6 @@ import { VerifyResultModel } from '@neo-one/client-common'; import { Block } from './Block'; import { Blockchain } from './Blockchain'; -import { ContractParametersContext } from './ContractParametersContext'; import { Endpoint } from './network'; import { ConsensusPayload } from './payload'; import { Transaction } from './transaction'; diff --git a/packages/neo-one-node-core/src/Notification.ts b/packages/neo-one-node-core/src/Notification.ts index 503c3a0f45..812ea18906 100644 --- a/packages/neo-one-node-core/src/Notification.ts +++ b/packages/neo-one-node-core/src/Notification.ts @@ -1,12 +1,13 @@ import { common, NotificationJSON, UInt160 } from '@neo-one/client-common'; -import { assertArrayStackItem, StackItem, stackItemToJSON } from './StackItems'; +import { ContractParameter } from './contractParameter'; +import { assertArrayStackItem, StackItem } from './StackItems'; import { Verifiable } from './Verifiable'; export interface NotificationAdd { readonly container?: Verifiable; readonly scriptHash: UInt160; readonly eventName: string; - readonly state: readonly StackItem[]; + readonly state: readonly ContractParameter[]; } export class Notification { @@ -14,7 +15,7 @@ export class Notification { const array = assertArrayStackItem(stackItem).array; const scriptHash = common.bufferToUInt160(array[0].getBuffer()); const eventName = array[1].getString(); - const state = assertArrayStackItem(array[2]).array; + const state = assertArrayStackItem(array[2]).array.map((stackItemIn) => stackItemIn.toContractParameter()); return new Notification({ container, @@ -27,7 +28,7 @@ export class Notification { public readonly container?: Verifiable; public readonly scriptHash: UInt160; public readonly eventName: string; - public readonly state: readonly StackItem[]; + public readonly state: readonly ContractParameter[]; public constructor({ container, scriptHash, eventName, state }: NotificationAdd) { this.container = container; @@ -39,7 +40,7 @@ export class Notification { public serializeJSON(): NotificationJSON { let state; try { - state = this.state.map((s) => stackItemToJSON(s, undefined)); + state = this.state.map((s) => s.serializeJSON()); } catch { state = 'error: recursive reference'; } diff --git a/packages/neo-one-node-core/src/Serializable.ts b/packages/neo-one-node-core/src/Serializable.ts index a95fe78cd0..725ac5757e 100644 --- a/packages/neo-one-node-core/src/Serializable.ts +++ b/packages/neo-one-node-core/src/Serializable.ts @@ -91,6 +91,7 @@ export function createDeserializeWire(deserializeWireBase: DeserializeWireBas // TODO: what did all of these `TransactionData` helpers do? How should we re implement? export interface SerializeJSONContext { readonly addressVersion: number; + readonly messageMagic: number; } export type SerializeJSON = (context: SerializeJSONContext) => TJSON | Promise; diff --git a/packages/neo-one-node-core/src/StackItems/ArrayStackItem.ts b/packages/neo-one-node-core/src/StackItems/ArrayStackItem.ts index a1696ee9c3..3ec5879417 100644 --- a/packages/neo-one-node-core/src/StackItems/ArrayStackItem.ts +++ b/packages/neo-one-node-core/src/StackItems/ArrayStackItem.ts @@ -1,6 +1,8 @@ +import { StackItemType } from '@neo-one/client-common'; +import { ArrayContractParameter, ContractParameter } from '../contractParameter'; +import { CircularReferenceError } from './errors'; import { StackItemAdd, StackItemBase } from './StackItemBase'; import { StackItem } from './StackItems'; -import { StackItemType } from './StackItemType'; export interface ArrayStackItemAdd extends StackItemAdd { readonly array: readonly StackItem[]; @@ -25,4 +27,14 @@ export class ArrayStackItem extends StackItemBase { public getBoolean() { return true; } + + public toContractParameter(seen: Set = new Set()): ContractParameter { + if (seen.has(this)) { + throw new CircularReferenceError(); + } + const newSeen = new Set([...seen]); + newSeen.add(this); + + return new ArrayContractParameter(this.array.map((val) => val.toContractParameter(newSeen))); + } } diff --git a/packages/neo-one-node-core/src/StackItems/BooleanStackItem.ts b/packages/neo-one-node-core/src/StackItems/BooleanStackItem.ts index f97922bb96..c3f559232e 100644 --- a/packages/neo-one-node-core/src/StackItems/BooleanStackItem.ts +++ b/packages/neo-one-node-core/src/StackItems/BooleanStackItem.ts @@ -1,7 +1,9 @@ +import { StackItemType } from '@neo-one/client-common'; import { BN } from 'bn.js'; +import { BooleanContractParameter, ContractParameter } from '../contractParameter'; import { PrimitiveStackItemBase } from './PrimitiveStackItemBase'; +import { StackItemBase } from './StackItemBase'; import { isBooleanStackItem, StackItem } from './StackItems'; -import { StackItemType } from './StackItemType'; export class BooleanStackItem extends PrimitiveStackItemBase { private static readonly TRUE = Buffer.from([0x01]); @@ -33,4 +35,8 @@ export class BooleanStackItem extends PrimitiveStackItemBase { public getInteger() { return this.value ? new BN(1) : new BN(0); } + + public toContractParameter(_seen: Set = new Set()): ContractParameter { + return new BooleanContractParameter(this.value); + } } diff --git a/packages/neo-one-node-core/src/StackItems/BufferStackItem.ts b/packages/neo-one-node-core/src/StackItems/BufferStackItem.ts index 01d18b8eeb..55d363abc3 100644 --- a/packages/neo-one-node-core/src/StackItems/BufferStackItem.ts +++ b/packages/neo-one-node-core/src/StackItems/BufferStackItem.ts @@ -1,5 +1,6 @@ +import { StackItemType } from '@neo-one/client-common'; +import { ByteArrayContractParameter, ContractParameter } from '../contractParameter'; import { StackItemBase } from './StackItemBase'; -import { StackItemType } from './StackItemType'; export class BufferStackItem extends StackItemBase { public readonly innerBuffer: Buffer; @@ -21,4 +22,8 @@ export class BufferStackItem extends StackItemBase { public getBuffer() { return this.innerBuffer; } + + public toContractParameter(_seen: Set = new Set()): ContractParameter { + return new ByteArrayContractParameter(this.innerBuffer); + } } diff --git a/packages/neo-one-node-core/src/StackItems/ByteStringStackItem.ts b/packages/neo-one-node-core/src/StackItems/ByteStringStackItem.ts index 4379327737..cbe5890e91 100644 --- a/packages/neo-one-node-core/src/StackItems/ByteStringStackItem.ts +++ b/packages/neo-one-node-core/src/StackItems/ByteStringStackItem.ts @@ -1,9 +1,11 @@ +import { StackItemType } from '@neo-one/client-common'; import { BN } from 'bn.js'; +import { ByteArrayContractParameter, ContractParameter } from '../contractParameter'; import { InvalidIntegerStackItemError } from '../errors'; import { IntegerStackItem } from './IntegerStackItem'; import { PrimitiveStackItemBase } from './PrimitiveStackItemBase'; +import { StackItemBase } from './StackItemBase'; import { isByteStringStackItem, StackItem } from './StackItems'; -import { StackItemType } from './StackItemType'; export class ByteStringStackItem extends PrimitiveStackItemBase { public static readonly empty = new ByteStringStackItem(Buffer.from([])); @@ -40,4 +42,8 @@ export class ByteStringStackItem extends PrimitiveStackItemBase { return new BN(this.getBuffer(), 'le'); } + + public toContractParameter(_seen: Set = new Set()): ContractParameter { + return new ByteArrayContractParameter(this.memory); + } } diff --git a/packages/neo-one-node-core/src/StackItems/IntegerStackItem.ts b/packages/neo-one-node-core/src/StackItems/IntegerStackItem.ts index e84701cb0f..2125ea1409 100644 --- a/packages/neo-one-node-core/src/StackItems/IntegerStackItem.ts +++ b/packages/neo-one-node-core/src/StackItems/IntegerStackItem.ts @@ -1,8 +1,10 @@ +import { StackItemType } from '@neo-one/client-common'; import { BN } from 'bn.js'; +import { ContractParameter, IntegerContractParameter } from '../contractParameter'; import { InvalidIntegerStackItemError } from '../errors'; import { PrimitiveStackItemBase } from './PrimitiveStackItemBase'; +import { StackItemBase } from './StackItemBase'; import { isIntegerStackItem, StackItem } from './StackItems'; -import { StackItemType } from './StackItemType'; export class IntegerStackItem extends PrimitiveStackItemBase { public static readonly Zero = new IntegerStackItem(new BN(0)); @@ -41,4 +43,8 @@ export class IntegerStackItem extends PrimitiveStackItemBase { public getInteger() { return this.value; } + + public toContractParameter(_seen: Set = new Set()): ContractParameter { + return new IntegerContractParameter(this.value); + } } diff --git a/packages/neo-one-node-core/src/StackItems/InteropInterface.ts b/packages/neo-one-node-core/src/StackItems/InteropInterface.ts index efd33e4f9a..4207882de5 100644 --- a/packages/neo-one-node-core/src/StackItems/InteropInterface.ts +++ b/packages/neo-one-node-core/src/StackItems/InteropInterface.ts @@ -1,6 +1,6 @@ +import { StackItemType } from '@neo-one/client-common'; import { InvalidInteropInterfaceValueError, InvalidStackItemCastError } from '../errors'; import { StackItemBase } from './StackItemBase'; -import { StackItemType } from './StackItemType'; // tslint:disable: no-any export class InteropInterface extends StackItemBase { diff --git a/packages/neo-one-node-core/src/StackItems/MapStackItem.ts b/packages/neo-one-node-core/src/StackItems/MapStackItem.ts index 9ef8082e1c..5a7d491731 100644 --- a/packages/neo-one-node-core/src/StackItems/MapStackItem.ts +++ b/packages/neo-one-node-core/src/StackItems/MapStackItem.ts @@ -1,6 +1,8 @@ +import { StackItemType } from '@neo-one/client-common'; +import { ContractParameter, MapContractParameter } from '../contractParameter'; +import { CircularReferenceError } from './errors'; import { StackItemBase } from './StackItemBase'; import { PrimitiveStackItem, StackItem } from './StackItems'; -import { StackItemType } from './StackItemType'; export class MapStackItem extends StackItemBase { public static readonly maxKeySize = 64; @@ -35,4 +37,19 @@ export class MapStackItem extends StackItemBase { public getBoolean() { return true; } + + public toContractParameter(seen: Set = new Set()): ContractParameter { + if (seen.has(this)) { + throw new CircularReferenceError(); + } + const newSeen = new Set([...seen]); + newSeen.add(this); + + return new MapContractParameter( + [...this.dictionary.keys()].map((key) => [ + key.toContractParameter(newSeen), + (this.dictionary.get(key) as StackItem).toContractParameter(newSeen), + ]), + ); + } } diff --git a/packages/neo-one-node-core/src/StackItems/NullStackItem.ts b/packages/neo-one-node-core/src/StackItems/NullStackItem.ts index 5a5a66d459..0f49c01b5e 100644 --- a/packages/neo-one-node-core/src/StackItems/NullStackItem.ts +++ b/packages/neo-one-node-core/src/StackItems/NullStackItem.ts @@ -1,7 +1,8 @@ +import { isStackItemType, StackItemType } from '@neo-one/client-common'; +import { AnyContractParameter, ContractParameter } from '../contractParameter'; import { InvalidStackItemCastError } from '../errors'; import { StackItemBase } from './StackItemBase'; import { StackItem } from './StackItems'; -import { isStackItemType, StackItemType } from './StackItemType'; export class NullStackItem extends StackItemBase { public constructor() { @@ -34,4 +35,8 @@ export class NullStackItem extends StackItemBase { public getString() { return ''; } + + public toContractParameter(_seen: Set = new Set()): ContractParameter { + return new AnyContractParameter(); + } } diff --git a/packages/neo-one-node-core/src/StackItems/PointerStackItem.ts b/packages/neo-one-node-core/src/StackItems/PointerStackItem.ts index b3d5748d09..a32cb1332e 100644 --- a/packages/neo-one-node-core/src/StackItems/PointerStackItem.ts +++ b/packages/neo-one-node-core/src/StackItems/PointerStackItem.ts @@ -1,6 +1,13 @@ +import { StackItemType } from '@neo-one/client-common'; +import { BN } from 'bn.js'; +import { + ArrayContractParameter, + ByteArrayContractParameter, + ContractParameter, + IntegerContractParameter, +} from '../contractParameter'; import { StackItemBase } from './StackItemBase'; import { isPointerStackItem, StackItem } from './StackItems'; -import { StackItemType } from './StackItemType'; // TODO: can decide if we need to implement this later; export type PointerStackItemScript = Buffer; @@ -38,4 +45,11 @@ export class PointerStackItem extends StackItemBase { public getBoolean() { return true; } + + public toContractParameter(_seen: Set = new Set()): ContractParameter { + return new ArrayContractParameter([ + new ByteArrayContractParameter(this.script), + new IntegerContractParameter(new BN(this.position)), + ]); + } } diff --git a/packages/neo-one-node-core/src/StackItems/StackItemBase.ts b/packages/neo-one-node-core/src/StackItems/StackItemBase.ts index 6fc884be4e..31a2cac530 100644 --- a/packages/neo-one-node-core/src/StackItems/StackItemBase.ts +++ b/packages/neo-one-node-core/src/StackItems/StackItemBase.ts @@ -1,5 +1,6 @@ +import { StackItemType } from '@neo-one/client-common'; import { BN } from 'bn.js'; -import { StackItemType } from './StackItemType'; +import { ContractParameter } from '../contractParameter'; export interface StackItemAdd { readonly isNull: boolean; @@ -35,4 +36,9 @@ export abstract class StackItemBase { public getString(): string { return this.getBuffer().toString('utf-8'); } + + public toContractParameter(): ContractParameter { + /* istanbul ignore next */ + throw new Error('method not implemented'); + } } diff --git a/packages/neo-one-node-core/src/StackItems/StackItemType.ts b/packages/neo-one-node-core/src/StackItems/StackItemType.ts index 766b569e9c..7c77c287b3 100644 --- a/packages/neo-one-node-core/src/StackItems/StackItemType.ts +++ b/packages/neo-one-node-core/src/StackItems/StackItemType.ts @@ -21,5 +21,21 @@ export const assertStackItemType = (value: number): StackItemType => { return value; } - throw new InvalidFormatError(`expected StackItemType, found: ${value}`); + throw new InvalidFormatError(`Expected StackItemType, found: ${value}`); }; + +export type StackItemTypeJSON = keyof typeof StackItemType; + +export const isStackItemTypeJSON = (type: string): type is StackItemTypeJSON => + // tslint:disable-next-line: strict-type-predicates no-any + StackItemType[type as any] !== undefined; + +export const assertStackItemTypeJSON = (type: string): StackItemTypeJSON => { + if (isStackItemTypeJSON(type)) { + return type; + } + + throw new InvalidFormatError(); +}; + +export const toStackItemTypeJSON = (type: StackItemType) => assertStackItemTypeJSON(StackItemType[type]); diff --git a/packages/neo-one-node-core/src/StackItems/StackItems.ts b/packages/neo-one-node-core/src/StackItems/StackItems.ts index 982e81e1aa..acbde50de5 100644 --- a/packages/neo-one-node-core/src/StackItems/StackItems.ts +++ b/packages/neo-one-node-core/src/StackItems/StackItems.ts @@ -1,4 +1,11 @@ -import { InvalidFormatError, JSONHelper, PrimitiveStackItemJSON, StackItemJSON } from '@neo-one/client-common'; +import { + InvalidFormatError, + isStackItemType, + JSONHelper, + PrimitiveStackItemJSON, + StackItemJSON, + StackItemType, +} from '@neo-one/client-common'; import { InvalidPrimitiveStackItemError, InvalidStackItemError, InvalidStackItemTypeError } from '../errors'; import { ArrayStackItem } from './ArrayStackItem'; import { BooleanStackItem } from './BooleanStackItem'; @@ -9,7 +16,6 @@ import { InteropInterface } from './InteropInterface'; import { MapStackItem } from './MapStackItem'; import { NullStackItem } from './NullStackItem'; import { PointerStackItem } from './PointerStackItem'; -import { isStackItemType, StackItemType } from './StackItemType'; import { StructStackItem } from './StructStackItem'; export type PrimitiveStackItem = BooleanStackItem | IntegerStackItem | ByteStringStackItem; @@ -132,6 +138,7 @@ export const assertPrimitiveStackItem = (item: any): PrimitiveStackItem => { throw new InvalidPrimitiveStackItemError(); }; +// TODO: this can/should probably be deleted so it can't be confused with ContractParameter/ContractParameterJSON export const stackItemToJSON = (item: StackItem, context?: Set): StackItemJSON => { switch (item.type) { case StackItemType.Array: diff --git a/packages/neo-one-node-core/src/StackItems/StructStackItem.ts b/packages/neo-one-node-core/src/StackItems/StructStackItem.ts index 68cc1c55f9..3ee477ae4e 100644 --- a/packages/neo-one-node-core/src/StackItems/StructStackItem.ts +++ b/packages/neo-one-node-core/src/StackItems/StructStackItem.ts @@ -1,6 +1,8 @@ +import { StackItemType } from '@neo-one/client-common'; +import { ArrayContractParameter, ContractParameter } from '../contractParameter'; +import { CircularReferenceError } from './errors'; import { StackItemBase } from './StackItemBase'; import { StackItem } from './StackItems'; -import { StackItemType } from './StackItemType'; export class StructStackItem extends StackItemBase { public readonly array: readonly StackItem[]; @@ -17,4 +19,14 @@ export class StructStackItem extends StackItemBase { public getBoolean() { return true; } + + public toContractParameter(seen: Set = new Set()): ContractParameter { + if (seen.has(this)) { + throw new CircularReferenceError(); + } + const newSeen = new Set([...seen]); + newSeen.add(this); + + return new ArrayContractParameter(this.array.map((val) => val.toContractParameter(newSeen))); + } } diff --git a/packages/neo-one-node-core/src/StackItems/errors.ts b/packages/neo-one-node-core/src/StackItems/errors.ts new file mode 100644 index 0000000000..041995bae6 --- /dev/null +++ b/packages/neo-one-node-core/src/StackItems/errors.ts @@ -0,0 +1,89 @@ +import { makeErrorWithCode } from '@neo-one/utils'; + +export const InvalidValueArrayError = makeErrorWithCode('INVALID_VALUE_ARRAY', () => 'Invalid Value. Expected Array'); +export const CircularReferenceError = makeErrorWithCode('CIRCULAR_REFERENCE_ERROR', () => 'Circular Reference Error'); +export const InvalidValueBufferError = makeErrorWithCode( + 'INVALID_VALUE_BUFFER', + () => 'Invalid Value. Expected Buffer', +); +export const InvalidValueEnumeratorError = makeErrorWithCode( + 'INVALID_VALUE_ENUMERATOR', + () => 'Invalid Value. Expected Enumerator', +); +export const InvalidValueHeaderError = makeErrorWithCode( + 'INVALID_VALUE_HEADER', + () => 'Invalid Value. Expected Header', +); +export const InvalidValueBlockError = makeErrorWithCode('INVALID_VALUE_BLOCK', () => 'Invalid Value. Expected Block'); +export const InvalidValueBlockBaseError = makeErrorWithCode( + 'INVALID_VALUE_BLOCK_BASE', + () => 'Invalid Value. Expected BlockBase', +); +export const InvalidValueTransactionError = makeErrorWithCode( + 'INVALID_VALUE_TRANSACTION', + () => 'Invalid Value. Expected Transaction', +); +export const InvalidValueWitnessError = makeErrorWithCode( + 'INVALID_VALUE_WITNESS', + () => 'Invalid Value. Expected Witness', +); +export const InvalidValueAttributeError = makeErrorWithCode( + 'INVALID_VALUE_ATTRIBUTE', + () => 'Invalid Value. Expected Attribute', +); +export const InvalidValueAttributeStackItemError = makeErrorWithCode( + 'INVALID_VALUE_ATTRIBUTE_STACK_ITEM', + () => 'Invalid Value. Expected AttributeStackItem', +); +export const InvalidValueInputError = makeErrorWithCode('INVALID_VALUE_INPUT', () => 'Invalid Value. Expected Input'); +export const InvalidValueMapStackItemError = makeErrorWithCode( + 'INVALID_VALUE_MAP_STACK_ITEM', + () => 'Invalid Value. Expected MapStackItem', +); +export const InvalidValueOutputError = makeErrorWithCode( + 'INVALID_VALUE_OUTPUT', + () => 'Invalid Value. Expected Output', +); +export const InvalidValueAccountError = makeErrorWithCode( + 'INVALID_VALUE_ACCOUNT', + () => 'Invalid Value. Expected Account', +); +export const InvalidValueAssetError = makeErrorWithCode('INVALID_VALUE_ASSET', () => 'Invalid Value. Expected Asset'); +export const InvalidValueContractError = makeErrorWithCode( + 'INVALID_VALUE_CONTRACT', + () => 'Invalid Value. Expected Contract', +); +export const InvalidValueValidatorError = makeErrorWithCode( + 'INVALID_VALUE_VALIDATOR', + () => 'Invalid Value. Expected Validator', +); +export const InvalidValueIteratorError = makeErrorWithCode( + 'INVALID_VALUE_ITERATOR', + () => 'Invalid Value. Expected Iterator', +); +export const InvalidValueStorageContextStackItemError = makeErrorWithCode( + 'INVALID_VALUE_STORAGE_CONTEXT_STACK_ITEM', + /* istanbul ignore next */ + () => 'Invalid Value. Expected StorageContextStackItem', +); +export const UnsupportedStackItemSerdeError = makeErrorWithCode( + 'UNSUPPORTED_STACK_ITEM_SERDE', + () => 'Unsupported StackItem serde.', +); +export const InvalidStorageStackItemEnumeratorError = makeErrorWithCode( + 'INVALID_STORAGE_STACK_ITEM_ENUMERATOR', + () => 'Current is not set. The enumerator has been fully consumed or has not been initialized', +); +export const InvalidStorageStackItemIteratorError = makeErrorWithCode( + 'INVALID_STORAGE_STACK_ITEM_ITERATOR', + () => 'Current is not set. The iterator has been fully consumed or has not been initialized', +); +export const MissingStackItemKeyError = makeErrorWithCode('MISSING_STACK_ITEM_KEY', () => 'Map does not contain key.'); +export const InvalidRecursiveSerializeError = makeErrorWithCode( + 'INVALID_RECURSIVE_SERIALIZE', + () => 'Attempted to serialize a recursive structure.', +); +export const IntegerTooLargeError = makeErrorWithCode( + 'INTEGER_TOO_LARGE', + () => 'Integer too large. Max size is 256 bits.', +); diff --git a/packages/neo-one-node-core/src/StackItems/index.ts b/packages/neo-one-node-core/src/StackItems/index.ts index 71c6ed6755..dadea74953 100644 --- a/packages/neo-one-node-core/src/StackItems/index.ts +++ b/packages/neo-one-node-core/src/StackItems/index.ts @@ -1,4 +1,3 @@ -export * from './StackItemType'; export * from './ArrayStackItem'; export * from './BooleanStackItem'; export * from './BufferStackItem'; @@ -8,7 +7,6 @@ export * from './InteropInterface'; export * from './MapStackItem'; export * from './NullStackItem'; export * from './PointerStackItem'; -export * from './StackItems'; -export * from './StackItems'; -export * from './StackItemType'; export * from './StructStackItem'; +export * from './StackItems'; +export * from './errors'; diff --git a/packages/neo-one-node-core/src/TransactionVerificationContext.ts b/packages/neo-one-node-core/src/TransactionVerificationContext.ts index 1cdbc9fc1a..f68df32aa1 100644 --- a/packages/neo-one-node-core/src/TransactionVerificationContext.ts +++ b/packages/neo-one-node-core/src/TransactionVerificationContext.ts @@ -5,7 +5,7 @@ import { isOracleResponse, Transaction } from './transaction'; const assertSender = (sender: UInt160 | undefined) => { if (sender === undefined) { - // TODO: implement error; + // TODO: implement error throw new Error(`Sender must be defined`); } @@ -61,7 +61,7 @@ export class TransactionVerificationContext { const key = common.uInt160ToHex(sender); const maybeFee = this.mutableSenderFee[key]; if (maybeFee === undefined) { - // TODO: implement error; + // TODO: implement error throw new Error('transaction not present in verification context to remove'); } diff --git a/packages/neo-one-node-core/src/__tests__/disassembleByteCode.test.ts b/packages/neo-one-node-core/src/__tests__/disassembleByteCode.test.ts new file mode 100644 index 0000000000..7cb6876878 --- /dev/null +++ b/packages/neo-one-node-core/src/__tests__/disassembleByteCode.test.ts @@ -0,0 +1,384 @@ +import { OpCode, ScriptBuilder, StackItemType } from '@neo-one/client-common'; +import { BN } from 'bn.js'; +import { disassembleByteCode } from '../disassembleByteCode'; + +const noOpOps: ReadonlyArray = [ + 'PUSHNULL', + 'PUSHM1', + 'PUSH0', + 'PUSH1', + 'PUSH2', + 'PUSH3', + 'PUSH4', + 'PUSH5', + 'PUSH6', + 'PUSH7', + 'PUSH8', + 'PUSH9', + 'PUSH10', + 'PUSH11', + 'PUSH12', + 'PUSH13', + 'PUSH14', + 'PUSH15', + 'PUSH16', + 'NOP', + 'CALLA', + 'ABORT', + 'ASSERT', + 'THROW', + 'ENDFINALLY', + 'RET', + 'DEPTH', + 'DROP', + 'NIP', + 'XDROP', + 'CLEAR', + 'DUP', + 'OVER', + 'PICK', + 'TUCK', + 'SWAP', + 'ROT', + 'ROLL', + 'REVERSE3', + 'REVERSE4', + 'REVERSEN', + 'LDSFLD0', + 'LDSFLD1', + 'LDSFLD2', + 'LDSFLD3', + 'LDSFLD4', + 'LDSFLD5', + 'LDSFLD6', + 'STSFLD0', + 'STSFLD1', + 'STSFLD2', + 'STSFLD3', + 'STSFLD4', + 'STSFLD5', + 'STSFLD6', + 'LDLOC0', + 'LDLOC1', + 'LDLOC2', + 'LDLOC3', + 'LDLOC4', + 'LDLOC5', + 'LDLOC6', + 'STLOC0', + 'STLOC1', + 'STLOC2', + 'STLOC3', + 'STLOC4', + 'STLOC5', + 'STLOC6', + 'LDARG0', + 'LDARG1', + 'LDARG2', + 'LDARG3', + 'LDARG4', + 'LDARG5', + 'LDARG6', + 'STARG0', + 'STARG1', + 'STARG2', + 'STARG3', + 'STARG4', + 'STARG5', + 'STARG6', + 'NEWBUFFER', + 'MEMCPY', + 'CAT', + 'SUBSTR', + 'LEFT', + 'RIGHT', + 'INVERT', + 'AND', + 'OR', + 'XOR', + 'EQUAL', + 'NOTEQUAL', + 'SIGN', + 'ABS', + 'NEGATE', + 'INC', + 'DEC', + 'ADD', + 'SUB', + 'MUL', + 'DIV', + 'MOD', + 'SHL', + 'SHR', + 'NOT', + 'BOOLAND', + 'BOOLOR', + 'NZ', + 'NUMEQUAL', + 'NUMNOTEQUAL', + 'LT', + 'LE', + 'GT', + 'GE', + 'MIN', + 'MAX', + 'WITHIN', + 'PACK', + 'UNPACK', + 'NEWARRAY0', + 'NEWARRAY', + 'NEWSTRUCT0', + 'NEWSTRUCT', + 'NEWMAP', + 'SIZE', + 'HASKEY', + 'KEYS', + 'VALUES', + 'PICKITEM', + 'APPEND', + 'SETITEM', + 'REVERSEITEMS', + 'REMOVE', + 'CLEARITEMS', + 'ISNULL', +]; + +// tslint:disable-next-line: no-any +const myExpect = (script: Buffer, answer: string) => { + const result = disassembleByteCode(script); + expect(result[0].value.replace('0000:', '')).toEqual(answer); +}; + +describe('disassembleByteCode', () => { + let sb: ScriptBuilder; + beforeEach(() => { + sb = new ScriptBuilder(); + }); + + noOpOps.forEach((op) => { + test(op, () => { + myExpect(sb.emitOp(op).build(), op); + }); + }); + + test('NEWARRAY_T ByteString', () => { + const script = sb.emitOp('NEWARRAY_T', Buffer.from([StackItemType.ByteString])).build(); + myExpect(script, 'NEWARRAY_T ByteString'); + }); + + test('NEWARRAY_T Incorrect byte', () => { + const script = sb.emitOp('NEWARRAY_T', Buffer.from([0xff])).build(); + myExpect(script, 'NEWARRAY_T 255'); + }); + test('ISTYPE ByteString', () => { + const script = sb.emitOp('ISTYPE', Buffer.from([StackItemType.ByteString])).build(); + myExpect(script, 'ISTYPE ByteString'); + }); + + test('ISTYPE Incorrect byte', () => { + const script = sb.emitOp('ISTYPE', Buffer.from([0xff])).build(); + myExpect(script, 'ISTYPE 255'); + }); + + test('CONVERT ByteString', () => { + const script = sb.emitOp('CONVERT', Buffer.from([StackItemType.ByteString])).build(); + myExpect(script, 'CONVERT ByteString'); + }); + + test('CONVERT Incorrect byte', () => { + const script = sb.emitOp('CONVERT', Buffer.from([0xff])).build(); + myExpect(script, 'CONVERT 255'); + }); + + test('SYSCALL System.Contract.Update', () => { + const script = sb.emitSysCall('System.Contract.Update').build(); + myExpect(script, `SYSCALL System.Contract.Update`); + }); + + test('SYSCALL System.Runtime.GetTime', () => { + const script = sb.emitSysCall('System.Contract.Update').build(); + myExpect(script, `SYSCALL System.Contract.Update`); + }); + + test('PUSHINT8 -128', () => { + const script = sb.emitPushInt(-128).build(); + myExpect(script, `PUSHINT8 ${-128}`); + }); + + test('PUSHINT8 127', () => { + const script = sb.emitPushInt(127).build(); + myExpect(script, `PUSHINT8 ${127}`); + }); + + test('PUSHINT16 -32768', () => { + const script = sb.emitPushInt(-32768).build(); + myExpect(script, `PUSHINT16 ${-32768}`); + }); + + test('PUSHINT16 32767', () => { + const script = sb.emitPushInt(32767).build(); + myExpect(script, `PUSHINT16 ${32767}`); + }); + + test('PUSHINT32 -2147483648', () => { + const script = sb.emitPushInt(-2147483648).build(); + myExpect(script, `PUSHINT32 ${-2147483648}`); + }); + + test('PUSHINT32 2147483647', () => { + const script = sb.emitPushInt(2147483647).build(); + myExpect(script, `PUSHINT32 ${2147483647}`); + }); + + test('PUSHINT64 negative', () => { + const bn = new BN(2).pow(new BN(64)).divn(-2); + const script = sb.emitPushInt(bn).build(); + myExpect(script, `PUSHINT64 ${bn.toString()}`); + }); + + test('PUSHINT64 positive', () => { + const bn = new BN(2).pow(new BN(64)).divn(2).subn(1); + const script = sb.emitPushInt(bn).build(); + myExpect(script, `PUSHINT64 ${bn.toString()}`); + }); + + test('PUSHINT128 negative', () => { + const bn = new BN(2).pow(new BN(128)).divn(-2); + const script = sb.emitPushInt(bn).build(); + myExpect(script, `PUSHINT128 ${bn.toString()}`); + }); + + test('PUSHINT128 positive', () => { + const bn = new BN(2).pow(new BN(128)).divn(2).subn(1); + const script = sb.emitPushInt(bn).build(); + myExpect(script, `PUSHINT128 ${bn.toString()}`); + }); + + test('PUSHINT256 negative', () => { + const bn = new BN(2).pow(new BN(256)).divn(-2); + const script = sb.emitPushInt(bn).build(); + myExpect(script, `PUSHINT256 ${bn.toString()}`); + }); + + test('PUSHINT256 positive', () => { + const bn = new BN(2).pow(new BN(256)).divn(2).subn(1); + const script = sb.emitPushInt(bn).build(); + myExpect(script, `PUSHINT256 ${bn.toString()}`); + }); + + test('JMP', () => { + const script = sb.emitOp('JMP', Buffer.from([0x3])).build(); + myExpect(script, 'JMP 3'); + }); + + test('JMPIF', () => { + const script = sb.emitOp('JMPIF', Buffer.from([0x3])).build(); + myExpect(script, 'JMPIF 3'); + }); + + test('JMPIFNOT', () => { + const script = sb.emitOp('JMPIFNOT', Buffer.from([0x3])).build(); + myExpect(script, 'JMPIFNOT 3'); + }); + + test('JMPEQ', () => { + const script = sb.emitOp('JMPEQ', Buffer.from([0x3])).build(); + myExpect(script, 'JMPEQ 3'); + }); + + test('JMPNE', () => { + const script = sb.emitOp('JMPNE', Buffer.from([0x3])).build(); + myExpect(script, 'JMPNE 3'); + }); + + test('JMPGT', () => { + const script = sb.emitOp('JMPGT', Buffer.from([0x3])).build(); + myExpect(script, 'JMPGT 3'); + }); + + test('JMPLT', () => { + const script = sb.emitOp('JMPLT', Buffer.from([0x3])).build(); + myExpect(script, 'JMPLT 3'); + }); + + test('JMPGE', () => { + const script = sb.emitOp('JMPGE', Buffer.from([0x3])).build(); + myExpect(script, 'JMPGE 3'); + }); + + test('JMPLE', () => { + const script = sb.emitOp('JMPLE', Buffer.from([0x3])).build(); + myExpect(script, 'JMPLE 3'); + }); + + test('CALL', () => { + const script = sb.emitOp('CALL', Buffer.from([0x3])).build(); + myExpect(script, 'CALL 3'); + }); + + test('ENDTRY', () => { + const script = sb.emitOp('ENDTRY', Buffer.from([0x3])).build(); + myExpect(script, 'ENDTRY 3'); + }); + + test('JMP_L', () => { + const script = sb.emitOp('JMP_L', new BN(2147483647).toBuffer('le')).build(); + myExpect(script, 'JMP_L 2147483647'); + }); + + test('JMPIF_L', () => { + const script = sb.emitOp('JMPIF_L', new BN(2147483647).toBuffer('le')).build(); + myExpect(script, 'JMPIF_L 2147483647'); + }); + + test('JMPIFNOT_L', () => { + const script = sb.emitOp('JMPIFNOT_L', new BN(2147483647).toBuffer('le')).build(); + myExpect(script, 'JMPIFNOT_L 2147483647'); + }); + + test('JMPEQ_L', () => { + const script = sb.emitOp('JMPEQ_L', new BN(2147483647).toBuffer('le')).build(); + myExpect(script, 'JMPEQ_L 2147483647'); + }); + + test('JMPNE_L', () => { + const script = sb.emitOp('JMPNE_L', new BN(2147483647).toBuffer('le')).build(); + myExpect(script, 'JMPNE_L 2147483647'); + }); + + test('JMPGT_L', () => { + const script = sb.emitOp('JMPGT_L', new BN(2147483647).toBuffer('le')).build(); + myExpect(script, 'JMPGT_L 2147483647'); + }); + + test('JMPLT_L', () => { + const script = sb.emitOp('JMPLT_L', new BN(2147483647).toBuffer('le')).build(); + myExpect(script, 'JMPLT_L 2147483647'); + }); + + test('JMPGE_L', () => { + const script = sb.emitOp('JMPGE_L', new BN(2147483647).toBuffer('le')).build(); + myExpect(script, 'JMPGE_L 2147483647'); + }); + + test('JMPLE_L', () => { + const script = sb.emitOp('JMPLE_L', new BN(2147483647).toBuffer('le')).build(); + myExpect(script, 'JMPLE_L 2147483647'); + }); + + test('CALL_L', () => { + const script = sb.emitOp('CALL_L', new BN(2147483647).toBuffer('le')).build(); + myExpect(script, 'CALL_L 2147483647'); + }); + + test('ENDTRY_L', () => { + const script = sb.emitOp('ENDTRY_L', new BN(2147483647).toBuffer('le')).build(); + myExpect(script, 'ENDTRY_L 2147483647'); + }); + + test('PUSHA', () => { + const buf = Buffer.from([1, 2, 3, 4]); + const script = sb.emitOp('PUSHA', buf).build(); + myExpect(script, 'PUSHA 0x01020304'); + }); +}); diff --git a/packages/neo-one-node-core/src/contractParameter/AnyContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/AnyContractParameter.ts new file mode 100644 index 0000000000..4d23478681 --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/AnyContractParameter.ts @@ -0,0 +1,30 @@ +import { AnyContractParameterJSON } from '@neo-one/client-common'; +import { DeserializeWireBaseOptions } from '../Serializable'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; + +export class AnyContractParameter extends ContractParameterBase< + AnyContractParameter, + AnyContractParameterJSON, + ContractParameterType.Any +> { + public static deserializeWireBase(options: DeserializeWireBaseOptions): AnyContractParameter { + super.deserializeContractParameterBaseWireBase(options); + + return new this(); + } + + public readonly type = ContractParameterType.Any; + public readonly size: number = 0; + + public asBoolean(): boolean { + return false; + } + + public serializeJSON(): AnyContractParameterJSON { + return { + type: 'Any', + value: undefined, + }; + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/ArrayContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/ArrayContractParameter.ts new file mode 100644 index 0000000000..a3c177054b --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/ArrayContractParameter.ts @@ -0,0 +1,42 @@ +import { ArrayContractParameterJSON, BinaryWriter, IOHelper, utils } from '@neo-one/client-common'; +import { ContractParameter } from './ContractParameter'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; + +export class ArrayContractParameter extends ContractParameterBase< + ArrayContractParameter, + ArrayContractParameterJSON, + ContractParameterType.Array +> { + public readonly type = ContractParameterType.Array; + public readonly value: readonly ContractParameter[]; + private readonly sizeInternal: () => number; + + public constructor(value: readonly ContractParameter[]) { + super(); + this.value = value; + this.sizeInternal = utils.lazy(() => IOHelper.sizeOfArray(this.value, (val) => val.size)); + } + + public get size(): number { + return this.sizeInternal(); + } + + public asBoolean(): boolean { + return this.value.length > 0; + } + + public serializeWireBase(writer: BinaryWriter): void { + super.serializeWireBase(writer); + writer.writeArray(this.value, (parameter) => parameter.serializeWireBase(writer)); + } + + // deserialize is monkey patched on later + + public serializeJSON(): ArrayContractParameterJSON { + return { + type: 'Array', + value: this.value.map((val) => val.serializeJSON()), + }; + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/BooleanContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/BooleanContractParameter.ts new file mode 100644 index 0000000000..518ef2b9a3 --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/BooleanContractParameter.ts @@ -0,0 +1,54 @@ +import { BinaryWriter, BooleanContractParameterJSON, IOHelper, utils } from '@neo-one/client-common'; +import { DeserializeWireBaseOptions } from '../Serializable'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; + +export class BooleanContractParameter extends ContractParameterBase< + BooleanContractParameter, + BooleanContractParameterJSON, + ContractParameterType.Boolean +> { + public static readonly TRUE = Buffer.from([1]); + public static readonly FALSE = Buffer.from([0]); + public static deserializeWireBase(options: DeserializeWireBaseOptions): BooleanContractParameter { + const { reader } = options; + super.deserializeContractParameterBaseWireBase(options); + const value = reader.readBoolean(); + + return new this(value); + } + + public readonly type = ContractParameterType.Boolean; + public readonly value: boolean; + private readonly sizeInternal: () => number; + + public constructor(value: boolean) { + super(); + this.value = value; + this.sizeInternal = utils.lazy(() => IOHelper.sizeOfBoolean); + } + + public get size(): number { + return this.sizeInternal(); + } + + public asBuffer(): Buffer { + return this.value ? BooleanContractParameter.TRUE : BooleanContractParameter.FALSE; + } + + public asBoolean(): boolean { + return this.value; + } + + public serializeWireBase(writer: BinaryWriter): void { + super.serializeWireBase(writer); + writer.writeBoolean(this.value); + } + + public serializeJSON(): BooleanContractParameterJSON { + return { + type: 'Boolean', + value: this.value, + }; + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/ByteArrayContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/ByteArrayContractParameter.ts new file mode 100644 index 0000000000..a8333ebcec --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/ByteArrayContractParameter.ts @@ -0,0 +1,48 @@ +import { BinaryWriter, ByteArrayContractParameterJSON, IOHelper, JSONHelper, utils } from '@neo-one/client-common'; +import { DeserializeWireBaseOptions } from '../Serializable'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; + +export class ByteArrayContractParameter extends ContractParameterBase< + ByteArrayContractParameter, + ByteArrayContractParameterJSON, + ContractParameterType.ByteArray +> { + public static deserializeWireBase(options: DeserializeWireBaseOptions): ByteArrayContractParameter { + const { reader } = options; + super.deserializeContractParameterBaseWireBase(options); + const value = reader.readVarBytesLE(); + + return new this(value); + } + + public readonly type = ContractParameterType.ByteArray; + public readonly value: Buffer; + private readonly sizeInternal: () => number; + + public constructor(value: Buffer) { + super(); + this.value = value; + this.sizeInternal = utils.lazy(() => IOHelper.sizeOfVarBytesLE(this.value)); + } + + public get size(): number { + return this.sizeInternal(); + } + + public asBuffer(): Buffer { + return this.value; + } + + public serializeWireBase(writer: BinaryWriter): void { + super.serializeWireBase(writer); + writer.writeVarBytesLE(this.value); + } + + public serializeJSON(): ByteArrayContractParameterJSON { + return { + type: 'ByteArray', + value: JSONHelper.writeBuffer(this.value), + }; + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/ContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/ContractParameter.ts new file mode 100644 index 0000000000..4e7ea1658d --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/ContractParameter.ts @@ -0,0 +1,124 @@ +import { assertContractParameterType } from '@neo-one/client-common'; +import { utils } from '@neo-one/utils'; +import { DeserializeWire, DeserializeWireBase, DeserializeWireBaseOptions } from '../Serializable'; +import { BinaryReader } from '../utils'; +import { AnyContractParameter } from './AnyContractParameter'; +import { ArrayContractParameter } from './ArrayContractParameter'; +import { BooleanContractParameter } from './BooleanContractParameter'; +import { ByteArrayContractParameter } from './ByteArrayContractParameter'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; +import { Hash160ContractParameter } from './Hash160ContractParameter'; +import { Hash256ContractParameter } from './Hash256ContractParameter'; +import { IntegerContractParameter } from './IntegerContractParameter'; +import { InteropInterfaceContractParameter } from './InteropInterfaceContractParameter'; +import { MapContractParameter } from './MapContractParameter'; +import { PublicKeyContractParameter } from './PublicKeyContractParameter'; +import { SignatureContractParameter } from './SignatureContractParameter'; +import { StringContractParameter } from './StringContractParameter'; +import { VoidContractParameter } from './VoidContractParameter'; + +export type ContractParameter = + | SignatureContractParameter + | BooleanContractParameter + | IntegerContractParameter + | Hash160ContractParameter + | Hash256ContractParameter + | ByteArrayContractParameter + | PublicKeyContractParameter + | StringContractParameter + | ArrayContractParameter + | MapContractParameter + | InteropInterfaceContractParameter + | VoidContractParameter + | AnyContractParameter; + +export const deserializeContractParameterWireBase = (options: DeserializeWireBaseOptions): ContractParameter => { + const { reader } = options; + const type = assertContractParameterType(reader.clone().readUInt8()); + switch (type) { + case ContractParameterType.Signature: + return SignatureContractParameter.deserializeWireBase(options); + case ContractParameterType.Boolean: + return BooleanContractParameter.deserializeWireBase(options); + case ContractParameterType.Integer: + return IntegerContractParameter.deserializeWireBase(options); + case ContractParameterType.Hash160: + return Hash160ContractParameter.deserializeWireBase(options); + case ContractParameterType.Hash256: + return Hash256ContractParameter.deserializeWireBase(options); + case ContractParameterType.ByteArray: + return ByteArrayContractParameter.deserializeWireBase(options); + case ContractParameterType.PublicKey: + return PublicKeyContractParameter.deserializeWireBase(options); + case ContractParameterType.String: + return StringContractParameter.deserializeWireBase(options); + case ContractParameterType.Array: + // tslint:disable-next-line + return (ArrayContractParameter as any).deserializeWireBase(options); + case ContractParameterType.Map: + // tslint:disable-next-line + return (MapContractParameter as any).deserializeWireBase(options); + case ContractParameterType.InteropInterface: + return InteropInterfaceContractParameter.deserializeWireBase(options); + case ContractParameterType.Void: + return VoidContractParameter.deserializeWireBase(options); + case ContractParameterType.Any: + return AnyContractParameter.deserializeWireBase(options); + default: + utils.assertNever(type); + throw new Error('For TS'); + } +}; + +// Copied over from Serializable.ts. Oddly TS won't import this +function createDeserializeWire(deserializeWireBase: DeserializeWireBase): DeserializeWire { + return (options) => + deserializeWireBase({ + context: options.context, + reader: new BinaryReader(options.buffer), + }); +} + +export const deserializeWire = createDeserializeWire(deserializeContractParameterWireBase); + +// tslint:disable-next-line no-object-mutation readonly-keyword +(ArrayContractParameter as { deserializeWireBase?: DeserializeWireBase }).deserializeWireBase = ( + options, +): ArrayContractParameter => { + const { reader } = options; + reader.readUInt8(); + const value = reader.readArray(() => deserializeContractParameterWireBase(options)); + + return new ArrayContractParameter(value); +}; + +// tslint:disable-next-line no-object-mutation +(ArrayContractParameter as { + // tslint:disable-next-line readonly-keyword + deserializeWire?: DeserializeWire; +}).deserializeWire = createDeserializeWire( + // tslint:disable-next-line no-any + (ArrayContractParameter as any).deserializeWireBase.bind(ArrayContractParameter), +); + +// tslint:disable-next-line no-object-mutation readonly-keyword +(MapContractParameter as { deserializeWireBase?: DeserializeWireBase }).deserializeWireBase = ( + options, +): MapContractParameter => { + const { reader } = options; + reader.readUInt8(); + const value = reader.readArray(() => reader.readArray(() => deserializeContractParameterWireBase(options))); + + // tslint:disable-next-line no-any + return new MapContractParameter(value as any); +}; + +// tslint:disable-next-line no-object-mutation +(MapContractParameter as { + // tslint:disable-next-line readonly-keyword + deserializeWire?: DeserializeWire; +}).deserializeWire = createDeserializeWire( + // tslint:disable-next-line no-any + (MapContractParameter as any).deserializeWireBase.bind(MapContractParameter), +); diff --git a/packages/neo-one-node-core/src/contractParameter/ContractParameterBase.ts b/packages/neo-one-node-core/src/contractParameter/ContractParameterBase.ts new file mode 100644 index 0000000000..026039426b --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/ContractParameterBase.ts @@ -0,0 +1,54 @@ +import { BinaryWriter } from '@neo-one/client-common'; +import { + createSerializeWire, + DeserializeWireBaseOptions, + DeserializeWireOptions, + SerializableJSON, + SerializableWire, + SerializeWire, +} from '../Serializable'; +import { BinaryReader } from '../utils'; +import { ContractParameterType } from './ContractParameterType'; + +export abstract class ContractParameterBase< + // tslint:disable-next-line: no-unused + T = {}, + TJSON = {}, + Type extends ContractParameterType = ContractParameterType +> implements SerializableWire, SerializableJSON { + public static deserializeContractParameterBaseWireBase({ reader }: DeserializeWireBaseOptions) { + const type = reader.readUInt8(); + + return { type }; + } + + public static deserializeWireBase(_options: DeserializeWireBaseOptions): ContractParameterBase { + throw new Error('Not Implemented'); + } + + public static deserializeWire(options: DeserializeWireOptions): ContractParameterBase { + return this.deserializeWireBase({ + context: options.context, + reader: new BinaryReader(options.buffer), + }); + } + + public abstract readonly type: Type; + public readonly serializeWire: SerializeWire = createSerializeWire(this.serializeWireBase.bind(this)); + + public asBuffer(): Buffer { + throw new Error('Unimplemented.'); + } + + public asBoolean(): boolean { + return this.asBuffer().some((value) => value !== 0); + } + + public serializeWireBase(writer: BinaryWriter): void { + writer.writeUInt8(this.type); + } + + public serializeJSON(): TJSON { + throw new Error('Not Implemented'); + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/ContractParameterType.ts b/packages/neo-one-node-core/src/contractParameter/ContractParameterType.ts new file mode 100644 index 0000000000..de416bd0d7 --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/ContractParameterType.ts @@ -0,0 +1 @@ +export { ContractParameterTypeModel as ContractParameterType } from '@neo-one/client-common'; diff --git a/packages/neo-one-node-core/src/contractParameter/Hash160ContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/Hash160ContractParameter.ts new file mode 100644 index 0000000000..3201c5f80e --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/Hash160ContractParameter.ts @@ -0,0 +1,56 @@ +import { + BinaryWriter, + common, + Hash160ContractParameterJSON, + IOHelper, + JSONHelper, + UInt160, + utils, +} from '@neo-one/client-common'; +import { DeserializeWireBaseOptions } from '../Serializable'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; + +export class Hash160ContractParameter extends ContractParameterBase< + Hash160ContractParameter, + Hash160ContractParameterJSON, + ContractParameterType.Hash160 +> { + public static deserializeWireBase(options: DeserializeWireBaseOptions): Hash160ContractParameter { + const { reader } = options; + super.deserializeContractParameterBaseWireBase(options); + const value = reader.readUInt160(); + + return new this(value); + } + + public readonly type = ContractParameterType.Hash160; + public readonly value: UInt160; + private readonly sizeInternal: () => number; + + public constructor(value: UInt160) { + super(); + this.value = value; + this.sizeInternal = utils.lazy(() => IOHelper.sizeOfUInt160); + } + + public get size(): number { + return this.sizeInternal(); + } + + public asBuffer(): Buffer { + return common.uInt160ToBuffer(this.value); + } + + public serializeWireBase(writer: BinaryWriter): void { + super.serializeWireBase(writer); + writer.writeUInt160(this.value); + } + + public serializeJSON(): Hash160ContractParameterJSON { + return { + type: 'Hash160', + value: JSONHelper.writeUInt160(this.value), + }; + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/Hash256ContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/Hash256ContractParameter.ts new file mode 100644 index 0000000000..73c1a065dc --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/Hash256ContractParameter.ts @@ -0,0 +1,56 @@ +import { + BinaryWriter, + common, + Hash256ContractParameterJSON, + IOHelper, + JSONHelper, + UInt256, + utils, +} from '@neo-one/client-common'; +import { DeserializeWireBaseOptions } from '../Serializable'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; + +export class Hash256ContractParameter extends ContractParameterBase< + Hash256ContractParameter, + Hash256ContractParameterJSON, + ContractParameterType.Hash256 +> { + public static deserializeWireBase(options: DeserializeWireBaseOptions): Hash256ContractParameter { + const { reader } = options; + super.deserializeContractParameterBaseWireBase(options); + const value = reader.readUInt256(); + + return new this(value); + } + + public readonly type = ContractParameterType.Hash256; + public readonly value: UInt256; + private readonly sizeInternal: () => number; + + public constructor(value: UInt256) { + super(); + this.value = value; + this.sizeInternal = utils.lazy(() => IOHelper.sizeOfUInt256); + } + + public get size(): number { + return this.sizeInternal(); + } + + public asBuffer(): Buffer { + return common.uInt256ToBuffer(this.value); + } + + public serializeWireBase(writer: BinaryWriter): void { + super.serializeWireBase(writer); + writer.writeUInt256(this.value); + } + + public serializeJSON(): Hash256ContractParameterJSON { + return { + type: 'Hash256', + value: JSONHelper.writeUInt256(this.value), + }; + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/IntegerContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/IntegerContractParameter.ts new file mode 100644 index 0000000000..71712918d8 --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/IntegerContractParameter.ts @@ -0,0 +1,53 @@ +import { BinaryWriter, IntegerContractParameterJSON, IOHelper, utils } from '@neo-one/client-common'; +import { BN } from 'bn.js'; +import { DeserializeWireBaseOptions } from '../Serializable'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; + +export class IntegerContractParameter extends ContractParameterBase< + IntegerContractParameter, + IntegerContractParameterJSON, + ContractParameterType.Integer +> { + public static deserializeWireBase(options: DeserializeWireBaseOptions): IntegerContractParameter { + const { reader } = options; + super.deserializeContractParameterBaseWireBase(options); + const value = utils.fromSignedBuffer(reader.readVarBytesLE()); + + return new this(value); + } + + public readonly type = ContractParameterType.Integer; + public readonly value: BN; + private readonly sizeInternal: () => number; + + public constructor(value: BN) { + super(); + this.value = value; + this.sizeInternal = utils.lazy(() => IOHelper.sizeOfVarBytesLE(utils.toSignedBuffer(this.value))); + } + + public get size(): number { + return this.sizeInternal(); + } + + public asBoolean(): boolean { + return !this.value.isZero(); + } + + public asBuffer(): Buffer { + return utils.toSignedBuffer(this.value); + } + + public serializeWireBase(writer: BinaryWriter): void { + super.serializeWireBase(writer); + writer.writeVarBytesLE(utils.toSignedBuffer(this.value)); + } + + public serializeJSON(): IntegerContractParameterJSON { + return { + type: 'Integer', + value: this.value.toString(10), + }; + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/InteropInterfaceContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/InteropInterfaceContractParameter.ts new file mode 100644 index 0000000000..b46bcbd52c --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/InteropInterfaceContractParameter.ts @@ -0,0 +1,25 @@ +import { InteropInterfaceContractParameterJSON } from '@neo-one/client-common'; +import { DeserializeWireBaseOptions } from '../Serializable'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; + +export class InteropInterfaceContractParameter extends ContractParameterBase< + InteropInterfaceContractParameter, + InteropInterfaceContractParameterJSON, + ContractParameterType.InteropInterface +> { + public static deserializeWireBase(options: DeserializeWireBaseOptions): InteropInterfaceContractParameter { + super.deserializeContractParameterBaseWireBase(options); + + return new this(); + } + + public readonly type = ContractParameterType.InteropInterface; + public readonly size: number = 0; + + public serializeJSON(): InteropInterfaceContractParameterJSON { + return { + type: 'InteropInterface', + }; + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/MapContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/MapContractParameter.ts new file mode 100644 index 0000000000..42a54b9949 --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/MapContractParameter.ts @@ -0,0 +1,47 @@ +import { BinaryWriter, ContractParameterJSON, IOHelper, MapContractParameterJSON, utils } from '@neo-one/client-common'; +import { ContractParameter } from './ContractParameter'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; + +export class MapContractParameter extends ContractParameterBase< + MapContractParameter, + MapContractParameterJSON, + ContractParameterType.Map +> { + public readonly type = ContractParameterType.Map; + public readonly value: ReadonlyArray; + private readonly sizeInternal: () => number; + + public constructor(value: ReadonlyArray) { + super(); + this.value = value; + this.sizeInternal = utils.lazy(() => IOHelper.sizeOfArray(this.value, (val) => val[0].size + val[1].size)); + } + + public get size(): number { + return this.sizeInternal(); + } + + public asBoolean(): boolean { + return this.value.length > 0; + } + + public serializeWireBase(writer: BinaryWriter): void { + super.serializeWireBase(writer); + writer.writeArray(this.value, (parameter) => + writer.writeArray(parameter, (value) => value.serializeWireBase(writer)), + ); + } + + // deserialize is monkey patched on later + + public serializeJSON(): MapContractParameterJSON { + return { + type: 'Map' as const, + value: this.value.map((val) => [ + val[0].serializeJSON(), + val[1].serializeJSON(), + ]), + }; + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/PublicKeyContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/PublicKeyContractParameter.ts new file mode 100644 index 0000000000..ac6e69b0ec --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/PublicKeyContractParameter.ts @@ -0,0 +1,56 @@ +import { + BinaryWriter, + common, + ECPoint, + IOHelper, + JSONHelper, + PublicKeyContractParameterJSON, + utils, +} from '@neo-one/client-common'; +import { DeserializeWireBaseOptions } from '../Serializable'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; + +export class PublicKeyContractParameter extends ContractParameterBase< + PublicKeyContractParameter, + PublicKeyContractParameterJSON, + ContractParameterType.PublicKey +> { + public static deserializeWireBase(options: DeserializeWireBaseOptions): PublicKeyContractParameter { + const { reader } = options; + super.deserializeContractParameterBaseWireBase(options); + const value = reader.readECPoint(); + + return new this(value); + } + + public readonly type = ContractParameterType.PublicKey; + public readonly value: ECPoint; + private readonly sizeInternal: () => number; + + public constructor(value: ECPoint) { + super(); + this.value = value; + this.sizeInternal = utils.lazy(() => IOHelper.sizeOfECPoint(this.value)); + } + + public get size(): number { + return this.sizeInternal(); + } + + public asBuffer(): Buffer { + return common.ecPointToBuffer(this.value); + } + + public serializeWireBase(writer: BinaryWriter): void { + super.serializeWireBase(writer); + writer.writeECPoint(this.value); + } + + public serializeJSON(): PublicKeyContractParameterJSON { + return { + type: 'PublicKey', + value: JSONHelper.writeECPoint(this.value), + }; + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/SignatureContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/SignatureContractParameter.ts new file mode 100644 index 0000000000..dea0a6aba4 --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/SignatureContractParameter.ts @@ -0,0 +1,49 @@ +import { BinaryWriter, IOHelper, JSONHelper, SignatureContractParameterJSON } from '@neo-one/client-common'; +import { DeserializeWireBaseOptions } from '../Serializable'; +import { utils } from '../utils'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; + +export class SignatureContractParameter extends ContractParameterBase< + SignatureContractParameter, + SignatureContractParameterJSON, + ContractParameterType.Signature +> { + public static deserializeWireBase(options: DeserializeWireBaseOptions): SignatureContractParameter { + const { reader } = options; + super.deserializeContractParameterBaseWireBase(options); + const value = reader.readVarBytesLE(); + + return new this(value); + } + + public readonly type = ContractParameterType.Signature; + public readonly value: Buffer; + private readonly sizeInternal: () => number; + + public constructor(value: Buffer) { + super(); + this.value = value; + this.sizeInternal = utils.lazy(() => IOHelper.sizeOfVarBytesLE(this.value)); + } + + public get size(): number { + return this.sizeInternal(); + } + + public asBuffer(): Buffer { + return this.value; + } + + public serializeWireBase(writer: BinaryWriter): void { + super.serializeWireBase(writer); + writer.writeVarBytesLE(this.value); + } + + public serializeJSON(): SignatureContractParameterJSON { + return { + type: 'Signature', + value: JSONHelper.writeBuffer(this.value), + }; + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/StringContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/StringContractParameter.ts new file mode 100644 index 0000000000..229bd1bd1a --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/StringContractParameter.ts @@ -0,0 +1,48 @@ +import { BinaryWriter, IOHelper, StringContractParameterJSON, utils } from '@neo-one/client-common'; +import { DeserializeWireBaseOptions } from '../Serializable'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; + +export class StringContractParameter extends ContractParameterBase< + StringContractParameter, + StringContractParameterJSON, + ContractParameterType.String +> { + public static deserializeWireBase(options: DeserializeWireBaseOptions): StringContractParameter { + const { reader } = options; + super.deserializeContractParameterBaseWireBase(options); + const value = reader.readVarString(); + + return new this(value); + } + + public readonly type = ContractParameterType.String; + public readonly value: string; + private readonly sizeInternal: () => number; + + public constructor(value: string) { + super(); + this.value = value; + this.sizeInternal = utils.lazy(() => IOHelper.sizeOfVarString(this.value)); + } + + public get size(): number { + return this.sizeInternal(); + } + + public asBuffer(): Buffer { + return Buffer.from(this.value, 'utf8'); + } + + public serializeWireBase(writer: BinaryWriter): void { + super.serializeWireBase(writer); + writer.writeVarString(this.value); + } + + public serializeJSON(): StringContractParameterJSON { + return { + type: 'String', + value: this.value, + }; + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/VoidContractParameter.ts b/packages/neo-one-node-core/src/contractParameter/VoidContractParameter.ts new file mode 100644 index 0000000000..c854ab347d --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/VoidContractParameter.ts @@ -0,0 +1,29 @@ +import { VoidContractParameterJSON } from '@neo-one/client-common'; +import { DeserializeWireBaseOptions } from '../Serializable'; +import { ContractParameterBase } from './ContractParameterBase'; +import { ContractParameterType } from './ContractParameterType'; + +export class VoidContractParameter extends ContractParameterBase< + VoidContractParameter, + VoidContractParameterJSON, + ContractParameterType.Void +> { + public static deserializeWireBase(options: DeserializeWireBaseOptions): VoidContractParameter { + super.deserializeContractParameterBaseWireBase(options); + + return new this(); + } + + public readonly type = ContractParameterType.Void; + public readonly size: number = 0; + + public asBoolean(): boolean { + return false; + } + + public serializeJSON(): VoidContractParameterJSON { + return { + type: 'Void', + }; + } +} diff --git a/packages/neo-one-node-core/src/contractParameter/index.ts b/packages/neo-one-node-core/src/contractParameter/index.ts new file mode 100644 index 0000000000..b954b575be --- /dev/null +++ b/packages/neo-one-node-core/src/contractParameter/index.ts @@ -0,0 +1,16 @@ +export * from './AnyContractParameter'; +export * from './ArrayContractParameter'; +export * from './BooleanContractParameter'; +export * from './ByteArrayContractParameter'; +export * from './ContractParameter'; +export * from './ContractParameterBase'; +export * from './ContractParameterType'; +export * from './Hash160ContractParameter'; +export * from './Hash256ContractParameter'; +export * from './IntegerContractParameter'; +export * from './InteropInterfaceContractParameter'; +export * from './MapContractParameter'; +export * from './PublicKeyContractParameter'; +export * from './SignatureContractParameter'; +export * from './StringContractParameter'; +export * from './VoidContractParameter'; diff --git a/packages/neo-one-node-core/src/disassembleByteCode.ts b/packages/neo-one-node-core/src/disassembleByteCode.ts new file mode 100644 index 0000000000..5ffc2ae833 --- /dev/null +++ b/packages/neo-one-node-core/src/disassembleByteCode.ts @@ -0,0 +1,142 @@ +// tslint:disable prefer-switch +import { Byte, isByteCode, Op, OpCode, toStackItemTypeJSON, toSysCallName } from '@neo-one/client-common'; +import { BinaryReader, utils } from './utils'; + +export const createHexString = (bytes: Buffer): string => { + let mutableResult = ''; + bytes.forEach((byte) => { + mutableResult += `${byte.toString(16).padStart(2, '0')}`; + }); + + return `0x${mutableResult}`; +}; + +interface Line { + readonly pc: number; + readonly value: string; +} + +export const disassembleByteCode = (bytes: Buffer): readonly Line[] => { + const reader = new BinaryReader(bytes); + + const signedBufferToString = (bytesLength: number) => + utils.fromSignedBuffer(reader.readBytes(bytesLength)).toString(10); + + const mutableResult: Array = []; + // tslint:disable-next-line no-loop-statement + while (reader.hasMore()) { + const pc = reader.index; + const byte = reader.readUInt8(); + if (!isByteCode(byte)) { + mutableResult.push([pc, 'UNKNOWN', undefined]); + continue; + } + + const pushData1 = byte === Op.PUSHDATA1; + const pushData2 = byte === Op.PUSHDATA2; + const pushData4 = byte === Op.PUSHDATA4; + + const opCode = Byte[byte]; + + if (pushData1 || pushData2 || pushData4) { + let numBytes; + if (pushData1) { + numBytes = reader.readUInt8(); + } else if (pushData2) { + numBytes = reader.readUInt16LE(); + } else { + numBytes = reader.readInt32LE(); + } + mutableResult.push([pc, opCode, createHexString(reader.readBytes(numBytes))]); + } else if (byte === Op.PUSHINT8) { + mutableResult.push([pc, opCode, signedBufferToString(1)]); + } else if (byte === Op.PUSHINT16) { + mutableResult.push([pc, opCode, signedBufferToString(2)]); + } else if (byte === Op.PUSHINT32) { + mutableResult.push([pc, opCode, signedBufferToString(4)]); + } else if (byte === Op.PUSHINT64) { + mutableResult.push([pc, opCode, signedBufferToString(8)]); + } else if (byte === Op.PUSHINT128) { + mutableResult.push([pc, opCode, signedBufferToString(16)]); + } else if (byte === Op.PUSHINT256) { + mutableResult.push([pc, opCode, signedBufferToString(32)]); + } else if ( + byte === Op.JMP || + byte === Op.JMPIF || + byte === Op.JMPIFNOT || + byte === Op.JMPEQ || + byte === Op.JMPNE || + byte === Op.JMPGT || + byte === Op.JMPLT || + byte === Op.JMPGE || + byte === Op.JMPLE || + byte === Op.CALL || + byte === Op.ENDTRY + ) { + mutableResult.push([pc, opCode, `${reader.readInt8()}`]); + } else if ( + byte === Op.JMP_L || + byte === Op.JMPIF_L || + byte === Op.JMPIFNOT_L || + byte === Op.JMPEQ_L || + byte === Op.JMPNE_L || + byte === Op.JMPGT_L || + byte === Op.JMPLT_L || + byte === Op.JMPGE_L || + byte === Op.JMPLE_L || + byte === Op.CALL_L || + byte === Op.ENDTRY_L + ) { + mutableResult.push([pc, opCode, `${reader.readInt32LE()}`]); + } else if (byte === Op.PUSHA) { + mutableResult.push([pc, opCode, `${createHexString(reader.readBytes(4))}`]); + } else if ( + byte === Op.LDSFLD || + byte === Op.STSFLD || + byte === Op.LDLOC || + byte === Op.STLOC || + byte === Op.LDARG || + byte === Op.STARG || + byte === Op.INITSSLOT + ) { + mutableResult.push([pc, opCode, `${reader.readUInt8()}`]); + } else if (byte === Op.TRY) { + const catchOffset = reader.readInt8(); + const finallyOffset = reader.readInt8(); + mutableResult.push([pc, opCode, `${catchOffset} ${finallyOffset}`]); + } else if (byte === Op.TRY_L) { + const catchOffset = reader.readInt32LE(); + const finallyOffset = reader.readInt32LE(); + mutableResult.push([pc, opCode, `${catchOffset} ${finallyOffset}`]); + } else if (byte === Op.INITSLOT) { + const localVarSlot = reader.readUInt8(); + const parametersCount = reader.readUInt8(); + mutableResult.push([pc, opCode, `${localVarSlot} ${parametersCount}`]); + } else if (byte === Op.NEWARRAY_T || byte === Op.ISTYPE || byte === Op.CONVERT) { + const type = reader.readUInt8(); + let typeString = `${type}`; + try { + typeString = toStackItemTypeJSON(type); + } catch { + // do nothing + } + mutableResult.push([pc, opCode, typeString]); + } else if (byte === Op.SYSCALL) { + const bytesOut = reader.readBytes(4); + let result = createHexString(bytesOut); + try { + result = toSysCallName(bytesOut.readUInt32BE()); + } catch { + // do nothing + } + mutableResult.push([pc, opCode, result]); + } else { + mutableResult.push([pc, opCode, undefined]); + } + } + + return mutableResult.map(([index, opCode, val]) => ({ + pc: index, + value: `${index.toString().padStart(4, '0')}:${opCode}${val === undefined ? '' : ` ${val}`}`, + })); +}; diff --git a/packages/neo-one-node-core/src/index.ts b/packages/neo-one-node-core/src/index.ts index c5e82c416c..182f48f5ea 100644 --- a/packages/neo-one-node-core/src/index.ts +++ b/packages/neo-one-node-core/src/index.ts @@ -42,3 +42,5 @@ export * from './Nep17Transfer'; export * from './Nep17BalanceKey'; export * from './Nep17TransferKey'; export * from './ApplicationLog'; +export * from './disassembleByteCode'; +export * from './contractParameter'; diff --git a/packages/neo-one-node-core/src/utils/deserializeStackItem.ts b/packages/neo-one-node-core/src/utils/deserializeStackItem.ts index 18e1986a2f..91f8c6771f 100644 --- a/packages/neo-one-node-core/src/utils/deserializeStackItem.ts +++ b/packages/neo-one-node-core/src/utils/deserializeStackItem.ts @@ -1,11 +1,10 @@ -import { InvalidFormatError } from '@neo-one/client-common'; +import { assertStackItemType, InvalidFormatError, StackItemType } from '@neo-one/client-common'; import { BN } from 'bn.js'; import _ from 'lodash'; import { ArrayStackItem, assertPrimitiveStackItem, assertStackItem, - assertStackItemType, BooleanStackItem, BufferStackItem, ByteStringStackItem, @@ -14,7 +13,6 @@ import { NullStackItem, PrimitiveStackItem, StackItem, - StackItemType, StructStackItem, } from '../StackItems'; import { BinaryReader } from './BinaryReader'; @@ -62,8 +60,7 @@ export const deserializeStackItem = (reader: BinaryReader, maxArraySize: number, break; case StackItemType.Buffer: - const size = reader.readVarUIntLE(maxItemSize).toNumber(); - deserialized.unshift(new BufferStackItem(reader.readVarBytesLE(size))); + deserialized.unshift(new BufferStackItem(reader.readVarBytesLE(maxItemSize))); break; case StackItemType.Array: diff --git a/packages/neo-one-node-core/src/vm.ts b/packages/neo-one-node-core/src/vm.ts index 83b4fd0174..f14eba6fea 100644 --- a/packages/neo-one-node-core/src/vm.ts +++ b/packages/neo-one-node-core/src/vm.ts @@ -19,7 +19,8 @@ export interface VMLog { readonly containerHash?: UInt256; readonly callingScriptHash: UInt160; readonly message: string; - readonly position: number; + // TODO: remove? + // readonly position: number; } export interface CallReceipt { diff --git a/packages/neo-one-node-rpc-handler/src/createHandler.ts b/packages/neo-one-node-rpc-handler/src/createHandler.ts index 40ec10568e..8f302bb072 100644 --- a/packages/neo-one-node-rpc-handler/src/createHandler.ts +++ b/packages/neo-one-node-rpc-handler/src/createHandler.ts @@ -1,8 +1,10 @@ import { + ApplicationLogJSON, CallReceiptJSON, common, crypto, JSONHelper, + LogJSON, RelayTransactionResultJSON, scriptHashToAddress, toVerifyResultJSON, @@ -24,10 +26,10 @@ import { Node, Signers, StackItem, - stackItemToJSON, StorageKey, Transaction, TransactionState, + VMLog, } from '@neo-one/node-core'; import { Labels, utils } from '@neo-one/utils'; import { BN } from 'bn.js'; @@ -300,11 +302,18 @@ export const createHandler = ({ } }; + const vmLogToJson = (log: VMLog): LogJSON => ({ + containerhash: log.containerHash ? common.uInt256ToString(log.containerHash) : undefined, + callingscripthash: common.uInt160ToString(log.callingScriptHash), + message: log.message, + // position: log.position, + }); + const getInvokeResult = (script: Buffer, receipt: CallReceipt): CallReceiptJSON => { - const { stack: stackIn, state, notifications, gasConsumed } = receipt; + const { stack: stackIn, state, notifications, gasConsumed, logs } = receipt; try { - const stack = stackIn.map((item: StackItem) => stackItemToJSON(item, undefined)); + const stack = stackIn.map((item: StackItem) => item.toContractParameter().serializeJSON()); return { script: script.toString('hex'), @@ -312,6 +321,7 @@ export const createHandler = ({ stack, gasconsumed: gasConsumed.toString(), notifications: notifications.map((n) => n.serializeJSON()), + logs: logs.map(vmLogToJson), }; } catch { return { @@ -320,6 +330,7 @@ export const createHandler = ({ stack: 'error: recursive reference', gasconsumed: gasConsumed.toString(), notifications: notifications.map((n) => n.serializeJSON()), + logs: logs.map(vmLogToJson), }; } }; @@ -605,7 +616,7 @@ export const createHandler = ({ [RPC_METHODS.listplugins]: async () => { throw new JSONRPCError(-101, 'Not implemented'); }, - [RPC_METHODS.getapplicationlog]: async (args) => { + [RPC_METHODS.getapplicationlog]: async (args): Promise => { const hash = common.stringToUInt256(args[0]); const value = await blockchain.applicationLogs.tryGet(hash); if (value === undefined) { @@ -621,6 +632,7 @@ export const createHandler = ({ gasconsumed, stack, notifications, + logs: [], // TODO: implement }; }, @@ -845,7 +857,6 @@ export const createHandler = ({ [RPC_METHODS.getinvocationdata]: async (_args) => { throw new JSONRPCError(-101, 'Not implemented'); // const transactionState = await blockchain.transactions.get(JSONHelper.readUInt256(args[0])); - // // TODO: check serializeJSON() method. Doesn't include `data` // const result = transactionState.transaction.serializeJSONWithInvocationData(); // if (result.data === undefined) { diff --git a/packages/neo-one-node-vm/lib/Dispatcher.Engine.cs b/packages/neo-one-node-vm/lib/Dispatcher.Engine.cs index 682f00b790..03d6784935 100644 --- a/packages/neo-one-node-vm/lib/Dispatcher.Engine.cs +++ b/packages/neo-one-node-vm/lib/Dispatcher.Engine.cs @@ -232,13 +232,14 @@ private dynamic[] _getNotifications() private dynamic[] _getLogs() { this.isEngineInitialized(); - var events = this.engine.Logs; - if (events == null || events.Count == 0) - { - return new dynamic[] { }; - } - - return events.Select((p) => ReturnHelpers.convertLog(p)).ToArray(); + return new dynamic[] { }; + // var events = this.engine.Logs; + // if (events == null || events.Count == 0) + // { + // return new dynamic[] { }; + // } + + // return events.Select((p) => ReturnHelpers.convertLog(p)).ToArray(); } private bool isEngineInitialized() diff --git a/packages/neo-one-node-vm/lib/ReturnHelpers.cs b/packages/neo-one-node-vm/lib/ReturnHelpers.cs index aadc41c8ff..6532abe3a1 100644 --- a/packages/neo-one-node-vm/lib/ReturnHelpers.cs +++ b/packages/neo-one-node-vm/lib/ReturnHelpers.cs @@ -156,7 +156,7 @@ public LogReturn(LogEventArgs log) containerHash = log.ScriptContainer != null ? Crypto.Hash256(log.ScriptContainer.GetHashData()) : null; callingScriptHash = log.ScriptHash != null ? log.ScriptHash.ToArray() : null; message = log.Message; - position = log.Position; + // position = log.Position; } } diff --git a/packages/neo-one-node-vm/src/Dispatcher.ts b/packages/neo-one-node-vm/src/Dispatcher.ts index 96c3f1af91..c0bb0106df 100644 --- a/packages/neo-one-node-vm/src/Dispatcher.ts +++ b/packages/neo-one-node-vm/src/Dispatcher.ts @@ -94,7 +94,7 @@ export class Dispatcher { }); } - public updateStore(storage: ReadonlyArray<{ key: Buffer; value: Buffer }>): void { + public updateStore(storage: ReadonlyArray<{ readonly key: Buffer; readonly value: Buffer }>): void { const tableChanges = storage.map((change) => ({ table: change.key[0], key: change.key.slice(1), diff --git a/packages/neo-one-node-vm/src/converters/log.ts b/packages/neo-one-node-vm/src/converters/log.ts index aaf00a70e7..629766e4fc 100644 --- a/packages/neo-one-node-vm/src/converters/log.ts +++ b/packages/neo-one-node-vm/src/converters/log.ts @@ -5,14 +5,14 @@ export interface LogReturn { readonly containerHash?: Buffer; readonly callingScriptHash: Buffer; readonly message: string; - readonly position: number; + // TODO + // readonly position: number; } -export const convertLog = ({ containerHash, callingScriptHash, message, position }: LogReturn): VMLog => { - return { - containerHash: containerHash ? common.asUInt256(containerHash) : undefined, - callingScriptHash: common.asUInt160(callingScriptHash), - message, - position, - }; -}; +export const convertLog = ({ containerHash, callingScriptHash, message }: LogReturn): VMLog => ({ + containerHash: containerHash ? common.asUInt256(containerHash) : undefined, + callingScriptHash: common.asUInt160(callingScriptHash), + message, + // TODO + // position, +}); diff --git a/packages/neo-one-node/src/startFullNode.ts b/packages/neo-one-node/src/startFullNode.ts index 4c5c506317..d81e24e473 100644 --- a/packages/neo-one-node/src/startFullNode.ts +++ b/packages/neo-one-node/src/startFullNode.ts @@ -12,8 +12,8 @@ import { composeDisposable, Disposable, noopDisposable } from '@neo-one/utils'; import { AbstractLevelDOWN } from 'abstract-leveldown'; import fs from 'fs-extra'; import LevelUp from 'levelup'; +import MemDown from 'memdown'; import RocksDB from 'rocksdb'; -import Memdown from 'memdown'; import { toArray } from 'rxjs/operators'; export interface LoggingOptions { @@ -40,6 +40,7 @@ export interface FullNodeOptions { readonly leveldown?: AbstractLevelDOWN; } +// tslint:disable-next-line: no-any const getUpdateVMMemoryStore = (vm: Dispatcher, db: any) => async () => { const updates = await streamToObservable<{ readonly key: Buffer; readonly value: Buffer }>(() => db.createReadStream(), @@ -64,7 +65,7 @@ export const startFullNode = async ({ leveldown: customLeveldown, }: FullNodeOptions): Promise => { let disposable = noopDisposable; - const isMemoryStore = customLeveldown !== undefined && customLeveldown instanceof Memdown; + const isMemoryStore = customLeveldown !== undefined && customLeveldown instanceof MemDown; try { if (!isMemoryStore) { await fs.ensureDir(dataPath); diff --git a/packages/neo-one-smart-contract-codegen/src/__data__/abiFactory.ts b/packages/neo-one-smart-contract-codegen/src/__data__/abiFactory.ts index 9d530683fc..a5d6692604 100644 --- a/packages/neo-one-smart-contract-codegen/src/__data__/abiFactory.ts +++ b/packages/neo-one-smart-contract-codegen/src/__data__/abiFactory.ts @@ -1,4 +1,4 @@ -import { ABI, ABIDefault, ABIReturn } from '@neo-one/client-common'; +import { ABIDefault, ABIReturn, ContractABIClient } from '@neo-one/client-common'; import _ from 'lodash'; // tslint:disable-next-line:no-any @@ -72,7 +72,7 @@ const abiReturns: ReadonlyArray = [ const boolReturnType: ABIReturn = { type: 'Boolean' }; -const createBaseABIFunctions = (): ReadonlyArray => { +const createBaseABIFunctions = (): ReadonlyArray => { const combinations = getCombinations([abiReturns, abiFunctionOptions]); return combinations.map(([abiReturn, abiFuncProps]) => { @@ -80,7 +80,7 @@ const createBaseABIFunctions = (): ReadonlyArray => { const name = `${abiReturn.type}${`${funcPropNames.length === 0 ? '' : '_'}${funcPropNames.join('_')}`}`; return { - functions: [ + methods: [ { name, returnType: abiReturn, @@ -91,7 +91,7 @@ const createBaseABIFunctions = (): ReadonlyArray => { }); }; -const createBaseABIEvents = (): ReadonlyArray => { +const createBaseABIEvents = (): ReadonlyArray => { const combinations = getCombinations([abiReturns, abiParameterOptions]); return combinations.map(([abiReturn, abiParamProps]) => { @@ -99,7 +99,7 @@ const createBaseABIEvents = (): ReadonlyArray => { const name = `${abiReturn.type}${`${paramPropNames.length === 0 ? '' : '_'}${paramPropNames.join('_')}`}`; return { - functions: [ + methods: [ { name: 'foo', returnType: boolReturnType, @@ -121,7 +121,7 @@ const createBaseABIEvents = (): ReadonlyArray => { }); }; -const createBaseABIFunctionParameters = (): ReadonlyArray => { +const createBaseABIFunctionParameters = (): ReadonlyArray => { const combinations = getCombinations([abiReturns, abiParameterOptions]); return combinations.map(([abiReturn, abiParamProps]) => { @@ -129,7 +129,7 @@ const createBaseABIFunctionParameters = (): ReadonlyArray => { const name = `${abiReturn.type}${`${paramPropNames.length === 0 ? '' : '_'}${paramPropNames.join('_')}`}`; return { - functions: [ + methods: [ { name, parameters: [ diff --git a/packages/neo-one-smart-contract-codegen/src/__data__/contractsPaths.ts b/packages/neo-one-smart-contract-codegen/src/__data__/contractsPaths.ts index 79e0584abd..b3e8c98ef3 100644 --- a/packages/neo-one-smart-contract-codegen/src/__data__/contractsPaths.ts +++ b/packages/neo-one-smart-contract-codegen/src/__data__/contractsPaths.ts @@ -14,7 +14,7 @@ export const contractsPaths: ReadonlyArray = [ contractPath: '/foo/bar/one/contracts/Token.ts', typesPath: '/foo/bar/one/generated/Token/types.js', createContractPath: '/foo/bar/one/generated/Token/contract.js', - abiPath: '/foo/bar/one/generated/Token/abi.js', + manifestPath: '/foo/bar/one/generated/Token/manifest.js', sourceMap, }, { @@ -22,7 +22,7 @@ export const contractsPaths: ReadonlyArray = [ contractPath: '/foo/bar/one/contracts/ICO.ts', typesPath: '/foo/bar/one/generated/ICO/types.js', createContractPath: '/foo/bar/one/generated/ICO/contract.js', - abiPath: '/foo/bar/one/generated/ICO/abi.js', + manifestPath: '/foo/bar/one/generated/ICO/manifest.js', sourceMap, }, ]; diff --git a/packages/neo-one-smart-contract-codegen/src/__data__/nep17.ts b/packages/neo-one-smart-contract-codegen/src/__data__/nep17.ts index 6c0cd28fd0..48fbb83122 100644 --- a/packages/neo-one-smart-contract-codegen/src/__data__/nep17.ts +++ b/packages/neo-one-smart-contract-codegen/src/__data__/nep17.ts @@ -1,30 +1,35 @@ -import { ABI } from '@neo-one/client-common'; +import { ContractABIClient } from '@neo-one/client-common'; -const abi = (decimals: number): ABI => ({ - functions: [ +const abi = (decimals: number): ContractABIClient => ({ + hash: '', + methods: [ { name: 'name', constant: true, parameters: [], returnType: { type: 'String' }, + offset: 0, }, { name: 'symbol', constant: true, parameters: [], returnType: { type: 'String' }, + offset: 0, }, { name: 'decimals', constant: true, parameters: [], returnType: { type: 'Integer', decimals: 0 }, + offset: 0, }, { name: 'totalSupply', constant: true, parameters: [], returnType: { type: 'Integer', decimals: 8 }, + offset: 0, }, { name: 'transfer', @@ -49,6 +54,7 @@ const abi = (decimals: number): ABI => ({ }, ], returnType: { type: 'Boolean' }, + offset: 0, }, { name: 'balanceOf', @@ -60,6 +66,7 @@ const abi = (decimals: number): ABI => ({ }, ], returnType: { type: 'Integer', decimals }, + offset: 0, }, { name: 'forward', @@ -68,6 +75,7 @@ const abi = (decimals: number): ABI => ({ { name: 'args', type: 'ForwardValue', rest: true }, ], returnType: { type: 'ForwardValue' }, + offset: 0, }, { name: 'forwardConstant', @@ -77,6 +85,7 @@ const abi = (decimals: number): ABI => ({ { name: 'args', type: 'ForwardValue', rest: true }, ], returnType: { type: 'ForwardValue' }, + offset: 0, }, { name: 'forwardForward', @@ -85,6 +94,7 @@ const abi = (decimals: number): ABI => ({ { name: 'args', type: 'ForwardValue', rest: true, forwardedValue: true }, ], returnType: { type: 'ForwardValue', forwardedValue: true }, + offset: 0, }, { name: 'forwardForwardConstant', @@ -94,6 +104,7 @@ const abi = (decimals: number): ABI => ({ { name: 'args', type: 'ForwardValue', rest: true, forwardedValue: true }, ], returnType: { type: 'ForwardValue', forwardedValue: true }, + offset: 0, }, { name: 'forwardTo', @@ -102,6 +113,7 @@ const abi = (decimals: number): ABI => ({ { name: 'second', type: 'Integer', decimals: 0, forwardedValue: true }, ], returnType: { type: 'Integer', decimals: 8, forwardedValue: true }, + offset: 0, }, { name: 'forwardToConstant', @@ -111,6 +123,7 @@ const abi = (decimals: number): ABI => ({ { name: 'second', type: 'Integer', decimals: 0, forwardedValue: true }, ], returnType: { type: 'Integer', decimals: 8, forwardedValue: true }, + offset: 0, }, { name: 'obj', @@ -129,6 +142,7 @@ const abi = (decimals: number): ABI => ({ }, ], returnType: { type: 'Void' }, + offset: 0, }, ], events: [ diff --git a/packages/neo-one-smart-contract-codegen/src/__data__/testUtils.ts b/packages/neo-one-smart-contract-codegen/src/__data__/testUtils.ts index 04abe421f4..eb46aefd45 100644 --- a/packages/neo-one-smart-contract-codegen/src/__data__/testUtils.ts +++ b/packages/neo-one-smart-contract-codegen/src/__data__/testUtils.ts @@ -1,15 +1,15 @@ -import { ABI } from '@neo-one/client-common'; +import { ContractManifestClient } from '@neo-one/client-common'; import { genSmartContractTypes } from '../types'; -const testABI = (abi: ABI, name: string) => { +const testContractManifestClient = (manifest: ContractManifestClient, name: string) => { test(name, () => { expect({ - inputABI: abi, - types: genSmartContractTypes(name, abi), + inputManifest: manifest, + types: genSmartContractTypes(name, manifest), }).toMatchSnapshot(); }); }; export const testUtils = { - testABI, + testContractManifestClient, }; diff --git a/packages/neo-one-smart-contract-codegen/src/__tests__/abi/genABI.test.ts b/packages/neo-one-smart-contract-codegen/src/__tests__/abi/genABI.test.ts index d4c039bfa3..c36c384668 100644 --- a/packages/neo-one-smart-contract-codegen/src/__tests__/abi/genABI.test.ts +++ b/packages/neo-one-smart-contract-codegen/src/__tests__/abi/genABI.test.ts @@ -1,8 +1,8 @@ import { nep17 } from '@neo-one/client-core'; -import { genABI } from '../../abi'; +import { genManifest } from '../../manifest'; -describe('genABI', () => { +describe('genManifest', () => { test('NEP17', () => { - expect(genABI('Token', nep17.abi(4))).toMatchSnapshot(); + expect(genManifest('Token', nep17.manifest(4))).toMatchSnapshot(); }); }); diff --git a/packages/neo-one-smart-contract-codegen/src/__tests__/contract/genContract.test.ts b/packages/neo-one-smart-contract-codegen/src/__tests__/contract/genContract.test.ts index 651edde370..ffc130fa38 100644 --- a/packages/neo-one-smart-contract-codegen/src/__tests__/contract/genContract.test.ts +++ b/packages/neo-one-smart-contract-codegen/src/__tests__/contract/genContract.test.ts @@ -7,7 +7,7 @@ describe('genContract', () => { name: 'Token', createContractPath: '/foo/bar/one/generated/Token/contract.js', typesPath: '/foo/bar/one/generated/Token/types.js', - abiPath: '/foo/bar/one/generated/Token/abi.js', + manifestPath: '/foo/bar/one/generated/Token/manifest.js', sourceMapsPath: '/foo/bar/one/generated/sourceMaps.js', networksDefinition: { main: { diff --git a/packages/neo-one-smart-contract-codegen/src/__tests__/files/genABIEventFiles.test.ts b/packages/neo-one-smart-contract-codegen/src/__tests__/files/genABIEventFiles.test.ts index 0cf81ac9b9..4f840665e9 100644 --- a/packages/neo-one-smart-contract-codegen/src/__tests__/files/genABIEventFiles.test.ts +++ b/packages/neo-one-smart-contract-codegen/src/__tests__/files/genABIEventFiles.test.ts @@ -6,6 +6,6 @@ describe('ABIEvent Tests', () => { if (abi.events === undefined) { throw new Error('it should be defined'); } - testUtils.testABI(abi, abi.events[0].name); + testUtils.testContractManifestClient(abi, abi.events[0].name); }); }); diff --git a/packages/neo-one-smart-contract-codegen/src/__tests__/genFiles.test.ts b/packages/neo-one-smart-contract-codegen/src/__tests__/genFiles.test.ts index ffabfe3045..d53d026e90 100644 --- a/packages/neo-one-smart-contract-codegen/src/__tests__/genFiles.test.ts +++ b/packages/neo-one-smart-contract-codegen/src/__tests__/genFiles.test.ts @@ -9,9 +9,9 @@ describe('genFiles', () => { contractPath: '/foo/bar/one/contracts/Token.ts', createContractPath: '/foo/bar/one/generated/Token/contract.js', typesPath: '/foo/bar/one/generated/Token/types.js', - abiPath: '/foo/bar/one/generated/Token/abi.js', + manifestPath: '/foo/bar/one/generated/Token/manifest.js', sourceMapsPath: '/foo/bar/one/generated/sourceMaps.js', - abi: nep17.abi(4), + manifest: nep17.manifest(4), networksDefinition: { main: { address: 'iamahash', diff --git a/packages/neo-one-smart-contract-codegen/src/__tests__/types/genSmartContractTypes.test.ts b/packages/neo-one-smart-contract-codegen/src/__tests__/types/genSmartContractTypes.test.ts index 2de1eaed02..9c98ca75a2 100644 --- a/packages/neo-one-smart-contract-codegen/src/__tests__/types/genSmartContractTypes.test.ts +++ b/packages/neo-one-smart-contract-codegen/src/__tests__/types/genSmartContractTypes.test.ts @@ -3,6 +3,6 @@ import { genSmartContractTypes } from '../../types'; describe('genSmartContractTypes', () => { test('NEP17', () => { - expect(genSmartContractTypes('Token', nep17.abi(4))).toMatchSnapshot(); + expect(genSmartContractTypes('Token', nep17.manifest(4))).toMatchSnapshot(); }); }); diff --git a/packages/neo-one-smart-contract-codegen/src/abi/genABI.ts b/packages/neo-one-smart-contract-codegen/src/abi/genABI.ts deleted file mode 100644 index 4ab1fadc49..0000000000 --- a/packages/neo-one-smart-contract-codegen/src/abi/genABI.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ABI } from '@neo-one/client-common'; -import stringify from 'safe-stable-stringify'; -import { getABIName } from './getABIName'; - -export const genABI = (name: string, abi: ABI) => ({ - js: `export const ${getABIName(name)} = ${stringify(abi, undefined, 2)};`, - ts: `import { ABI } from '@neo-one/client'; - -export const ${getABIName(name)}: ABI = ${stringify(abi, undefined, 2)}; -`, -}); diff --git a/packages/neo-one-smart-contract-codegen/src/abi/getABIName.ts b/packages/neo-one-smart-contract-codegen/src/abi/getABIName.ts deleted file mode 100644 index 68338b5b88..0000000000 --- a/packages/neo-one-smart-contract-codegen/src/abi/getABIName.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { lowerCaseFirst } from '../utils'; - -export const getABIName = (name: string) => `${lowerCaseFirst(name)}ABI`; diff --git a/packages/neo-one-smart-contract-codegen/src/abi/index.ts b/packages/neo-one-smart-contract-codegen/src/abi/index.ts deleted file mode 100644 index b21d176ea1..0000000000 --- a/packages/neo-one-smart-contract-codegen/src/abi/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './genABI'; -export * from './getABIName'; diff --git a/packages/neo-one-smart-contract-codegen/src/client/genBrowserClient.ts b/packages/neo-one-smart-contract-codegen/src/client/genBrowserClient.ts index ba47f38f3d..9f691d2836 100644 --- a/packages/neo-one-smart-contract-codegen/src/client/genBrowserClient.ts +++ b/packages/neo-one-smart-contract-codegen/src/client/genBrowserClient.ts @@ -35,9 +35,12 @@ if (process.env.NODE_ENV !== 'production' || process.env.NEO_ONE_DEV === 'true') if (localUserAccountProvider !== undefined) { const localKeyStore = localUserAccountProvider.keystore; if (localKeyStore instanceof LocalKeyStore) { - addLocalKeysSync([ + Promise.all([ ${wallets - .map(({ name, wif }) => `{ network: '${localDevNetworkName}', name: '${name}', privateKey: '${wif}' },`) + .map( + ({ name, wif }) => + `localKeyStore.addUserAccount({ network: '${localDevNetworkName}', name: '${name}', privateKey: '${wif}' }),`, + ) .join('\n ')} ], localKeyStore); } @@ -57,7 +60,6 @@ if (process.env.NODE_ENV !== 'production' || process.env.NEO_ONE_DEV === 'true') return { js: ` import { - addLocalKeysSync, Client, DeveloperClient, LocalKeyStore, @@ -83,7 +85,6 @@ export const createDeveloperClients = () => ${createDeveloperClients} `, ts: ` import { - addLocalKeysSync, Client, DeveloperClient, DeveloperClients, diff --git a/packages/neo-one-smart-contract-codegen/src/client/genClient.ts b/packages/neo-one-smart-contract-codegen/src/client/genClient.ts index 7add66ec95..7c43a4146e 100644 --- a/packages/neo-one-smart-contract-codegen/src/client/genClient.ts +++ b/packages/neo-one-smart-contract-codegen/src/client/genClient.ts @@ -32,11 +32,16 @@ export const genClient = ({ if (localUserAccountProvider !== undefined) { const localKeyStore = localUserAccountProvider.keystore; if (localKeyStore instanceof LocalKeyStore) { - addLocalKeysSync([ + Promise.all([ ${wallets - .map(({ name, wif }) => `{ network: '${localDevNetworkName}', name: '${name}', privateKey: '${wif}' },`) + .map( + ({ name, wif }) => + `localKeyStore.addUserAccount({ network: '${localDevNetworkName}', name: '${name}', privateKey: '${wif}' }),`, + ) .join('\n ')} - ], localKeyStore); + ]).catch(() => { + // do nothing + }); } } }`; @@ -71,7 +76,6 @@ export const genClient = ({ return { js: ` import { - addLocalKeysSync, Client, DapiUserAccountProvider, DeveloperClient, @@ -105,7 +109,6 @@ export const createDeveloperClients = (host = 'localhost') => ${createDeveloperC `, ts: ` import { - addLocalKeysSync, Client, DapiUserAccountProvider, DeveloperClient, diff --git a/packages/neo-one-smart-contract-codegen/src/contract/genContract.ts b/packages/neo-one-smart-contract-codegen/src/contract/genContract.ts index 033e787743..ea3b2506db 100644 --- a/packages/neo-one-smart-contract-codegen/src/contract/genContract.ts +++ b/packages/neo-one-smart-contract-codegen/src/contract/genContract.ts @@ -1,6 +1,6 @@ import { SmartContractNetworksDefinition } from '@neo-one/client-common'; import stringify from 'safe-stable-stringify'; -import { getABIName } from '../abi'; +import { getManifestName } from '../manifest'; import { getSmartContractName } from '../types'; import { getRelativeImport } from '../utils'; import { getCreateSmartContractName } from './getCreateSmartContractName'; @@ -10,29 +10,29 @@ export const genContract = ({ createContractPath, typesPath, sourceMapsPath, - abiPath, + manifestPath, networksDefinition, }: { readonly name: string; readonly createContractPath: string; readonly typesPath: string; - readonly abiPath: string; + readonly manifestPath: string; readonly sourceMapsPath: string; readonly networksDefinition: SmartContractNetworksDefinition; }) => { const relativeTypes = getRelativeImport(createContractPath, typesPath); const smartContract = getSmartContractName(name); - const relativeABI = getRelativeImport(createContractPath, abiPath); + const relativeManifest = getRelativeImport(createContractPath, manifestPath); const relativeSourceMaps = getRelativeImport(createContractPath, sourceMapsPath); - const abiName = getABIName(name); + const manifestName = getManifestName(name); return { - js: `import { ${abiName} } from '${relativeABI}'; + js: `import { ${manifestName} } from '${relativeManifest}'; import { sourceMaps } from '${relativeSourceMaps}'; const definition = { networks: ${stringify(networksDefinition, undefined, 2)}, - abi: ${abiName}, + manifest: ${manifestName}, sourceMaps, }; @@ -43,12 +43,12 @@ export const ${getCreateSmartContractName(name)} = ( ts: ` import { Client } from '@neo-one/client'; import { ${smartContract} } from '${relativeTypes}'; -import { ${abiName} } from '${relativeABI}'; +import { ${manifestName} } from '${relativeManifest}'; import { sourceMaps } from '${relativeSourceMaps}'; const definition = { networks: ${stringify(networksDefinition, undefined, 2)}, - abi: ${abiName}, + manifest: ${manifestName}, sourceMaps, }; diff --git a/packages/neo-one-smart-contract-codegen/src/genFiles.ts b/packages/neo-one-smart-contract-codegen/src/genFiles.ts index 2dc68a6645..8c49f8173d 100644 --- a/packages/neo-one-smart-contract-codegen/src/genFiles.ts +++ b/packages/neo-one-smart-contract-codegen/src/genFiles.ts @@ -1,7 +1,7 @@ -import { ABI, SmartContractNetworksDefinition } from '@neo-one/client-common'; -import { genABI } from './abi'; +import { ContractManifestClient, SmartContractNetworksDefinition } from '@neo-one/client-common'; import { genContract } from './contract'; import { formatFile } from './formatFile'; +import { genManifest } from './manifest'; import { FileResult } from './type'; import { genSmartContractTypes } from './types'; @@ -17,8 +17,8 @@ export const genFiles = ({ sourceMapsPath, createContractPath, typesPath, - abiPath, - abi, + manifestPath, + manifest, browserify, }: { readonly name: string; @@ -26,27 +26,27 @@ export const genFiles = ({ readonly sourceMapsPath: string; readonly createContractPath: string; readonly typesPath: string; - readonly abiPath: string; + readonly manifestPath: string; readonly contractPath: string; - readonly abi: ABI; + readonly manifest: ContractManifestClient; readonly browserify: boolean; }) => { - const abiFile = formatFile(genABI(name, abi), browserify); + const manifestFile = formatFile(genManifest(name, manifest), browserify); const contractFile = formatFile( genContract({ name, createContractPath, sourceMapsPath, typesPath, - abiPath, + manifestPath, networksDefinition, }), browserify, ); - const typesFile = formatFile(genSmartContractTypes(name, abi), browserify); + const typesFile = formatFile(genSmartContractTypes(name, manifest), browserify); return { - abi: abiFile, + manifest: manifestFile, contract: contractFile, types: typesFile, }; diff --git a/packages/neo-one-smart-contract-codegen/src/generated/genGenerated.ts b/packages/neo-one-smart-contract-codegen/src/generated/genGenerated.ts index ad92dd8021..2d9137c871 100644 --- a/packages/neo-one-smart-contract-codegen/src/generated/genGenerated.ts +++ b/packages/neo-one-smart-contract-codegen/src/generated/genGenerated.ts @@ -35,7 +35,11 @@ ${createExport(generatedPath, contractsPath)}${ framework === 'vue' ? createNewLineExport(generatedPath, vuePath) : '' } ${createExport(generatedPath, clientPath)} -${_.flatMap(contractsPaths, ({ createContractPath, typesPath, abiPath }) => [createContractPath, typesPath, abiPath]) +${_.flatMap(contractsPaths, ({ createContractPath, typesPath, manifestPath }) => [ + createContractPath, + typesPath, + manifestPath, +]) .map((importPath) => createExport(generatedPath, importPath)) .join('\n')} `, @@ -44,7 +48,7 @@ ${framework === 'react' ? createNewLineExport(generatedPath, reactPath) : ''}${ framework === 'angular' ? createNewLineExport(generatedPath, angularPath) : '' }${framework === 'vue' ? createNewLineExport(generatedPath, vuePath) : ''} ${createExport(generatedPath, clientPath)} -${_.flatMap(contractsPaths, ({ createContractPath, abiPath }) => [createContractPath, abiPath]) +${_.flatMap(contractsPaths, ({ createContractPath, manifestPath }) => [createContractPath, manifestPath]) .map((importPath) => createExport(generatedPath, importPath)) .join('\n')} `, diff --git a/packages/neo-one-smart-contract-codegen/src/manifest/genManifest.ts b/packages/neo-one-smart-contract-codegen/src/manifest/genManifest.ts new file mode 100644 index 0000000000..01b7bb1a78 --- /dev/null +++ b/packages/neo-one-smart-contract-codegen/src/manifest/genManifest.ts @@ -0,0 +1,11 @@ +import { ContractManifestClient } from '@neo-one/client-common'; +import stringify from 'safe-stable-stringify'; +import { getManifestName } from './getManifestName'; + +export const genManifest = (name: string, manifest: ContractManifestClient) => ({ + js: `export const ${getManifestName(name)} = ${stringify(manifest, undefined, 2)};`, + ts: `import { ContractManifestClient } from '@neo-one/client'; + +export const ${getManifestName(name)}: ContractManifestClient = ${stringify(manifest, undefined, 2)}; +`, +}); diff --git a/packages/neo-one-smart-contract-codegen/src/manifest/getManifestName.ts b/packages/neo-one-smart-contract-codegen/src/manifest/getManifestName.ts new file mode 100644 index 0000000000..85e4e3f5c9 --- /dev/null +++ b/packages/neo-one-smart-contract-codegen/src/manifest/getManifestName.ts @@ -0,0 +1,3 @@ +import { lowerCaseFirst } from '../utils'; + +export const getManifestName = (name: string) => `${lowerCaseFirst(name)}Manifest`; diff --git a/packages/neo-one-smart-contract-codegen/src/manifest/index.ts b/packages/neo-one-smart-contract-codegen/src/manifest/index.ts new file mode 100644 index 0000000000..9a971aaccd --- /dev/null +++ b/packages/neo-one-smart-contract-codegen/src/manifest/index.ts @@ -0,0 +1,2 @@ +export * from './genManifest'; +export * from './getManifestName'; diff --git a/packages/neo-one-smart-contract-codegen/src/type.ts b/packages/neo-one-smart-contract-codegen/src/type.ts index 990f6e7907..472e0621e0 100644 --- a/packages/neo-one-smart-contract-codegen/src/type.ts +++ b/packages/neo-one-smart-contract-codegen/src/type.ts @@ -5,7 +5,7 @@ export interface ContractPaths { readonly sourceMap: RawSourceMap; readonly contractPath: string; readonly createContractPath: string; - readonly abiPath: string; + readonly manifestPath: string; readonly typesPath: string; } diff --git a/packages/neo-one-smart-contract-codegen/src/types/genConstantFunction.ts b/packages/neo-one-smart-contract-codegen/src/types/genConstantFunction.ts index 23c1b59c96..5720691bcc 100644 --- a/packages/neo-one-smart-contract-codegen/src/types/genConstantFunction.ts +++ b/packages/neo-one-smart-contract-codegen/src/types/genConstantFunction.ts @@ -1,4 +1,4 @@ -import { ABIFunction } from '@neo-one/client-common'; +import { ContractMethodDescriptorClient } from '@neo-one/client-common'; import { toTypeScriptType } from '../utils'; import { genFunctionParameters } from './genFunctionParameters'; @@ -6,7 +6,10 @@ export interface GenConstantFunctionOptions { readonly migration?: boolean; } -export const genConstantFunction = (abi: ABIFunction, options: GenConstantFunctionOptions): string => { +export const genConstantFunction = ( + abi: ContractMethodDescriptorClient, + options: GenConstantFunctionOptions, +): string => { const paramss = genFunctionParameters(abi, undefined, options); if (paramss.length === 1) { return `(${paramss[0]}) => Promise<${toTypeScriptType(abi.returnType, { isParameter: false })}>;`; diff --git a/packages/neo-one-smart-contract-codegen/src/types/genEvent.ts b/packages/neo-one-smart-contract-codegen/src/types/genEvent.ts index 870a45b466..b68a851c32 100644 --- a/packages/neo-one-smart-contract-codegen/src/types/genEvent.ts +++ b/packages/neo-one-smart-contract-codegen/src/types/genEvent.ts @@ -1,8 +1,8 @@ -import { ABIEvent } from '@neo-one/client-common'; +import { ContractEventDescriptorClient } from '@neo-one/client-common'; import { toTypeScriptType } from '../utils'; import { getSingleEventName } from './getSingleEventName'; -export const genEvent = (name: string, event: ABIEvent): string => { +export const genEvent = (name: string, event: ContractEventDescriptorClient): string => { const eventName = getSingleEventName(name, event.name); const eventNameParameters = `${eventName}Parameters`; diff --git a/packages/neo-one-smart-contract-codegen/src/types/genForwardArgsFunction.ts b/packages/neo-one-smart-contract-codegen/src/types/genForwardArgsFunction.ts index 6b332e8ba8..bee84132d2 100644 --- a/packages/neo-one-smart-contract-codegen/src/types/genForwardArgsFunction.ts +++ b/packages/neo-one-smart-contract-codegen/src/types/genForwardArgsFunction.ts @@ -1,4 +1,4 @@ -import { ABIFunction, ABIParameter } from '@neo-one/client-common'; +import { ABIParameter, ContractMethodDescriptorClient } from '@neo-one/client-common'; import { genFunctionParameters } from './genFunctionParameters'; import { getEventName } from './getEventName'; @@ -8,7 +8,7 @@ export interface GenForwardArgsFunctionOptions { export const genForwardArgsFunction = ( name: string, - abi: ABIFunction, + abi: ContractMethodDescriptorClient, parameters: ReadonlyArray, options: GenForwardArgsFunctionOptions, ): string => diff --git a/packages/neo-one-smart-contract-codegen/src/types/genForwardReturnFunction.ts b/packages/neo-one-smart-contract-codegen/src/types/genForwardReturnFunction.ts index 25bac4316a..f39cca9f35 100644 --- a/packages/neo-one-smart-contract-codegen/src/types/genForwardReturnFunction.ts +++ b/packages/neo-one-smart-contract-codegen/src/types/genForwardReturnFunction.ts @@ -1,8 +1,8 @@ -import { ABIFunction } from '@neo-one/client-common'; +import { ContractMethodDescriptorClient } from '@neo-one/client-common'; import { toTypeScriptType } from '../utils'; import { getEventName } from './getEventName'; -export const genForwardReturnFunction = (name: string, abi: ABIFunction): string => { +export const genForwardReturnFunction = (name: string, abi: ContractMethodDescriptorClient): string => { const returnType = toTypeScriptType(abi.returnType, { isParameter: false }); return `{ diff --git a/packages/neo-one-smart-contract-codegen/src/types/genFunction.ts b/packages/neo-one-smart-contract-codegen/src/types/genFunction.ts index bb2fbbf2f3..464f177882 100644 --- a/packages/neo-one-smart-contract-codegen/src/types/genFunction.ts +++ b/packages/neo-one-smart-contract-codegen/src/types/genFunction.ts @@ -1,14 +1,10 @@ -import { ABIFunction } from '@neo-one/client-common'; +import { ContractMethodDescriptorClient } from '@neo-one/client-common'; import { toTypeScriptType } from '../utils'; import { genFunctionParameters } from './genFunctionParameters'; import { getEventName } from './getEventName'; import { hasForward } from './hasForward'; -const getFunctionReturnReceipt = (name: string, abi: ABIFunction) => { - if (abi.claim) { - return 'TransactionReceipt'; - } - +const getFunctionReturnReceipt = (name: string, abi: ContractMethodDescriptorClient) => { const eventName = getEventName(name); const event = hasForward(abi) ? `TForwardOptions extends ForwardOptions ? ${eventName} | T : ${eventName}` @@ -17,26 +13,25 @@ const getFunctionReturnReceipt = (name: string, abi: ABIFunction) => { return `InvokeReceipt<${toTypeScriptType(abi.returnType, { isParameter: false })}, ${event}>`; }; -const getFunctionReturnTransaction = (abi: ABIFunction) => (abi.claim ? 'ClaimTransaction' : 'InvocationTransaction'); - -const getFunctionReturnType = (name: string, abi: ABIFunction) => - `TransactionResult<${getFunctionReturnReceipt(name, abi)}, ${getFunctionReturnTransaction(abi)}>`; +const getFunctionReturnType = (name: string, abi: ContractMethodDescriptorClient) => + `TransactionResult<${getFunctionReturnReceipt(name, abi)}>`; -const getForwardType = (abi: ABIFunction) => (hasForward(abi) ? '>' : ''); +const getForwardType = (abi: ContractMethodDescriptorClient) => + hasForward(abi) ? '>' : ''; -const getFunctionType = (name: string, abi: ABIFunction, migration = false) => +const getFunctionType = (name: string, abi: ContractMethodDescriptorClient, migration = false) => genFunctionParameters(abi, abi.parameters, { migration, }) .map((params) => `${getForwardType(abi)}(${params}): Promise<${getFunctionReturnType(name, abi)}>;`) .join(' \n'); -const createConfirmedFunc = (abi: ABIFunction, params: string, name: string, arrow = false) => +const createConfirmedFunc = (abi: ContractMethodDescriptorClient, params: string, name: string, arrow = false) => `${getForwardType(abi)}(${params})${arrow ? ' =>' : ':'} Promise<${getFunctionReturnReceipt( name, abi, - )} & { readonly transaction: ${getFunctionReturnTransaction(abi)}}>;`; -const getConfirmedType = (name: string, abi: ABIFunction, migration = false) => { + )} & { readonly transaction: Transaction }>;`; +const getConfirmedType = (name: string, abi: ContractMethodDescriptorClient, migration = false) => { const paramss = genFunctionParameters(abi, abi.parameters, { withConfirmedOptions: true, migration, @@ -55,7 +50,7 @@ export interface GenFunctionOptions { readonly migration?: boolean; } -export const genFunction = (name: string, abi: ABIFunction, options: GenFunctionOptions): string => +export const genFunction = (name: string, abi: ContractMethodDescriptorClient, options: GenFunctionOptions): string => options.migration ? getConfirmedType(name, abi, options.migration) : `{ diff --git a/packages/neo-one-smart-contract-codegen/src/types/genFunctionParameters.ts b/packages/neo-one-smart-contract-codegen/src/types/genFunctionParameters.ts index 0f1dcac7d2..ff48e37cf8 100644 --- a/packages/neo-one-smart-contract-codegen/src/types/genFunctionParameters.ts +++ b/packages/neo-one-smart-contract-codegen/src/types/genFunctionParameters.ts @@ -1,4 +1,4 @@ -import { ABIFunction, ABIParameter } from '@neo-one/client-common'; +import { ABIParameter, ContractMethodDescriptorClient } from '@neo-one/client-common'; import _ from 'lodash'; import { toTypeScriptType } from '../utils'; @@ -12,37 +12,17 @@ interface Options { readonly migration?: boolean; } -const getOptions = (abi: ABIFunction, { withConfirmedOptions = false }: Options = {}) => { +const getOptions = (abi: ContractMethodDescriptorClient, { withConfirmedOptions = false }: Options = {}) => { if (abi.constant) { return withConfirmedOptions ? ['options?: GetOptions'] : []; } const type = withConfirmedOptions ? ' & GetOptions' : ''; - if (abi.sendUnsafe && abi.receive) { - return [`options?: InvokeSendUnsafeReceiveTransactionOptions${type}`]; - } - - if (abi.sendUnsafe) { - return [`options?: InvokeSendUnsafeTransactionOptions${type}`]; - } - if (abi.receive) { return [`options?: InvokeReceiveTransactionOptions${type}`]; } - if (abi.refundAssets) { - return [`hash: Hash256String, options?: TransactionOptions${type}`]; - } - - if (abi.send) { - return [`transfer: Transfer, options?: TransactionOptions${type}`]; - } - - if (abi.completeSend) { - return [`hash: Hash256String, options?: TransactionOptions${type}`]; - } - return [`options?: TransactionOptions${type}`]; }; @@ -50,7 +30,7 @@ const getRestParameter = (param: ABIParameter, migration = false) => `...${param.name}: ${toTypeScriptType(param, { isParameter: true, includeOptional: false, migration })}[]`; export const genFunctionParameters = ( - abi: ABIFunction, + abi: ContractMethodDescriptorClient, parameters: ReadonlyArray = abi.parameters === undefined ? [] : abi.parameters, options: Options = {}, ): ReadonlyArray => { diff --git a/packages/neo-one-smart-contract-codegen/src/types/genMigrationSmartContract.ts b/packages/neo-one-smart-contract-codegen/src/types/genMigrationSmartContract.ts index 2afc2db581..bc8bd17ed6 100644 --- a/packages/neo-one-smart-contract-codegen/src/types/genMigrationSmartContract.ts +++ b/packages/neo-one-smart-contract-codegen/src/types/genMigrationSmartContract.ts @@ -1,6 +1,6 @@ -import { ABI } from '@neo-one/client-common'; +import { ContractManifestClient } from '@neo-one/client-common'; import { genSmartContractBase } from './genSmartContractBase'; import { getMigrationSmartContractName } from './getMigrationSmartContractName'; -export const genMigrationSmartContract = (name: string, abi: ABI): string => - genSmartContractBase(name, getMigrationSmartContractName(name), abi, true); +export const genMigrationSmartContract = (name: string, manifest: ContractManifestClient): string => + genSmartContractBase(name, getMigrationSmartContractName(name), manifest, true); diff --git a/packages/neo-one-smart-contract-codegen/src/types/genSmartContract.ts b/packages/neo-one-smart-contract-codegen/src/types/genSmartContract.ts index c4eb5931a6..5d8d9a927f 100644 --- a/packages/neo-one-smart-contract-codegen/src/types/genSmartContract.ts +++ b/packages/neo-one-smart-contract-codegen/src/types/genSmartContract.ts @@ -1,6 +1,6 @@ -import { ABI } from '@neo-one/client-common'; +import { ContractManifestClient } from '@neo-one/client-common'; import { genSmartContractBase } from './genSmartContractBase'; import { getSmartContractName } from './getSmartContractName'; -export const genSmartContract = (name: string, abi: ABI): string => - genSmartContractBase(name, getSmartContractName(name), abi); +export const genSmartContract = (name: string, manifest: ContractManifestClient): string => + genSmartContractBase(name, getSmartContractName(name), manifest); diff --git a/packages/neo-one-smart-contract-codegen/src/types/genSmartContractBase.ts b/packages/neo-one-smart-contract-codegen/src/types/genSmartContractBase.ts index 8731ad560b..8fb5e60990 100644 --- a/packages/neo-one-smart-contract-codegen/src/types/genSmartContractBase.ts +++ b/packages/neo-one-smart-contract-codegen/src/types/genSmartContractBase.ts @@ -1,4 +1,4 @@ -import { ABI, ABIFunction } from '@neo-one/client-common'; +import { ContractManifestClient, ContractMethodDescriptorClient } from '@neo-one/client-common'; import { createForwardedValueFuncArgsName, createForwardedValueFuncReturnName } from '@neo-one/client-core'; import _ from 'lodash'; import { genConstantFunction } from './genConstantFunction'; @@ -7,13 +7,18 @@ import { genForwardReturnFunction } from './genForwardReturnFunction'; import { genFunction } from './genFunction'; import { getEventName } from './getEventName'; -export const genSmartContractBase = (name: string, interfaceName: string, abi: ABI, migration = false): string => { +export const genSmartContractBase = ( + name: string, + interfaceName: string, + manifest: ContractManifestClient, + migration = false, +): string => { const extendsClause = ` extends SmartContract`; return ` export interface ${interfaceName}${migration ? '' : extendsClause} { ${_.flatten( - _.sortBy(abi.functions, [(func: ABIFunction) => func.name]).map((func) => { + _.sortBy(manifest.abi.methods, [(func: ContractMethodDescriptorClient) => func.name]).map((func) => { const parameters = func.parameters === undefined ? [] : func.parameters; const forwardedParameters = parameters.filter((parameter) => parameter.forwardedValue); let decls = [ diff --git a/packages/neo-one-smart-contract-codegen/src/types/genSmartContractTypes.ts b/packages/neo-one-smart-contract-codegen/src/types/genSmartContractTypes.ts index 90871257a7..7e1173abea 100644 --- a/packages/neo-one-smart-contract-codegen/src/types/genSmartContractTypes.ts +++ b/packages/neo-one-smart-contract-codegen/src/types/genSmartContractTypes.ts @@ -1,4 +1,4 @@ -import { ABI } from '@neo-one/client-common'; +import { ContractManifestClient } from '@neo-one/client-common'; import { genEvent } from './genEvent'; import { genMigrationSmartContract } from './genMigrationSmartContract'; import { genSmartContract } from './genSmartContract'; @@ -60,14 +60,6 @@ const getImportClauses = (text: string) => { mutableClauses.push('TransactionReceipt'); } - if (text.includes('ClaimTransaction')) { - mutableClauses.push('ClaimTransaction'); - } - - if (text.includes('InvocationTransaction')) { - mutableClauses.push('InvocationTransaction'); - } - if (text.includes('TransactionOptions')) { mutableClauses.push('TransactionOptions'); } @@ -96,19 +88,23 @@ const getImportClauses = (text: string) => { mutableClauses.push('ForwardOptions'); } + if (text.includes('Transaction')) { + mutableClauses.push('Transaction'); + } + return mutableClauses; }; -export const genSmartContractTypes = (name: string, abi: ABI) => { - const events = abi.events === undefined ? [] : abi.events; +export const genSmartContractTypes = (name: string, manifest: ContractManifestClient) => { + const events = manifest.abi.events; const eventType = `export type ${getEventName(name)} = ${ events.length === 0 ? 'never' : events.map((event) => getSingleEventName(name, event.name)).join(' | ') }`; const text = ` ${events.map((event) => genEvent(name, event)).join('\n')} ${eventType} -${genSmartContract(name, abi)} -${genMigrationSmartContract(name, abi)}`; +${genSmartContract(name, manifest)} +${genMigrationSmartContract(name, manifest)}`; const importClauses = getImportClauses(text); // tslint:disable-next-line no-array-mutation diff --git a/packages/neo-one-smart-contract-codegen/src/types/hasForward.ts b/packages/neo-one-smart-contract-codegen/src/types/hasForward.ts index 998f6c68d1..de3c1cc2b6 100644 --- a/packages/neo-one-smart-contract-codegen/src/types/hasForward.ts +++ b/packages/neo-one-smart-contract-codegen/src/types/hasForward.ts @@ -1,6 +1,6 @@ -import { ABIFunction } from '@neo-one/client-common'; +import { ContractMethodDescriptorClient } from '@neo-one/client-common'; -export const hasForward = ({ parameters }: ABIFunction) => +export const hasForward = ({ parameters }: ContractMethodDescriptorClient) => parameters !== undefined && parameters.length > 0 && parameters[parameters.length - 1].rest && diff --git a/packages/neo-one-smart-contract-codegen/src/utils/toTypeScriptType.ts b/packages/neo-one-smart-contract-codegen/src/utils/toTypeScriptType.ts index 009dacfe8a..af3b0d5b11 100644 --- a/packages/neo-one-smart-contract-codegen/src/utils/toTypeScriptType.ts +++ b/packages/neo-one-smart-contract-codegen/src/utils/toTypeScriptType.ts @@ -20,6 +20,7 @@ export const toTypeScriptType = ( case 'Boolean': return addOptions('boolean'); case 'Address': + case 'Hash160': return addOptions('AddressString'); case 'Hash256': return addOptions('Hash256String'); @@ -44,6 +45,8 @@ export const toTypeScriptType = ( ) .join('\n')} }`); + case 'Any': + return 'any'; case 'Void': return 'undefined'; case 'Integer': diff --git a/packages/neo-one-smart-contract-compiler/src/DiagnosticMessage.ts b/packages/neo-one-smart-contract-compiler/src/DiagnosticMessage.ts index a238058aaa..e4e550304c 100644 --- a/packages/neo-one-smart-contract-compiler/src/DiagnosticMessage.ts +++ b/packages/neo-one-smart-contract-compiler/src/DiagnosticMessage.ts @@ -20,7 +20,12 @@ export enum DiagnosticMessage { InvalidContractEventArgStringLiteral = 'Invalid SmartContract event. Argument must be a string literal.', InvalidContractEventDeclaration = 'Invalid SmartContract event. Event must be assigned to a variable.', InvalidContractPropertiesMissing = 'Invalid SmartContract. Properties must be defined.', + InvalidContractPropertiesWarning = 'Invalid SmartContract. Properties should be defined.', InvalidContractPropertiesInitializer = 'Invalid SmartContract. Properties must be defined with an object literal of literal properties.', + InvalidContractPropertyPayableNep5 = 'Invalid SmartContract. Detected a NEP5 contract with payable. A NEP5 contract must be payable to accept assets. Set payable property to `true`.', + InvalidContractPropertyTrusts = 'Invalid SmartContract. Property `properties.trusts` must be a wildcard string ("*") or an array of valid UInt160 hex strings', + InvalidContractPropertyPermissions = 'Invalid SmartContract. Property `properties.permissions` must be a valid array of permission objects', + InvalidContractPropertyGroups = 'Invalid SmartContract. Property `properties.groups` must be a valid array of contract group objects', InvalidContractMethodMultipleSignatures = 'Invalid SmartContract method. Method must have one call signature', InvalidContractConstructor = 'Expected a single constructor declaration', InvalidContractExtends = 'Expected a single class declaration', @@ -40,6 +45,7 @@ export enum DiagnosticMessage { ResolveOneType = 'Expected type to resolve to one known type', InvalidAddress = 'Argument to Address.from must be a string literal address.', InvalidHash256 = 'Argument to Hash256.from must be a string literal hash256.', + InvalidHash160 = 'Argument to Hash160.from must be a string literal hash160.', InvalidPublicKey = 'Argument to PublicKey.from must be a string literal publicKey.', EventNotifierArguments = 'The arguments to createEventNotifier must be string literals.', InvalidBuiltinCall = 'Value is not callable.', diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/hashes.ts b/packages/neo-one-smart-contract-compiler/src/__data__/hashes.ts new file mode 100644 index 0000000000..7cb2920dd5 --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/__data__/hashes.ts @@ -0,0 +1,4 @@ +export const hashes = { + OLD_NEO_ASSET_HASH: '0xc56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b', + OLD_GAS_ASSET_HASH: '0x602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7', +}; diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/compile.ts b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/compile.ts index eb98021501..1bbb20d6c2 100644 --- a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/compile.ts +++ b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/compile.ts @@ -12,8 +12,8 @@ type ExpectOptions = | { readonly type: 'error'; readonly code?: DiagnosticCode } | { readonly type: 'warning'; readonly code?: DiagnosticCode }; -const compile = (context: Context, sourceFile: ts.SourceFile, options: ExpectOptions) => { - compileScript({ context, sourceFile }); +const compile = async (context: Context, sourceFile: ts.SourceFile, options: ExpectOptions) => { + await compileScript({ context, sourceFile }); const expectDiagnostic = (category: ts.DiagnosticCategory) => { const diag = context.diagnostics.find( @@ -36,13 +36,13 @@ const compile = (context: Context, sourceFile: ts.SourceFile, options: ExpectOpt } }; -export const compileString = (code: string, options: ExpectOptions): void => { +export const compileString = async (code: string, options: ExpectOptions): Promise => { const { context, sourceFile } = createContextForSnippet(code, createCompilerHost()); - compile(context, sourceFile, options); + await compile(context, sourceFile, options); }; -export const compileSnippet = (snippetPath: string, options: ExpectOptions): void => { +export const compileSnippet = async (snippetPath: string, options: ExpectOptions): Promise => { const dir = pathResolve( appRootDir.get(), 'packages', @@ -54,5 +54,5 @@ export const compileSnippet = (snippetPath: string, options: ExpectOptions): voi const context = createContextForPath(snippetPath, createCompilerHost()); const sourceFile = tsUtils.file.getSourceFileOrThrow(context.program, pathResolve(dir, snippetPath)); - compile(context, sourceFile, options); + await compile(context, sourceFile, options); }; diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/execute.ts b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/execute.ts index 12909a75c9..baf63593ac 100644 --- a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/execute.ts +++ b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/execute.ts @@ -16,7 +16,7 @@ const execute = async ( const { contract: { script: compiledCode }, sourceMap, - } = compile({ context, sourceFile }); + } = await compile({ context, sourceFile }); const { receipt, sourceMaps } = await executeScript(context.diagnostics, compiledCode, sourceMap, options); await checkResult(receipt, sourceMaps, true); diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/executeScript.ts b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/executeScript.ts index 6ba12f7cca..8cda13968a 100644 --- a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/executeScript.ts +++ b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/executeScript.ts @@ -1,14 +1,21 @@ -import { CallReceiptJSON, common, crypto, scriptHashToAddress, SourceMaps } from '@neo-one/client-common'; +import { + CallReceiptJSON, + common, + crypto, + scriptHashToAddress, + SourceMaps, + toVMStateJSON, +} from '@neo-one/client-common'; import { Blockchain } from '@neo-one/node-blockchain'; +import { NativeContainer } from '@neo-one/node-native'; import { test as testNet } from '@neo-one/node-neo-settings'; import { storage } from '@neo-one/node-storage-levelup'; -import { Dispatcher, blockchainSettingsToProtocolSettings } from '@neo-one/node-vm'; +import { blockchainSettingsToProtocolSettings, Dispatcher } from '@neo-one/node-vm'; import LevelUp from 'levelup'; import MemDown from 'memdown'; import { RawSourceMap } from 'source-map'; import ts from 'typescript'; import { throwOnDiagnosticErrorOrWarning } from '../../utils'; -import { NativeContainer } from '@neo-one/node-native'; export interface ExecuteOptions { readonly prelude?: Buffer; @@ -49,11 +56,18 @@ export const executeScript = async ( const address = scriptHashToAddress(common.uInt160ToString(crypto.toScriptHash(code))); await blockchain.stop(); - // TODO: pickup here, how are we converting this? return { receipt: { - result: receipt, - actions: receipt.actions.map((action) => action.serializeJSON(blockchain.serializeJSONContext)), + script: compiledCode, + state: toVMStateJSON(receipt.state), + gasconsumed: receipt.gasConsumed.toString(), + stack: receipt.stack.map((stackItem, _) => stackItem.toContractParameter().serializeJSON()), + notifications: receipt.notifications.map((n) => n.serializeJSON()), + logs: receipt.logs.map((log) => ({ + message: log.message, + containerhash: log.containerHash ? common.uInt256ToString(log.containerHash) : undefined, + callingscripthash: common.uInt160ToString(log.callingScriptHash), + })), }, sourceMaps: { [address]: resolvedSourceMap, diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/extractors.ts b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/extractors.ts index 11b88fd733..0b4ba210a9 100644 --- a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/extractors.ts +++ b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/extractors.ts @@ -17,24 +17,20 @@ export const checkRawResult = async (receipt: RawCallReceipt, sourceMaps: Source if (receipt.state === 'FAULT') { enableConsoleLogForTest(); try { - // TODO: reimplement this message processing - // const message = await processActionsAndMessage({ - // actions: receipt.actions, - // message: receipt.message, - // sourceMaps, - // }); - - throw new Error(receipt.stack as string); + const message = await processActionsAndMessage({ + actions: [...receipt.notifications, ...receipt.logs], + sourceMaps, + }); + throw new Error(message); } finally { disableConsoleLogForTest(); } } - // TODO: reimplement this log processing - // await processConsoleLogMessages({ - // actions: receipt.actions, - // sourceMaps, - // }); + await processConsoleLogMessages({ + actions: [...receipt.notifications, ...receipt.logs], + sourceMaps, + }); if (checkStack && receipt.stack.length !== 0) { throw new Error(`Found leftover stack items, length: ${receipt.stack.length}`); diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/getClients.ts b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/getClients.ts index 6aaa21f3a5..a973ce027e 100644 --- a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/getClients.ts +++ b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/getClients.ts @@ -11,10 +11,10 @@ export const getClients = async ({ privateKey, dataProvider }: Options) => { const masterWalletName = 'master'; const keystore = new LocalKeyStore(new LocalMemoryStore()); - const masterWallet = await keystore.addUserAccount({ + const masterWallet = await keystore.addMultiSigUserAccount({ network: networkName, name: masterWalletName, - privateKey, + privateKeys: [privateKey], }); const provider = new NEOONEProvider([dataProvider]); diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/startNode.ts b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/startNode.ts index 04b4c409a3..79e5eb0fd2 100644 --- a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/startNode.ts +++ b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/startNode.ts @@ -3,28 +3,41 @@ import { common, Contract, + ContractABI, + ContractMethodDescriptorClient, crypto, - InvocationResult, RawInvokeReceipt, scriptHashToAddress, SmartContractDefinition, SourceMaps, - UserAccountID, Transaction, - ContractABI, + UserAccountID, } from '@neo-one/client-common'; -import { DeveloperClient, LocalKeyStore, LocalWallet, NEOONEDataProvider, SmartContract } from '@neo-one/client-core'; -import { Client, InvokeExecuteTransactionOptions, ReadClient } from '@neo-one/client-full-core'; +import { + DeveloperClient, + LocalKeyStore, + LocalWallet, + NEOONEDataProvider, + NEOONEProvider, + SmartContract, +} from '@neo-one/client-core'; +import { + Client, + ContractRegister, + InvokeExecuteTransactionOptions, + LocalUserAccountProvider, + ReadClient, +} from '@neo-one/client-full-core'; import { createCompilerHost, pathResolve } from '@neo-one/smart-contract-compiler-node'; import { tsUtils } from '@neo-one/ts-utils'; import { Modifiable } from '@neo-one/utils'; import * as appRootDir from 'app-root-dir'; import BigNumber from 'bignumber.js'; import ts from 'typescript'; +import { createNode } from '../../../../neo-one-smart-contract-test/src/createNode'; import { compile } from '../../compile'; import { CompileResult, LinkedContracts } from '../../compile/types'; import { Context } from '../../Context'; -import { createNode } from '@neo-one/smart-contract-test'; import { createContextForPath, createContextForSnippet } from '../../createContext'; import { throwOnDiagnosticErrorOrWarning } from '../../utils'; import { checkRawResult } from './extractors'; @@ -42,10 +55,14 @@ export interface Result { interface AddContractOptions { readonly fileName?: string; + readonly manifestMethods?: readonly ContractMethodDescriptorClient[]; } export interface TestNode { - readonly addContract: (script: string, options?: AddContractOptions) => Promise; + readonly addContract: ( + script: string, + options?: AddContractOptions, + ) => Promise<{ readonly contract: Contract; readonly address: string }>; readonly addContractWithDefinition: ( script: string, options?: AddContractOptions, @@ -60,12 +77,13 @@ export interface TestNode { readonly transaction: Transaction; readonly sourceMaps: SourceMaps; }>; - readonly compileScript: (script: string) => CompileResult; + readonly compileScript: (script: string) => Promise; readonly masterWallet: LocalWallet; readonly client: Client; readonly readClient: ReadClient; readonly developerClient: DeveloperClient; readonly sourceMaps: SourceMaps; + readonly userAccountProviders: { readonly memory: LocalUserAccountProvider }; } export interface Options { @@ -79,13 +97,7 @@ export interface StartNodeOptions { readonly ignoreWarnings?: boolean; } -// execute string -export interface InvokeValidateResultOptions { - readonly result: InvocationResult; - readonly developerClient: DeveloperClient; -} - -const getCompiledScript = (script: string, fileName?: string): CompileResult => { +const getCompiledScript = async (script: string, fileName?: string): Promise => { const { context, sourceFile } = createContextForSnippet(script, createCompilerHost(), { fileName, withTestHarness: true, @@ -98,23 +110,15 @@ const publish = async ( client: Client, developerClient: DeveloperClient, context: Context, - code: string, + contract: ContractRegister, ignoreWarnings?: boolean, ): Promise => { throwOnDiagnosticErrorOrWarning(context.diagnostics, ignoreWarnings); const result = await client.publish({ - script: code, - parameters: ['String', 'Array'], - returnType: 'Buffer', - name: 'TestContract', - codeVersion: '1.0', - author: 'test', - email: 'test@test.com', - description: 'test', - storage: true, - dynamicInvoke: true, - payable: true, + script: contract.script, + manifest: contract.manifest, + name: contract.name, }); const [publishReceipt] = await Promise.all([ @@ -140,46 +144,49 @@ export const startNode = async (outerOptions: StartNodeOptions = {}): Promise { + // tslint:disable-next-line: no-object-mutation options.maxNetworkFee = new BigNumber(-1); + // tslint:disable-next-line: no-object-mutation options.maxSystemFee = new BigNumber(-1); }); return { - async addContract(script, options = {}): Promise { - const { - contract: { script: outputScript }, - context, - sourceMap, - } = getCompiledScript(script, options.fileName); + async addContract( + script, + options = {}, + ): Promise<{ + readonly contract: Contract; + readonly address: string; + }> { + const { contract, context, sourceMap } = await getCompiledScript(script, options.fileName); const [result, resolvedSourceMap] = await Promise.all([ - publish(client, developerClient, context, outputScript, outerOptions.ignoreWarnings), + publish(client, developerClient, context, contract, outerOptions.ignoreWarnings), sourceMap, ]); mutableSourceMaps[result.hash] = resolvedSourceMap; - return result; + return { contract: result, address: scriptHashToAddress(result.manifest.abi.hash) }; }, async addContractWithDefinition( script, options = {}, ): Promise<{ contract: Contract; definition: SmartContractDefinition }> { - const { - contract: { script: outputScript }, - context, - sourceMap, - abi, - } = getCompiledScript(script, options.fileName); + const { contract, context, sourceMap } = await getCompiledScript(script, options.fileName); const [result, resolvedSourceMap] = await Promise.all([ - publish(client, developerClient, context, outputScript, outerOptions.ignoreWarnings), + publish(client, developerClient, context, contract, outerOptions.ignoreWarnings), sourceMap, ]); mutableSourceMaps[result.hash] = resolvedSourceMap; return { contract: result, - definition: createContractDefinition(result, mutableSourceMaps), + definition: { + manifest: contract.manifest, + networks: { [networkName]: { address: scriptHashToAddress(result.manifest.abi.hash) } }, + sourceMaps: mutableSourceMaps, + }, }; }, async addContractFromSnippet(snippetPath, linked = {}): Promise { @@ -194,13 +201,10 @@ export const startNode = async (outerOptions: StartNodeOptions = {}): Promise export const getUInt256Hash = (value: string) => `Buffer.from('${common.stringToUInt256(value).toString('hex')}', 'hex')`; export const getAddressHash = (value: string) => getUInt160Hash(addressToScriptHash(value)); -export const getBufferHash = (value: string) => `Buffer.from('${value}', 'hex')`; +export const getBufferHash = (value: string, encoding?: string) => `Buffer.from('${value}', '${encoding ?? 'hex'}')`; export const getBuffer = (value: Buffer) => `Buffer.from('${value.toString('hex')}', 'hex')`; export const getDecimal = (value: BigNumber) => common.fixed8FromDecimal(value).toString(10); diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/index.ts b/packages/neo-one-smart-contract-compiler/src/__data__/index.ts index 3c319ecf2d..b1ff372532 100644 --- a/packages/neo-one-smart-contract-compiler/src/__data__/index.ts +++ b/packages/neo-one-smart-contract-compiler/src/__data__/index.ts @@ -2,3 +2,4 @@ import * as helpers from './helpers'; export { helpers }; export * from './keys'; +export * from './hashes'; diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/keys.ts b/packages/neo-one-smart-contract-compiler/src/__data__/keys.ts index 011a134a12..1f70677981 100644 --- a/packages/neo-one-smart-contract-compiler/src/__data__/keys.ts +++ b/packages/neo-one-smart-contract-compiler/src/__data__/keys.ts @@ -15,7 +15,7 @@ export const keys: ReadonlyArray<{ }> = [ { name: 'first', - address: 'ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW', + address: 'NNWAo5vdVJz1oyCuNiaTBA3amBHnWCF4Yk', privateKey: common.bufferToPrivateKey( Buffer.from('7d128a6d096f0c14c3a25a2b0c41cf79661bfcb4a8cc95aaaea28bde4d732344', 'hex'), ), @@ -29,14 +29,12 @@ export const keys: ReadonlyArray<{ wif: 'L1QqQJnpBwbsPGAuutuzPTac8piqvbR1HRjrY5qHup48TBCBFe4g', password: 'city of zion', encryptedWIF: '6PYLHmDf6AjF4AsVtosmxHuPYeuyJL3SLuw7J1U8i7HxKAnYNsp61HYRfF', - scriptHash: common.bufferToUInt160(Buffer.from('3775292229eccdf904f16fff8e83e7cffdc0f0ce', 'hex')), - scriptHashString: common.uInt160ToString( - common.bufferToUInt160(Buffer.from('3775292229eccdf904f16fff8e83e7cffdc0f0ce', 'hex')), - ), + scriptHash: common.hexToUInt160('36a6e6a7c4658acf096f5d288cc81129c815681c'), + scriptHashString: '36a6e6a7c4658acf096f5d288cc81129c815681c', }, { name: 'second', - address: 'ALfnhLg7rUyL6Jr98bzzoxz5J7m64fbR4s', + address: 'NiwvMyWYeNghLG8tDyKkWwuZV3wS8CPrrV', privateKey: common.bufferToPrivateKey( Buffer.from('9ab7e154840daca3a2efadaf0df93cd3a5b51768c632f5433f86909d9b994a69', 'hex'), ), @@ -50,14 +48,12 @@ export const keys: ReadonlyArray<{ wif: 'L2QTooFoDFyRFTxmtiVHt5CfsXfVnexdbENGDkkrrgTTryiLsPMG', password: '我的密码', encryptedWIF: '6PYWVp3xfgvnuNKP7ZavSViYvvim2zuzx9Q33vuWZr8aURiKeJ6Zm7BfPQ', - scriptHash: common.bufferToUInt160(Buffer.from('35b20010db73bf86371075ddfba4e6596f1ff35d', 'hex')), - scriptHashString: common.uInt160ToString( - common.bufferToUInt160(Buffer.from('35b20010db73bf86371075ddfba4e6596f1ff35d', 'hex')), - ), + scriptHash: common.hexToUInt160('5461c33e9bbc7de7076754540ba9e62b255ea9fc'), + scriptHashString: '5461c33e9bbc7de7076754540ba9e62b255ea9fc', }, { name: 'third', - address: 'AVf4UGKevVrMR1j3UkPsuoYKSC4ocoAkKx', + address: 'NTWHAzB82LRGWNuuqjVyyzpGvF3WxbbPoG', privateKey: common.bufferToPrivateKey( Buffer.from('3edee7036b8fd9cef91de47386b191dd76db2888a553e7736bb02808932a915b', 'hex'), ), @@ -71,10 +67,8 @@ export const keys: ReadonlyArray<{ wif: 'KyKvWLZsNwBJx5j9nurHYRwhYfdQUu9tTEDsLCUHDbYBL8cHxMiG', password: 'MyL33tP@33w0rd', encryptedWIF: '6PYNoc1EG5J38MTqGN9Anphfdd6UwbS4cpFCzHhrkSKBBbV1qkbJJZQnkn', - scriptHash: common.bufferToUInt160(Buffer.from('9847e26135152874355e324afd5cc99f002acb33', 'hex')), - scriptHashString: common.uInt160ToString( - common.bufferToUInt160(Buffer.from('9847e26135152874355e324afd5cc99f002acb33', 'hex')), - ), + scriptHash: common.hexToUInt160('a38db239bb36ace1a69eb727a5b0157baa094653'), + scriptHashString: 'a38db239bb36ace1a69eb727a5b0157baa094653', }, ]; diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/snippets/linked/Bar.ts b/packages/neo-one-smart-contract-compiler/src/__data__/snippets/linked/Bar.ts index 88c6fcc8f3..ec07db9e79 100644 --- a/packages/neo-one-smart-contract-compiler/src/__data__/snippets/linked/Bar.ts +++ b/packages/neo-one-smart-contract-compiler/src/__data__/snippets/linked/Bar.ts @@ -4,10 +4,9 @@ import { Foo } from './Foo'; export class Bar extends SmartContract { public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'Bar', + groups: [], + permissions: [], + trusts: '*', }; public getFoo(expected: Address): string { diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/snippets/linked/Foo.ts b/packages/neo-one-smart-contract-compiler/src/__data__/snippets/linked/Foo.ts index 069f65d13f..712280c5cc 100644 --- a/packages/neo-one-smart-contract-compiler/src/__data__/snippets/linked/Foo.ts +++ b/packages/neo-one-smart-contract-compiler/src/__data__/snippets/linked/Foo.ts @@ -3,10 +3,9 @@ import { SmartContract } from '@neo-one/smart-contract'; export class Foo extends SmartContract { public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'Foo', + groups: [], + permissions: [], + trusts: '*', }; public getFoo(): string { diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/snippets/semantic/single/complex.ts b/packages/neo-one-smart-contract-compiler/src/__data__/snippets/semantic/single/complex.ts index 2aad39c273..43115f5745 100644 --- a/packages/neo-one-smart-contract-compiler/src/__data__/snippets/semantic/single/complex.ts +++ b/packages/neo-one-smart-contract-compiler/src/__data__/snippets/semantic/single/complex.ts @@ -25,10 +25,9 @@ const notifyRefund = createEventNotifier('refund'); // tslint:disable-next-line export-name export class ICO extends SmartContract { public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'NEO•ONE ICO', + trusts: '*', + groups: [], + permissions: [], }; public readonly name = 'One'; public readonly symbol = 'ONE'; @@ -98,36 +97,34 @@ export class ICO extends SmartContract { throw new Error('Invalid mintTokens'); } - const { references } = Blockchain.currentTransaction; - if (references.length === 0) { - throw new Error('Invalid mintTokens'); - } - const sender = references[0].address; - - let amount = 0; - // tslint:disable-next-line no-loop-statement - for (const output of Blockchain.currentTransaction.outputs) { - if (output.address.equals(this.owner)) { - if (!output.asset.equals(Hash256.NEO)) { - notifyRefund(); - - throw new Error('Invalid mintTokens'); - } - - amount += output.value * this.amountPerNEO; - } - } - - if (amount > this.remaining) { - notifyRefund(); - - throw new Error('Invalid mintTokens'); - } - - this.balances.set(sender, this.balanceOf(sender) + amount); - this.mutableRemaining -= amount; - this.mutableSupply += amount; - notifyTransfer(undefined, sender, amount); + // Outputs represent the destination addresses and amounts for native assets + // A reference is a corresponding output for the inputs of the transaction + // Now we want to use notifications to check if transfers were sent to this contract + // const { notifications, sender } = Blockchain.currentTransaction; + + // // Here we're getting the amount of NEO sent to the contract + // let amount = 0; + // // tslint:disable-next-line no-loop-statement + // for (const notification of notifications) { + // // Every notification we check that the transferTo address is to this contract + // if (notification.state[1].equals(this.address)) { + // // Only distribute for NEO received + // if (notification.scriptHash.equals(Hash256.NEO)) { + // amount += notification[2] * this.amountPerNEO; + // } + // } + // } + + // if (amount > this.remaining) { + // notifyRefund(); + + // throw new Error('Invalid mintTokens'); + // } + + // this.balances.set(sender, this.balanceOf(sender) + amount); + // this.mutableRemaining -= amount; + // this.mutableSupply += amount; + // notifyTransfer(undefined, sender, amount); } private hasStarted(): boolean { diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/snippets/semantic/single/valid.ts b/packages/neo-one-smart-contract-compiler/src/__data__/snippets/semantic/single/valid.ts index 58f7c57550..444a1717d8 100644 --- a/packages/neo-one-smart-contract-compiler/src/__data__/snippets/semantic/single/valid.ts +++ b/packages/neo-one-smart-contract-compiler/src/__data__/snippets/semantic/single/valid.ts @@ -47,16 +47,16 @@ interface TokenPayableContract { // tslint:disable-next-line export-name export class One extends SmartContract { public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'NEO•ONE ICO', + trusts: '*', + groups: [], + permissions: [], }; public readonly name = 'One'; public readonly symbol = 'ONE'; public readonly decimals = 8; public readonly amountPerNEO = 100_000; private readonly balances = MapStorage.for>(); + // tslint:disable-next-line: readonly-array private readonly approvedTransfers = MapStorage.for<[Address, Address], Fixed<8>>(); private mutableRemaining: Fixed<8> = 10_000_000_000_00000000; private mutableSupply: Fixed<8> = 0; @@ -189,30 +189,30 @@ export class One extends SmartContract { throw new Error('Invalid mintTokens'); } - const { references } = Blockchain.currentTransaction; - if (references.length === 0) { - throw new Error('Invalid mintTokens'); - } - const sender = references[0].address; - - let amount = 0; - // tslint:disable-next-line no-loop-statement - for (const output of Blockchain.currentTransaction.outputs) { - if (output.address.equals(this.address)) { - if (!output.asset.equals(Hash256.NEO)) { - throw new Error('Invalid mintTokens'); - } - - amount += output.value * this.amountPerNEO; - } - } - - if (amount > this.remaining) { - throw new Error('Invalid mintTokens'); - } - - this.mutableRemaining -= amount; - this.issue(sender, amount); + // Outputs represent the destination addresses and amounts for native assets + // A reference is a corresponding output for the inputs of the transaction + // Now we want to use notifications to check if transfers were sent to this contract + // const { notifications, sender } = Blockchain.currentTransaction; + + // // Here we're getting the amount of NEO sent to the contract + // let amount = 0; + // // tslint:disable-next-line no-loop-statement + // for (const notification of notifications) { + // // Every notification we check that the transferTo address is to this contract + // if (notification.state[1].equals(this.address)) { + // // Only distribute for NEO received + // if (notification.scriptHash.equals(Hash256.NEO)) { + // amount += notification[2] * this.amountPerNEO; + // } + // } + // } + + // if (amount > this.remaining) { + // throw new Error('Invalid mintTokens'); + // } + + // this.mutableRemaining -= amount; + // this.issue(sender, amount); } private issue(addr: Address, amount: Fixed<8>): void { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/arguments/__snapshots__/index.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/arguments/__snapshots__/index.test.ts.snap deleted file mode 100644 index a4094b9222..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/arguments/__snapshots__/index.test.ts.snap +++ /dev/null @@ -1,25 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`IArguments cannot be implemented 1`] = ` -"snippetCode.ts (2,13): Class 'MyArray' incorrectly implements interface 'IArguments'. - Property '[one0]' is missing in type 'MyArray' but required in type 'IArguments'. - - 1 | - > 2 | class MyArray implements IArguments { - | ^ - 3 | } - 4 | -" -`; - -exports[`IArguments cannot be referenced 1`] = ` -"snippetCode.ts (3,19): Builtins cannot be referenced - - 1 | - 2 | const y = () => { - > 3 | const x = arguments; - | ^ - 4 | } - 5 | -" -`; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/arguments/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/arguments/index.test.ts deleted file mode 100644 index ed7ab51c0c..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/arguments/index.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { helpers } from '../../../../__data__'; -import { DiagnosticCode } from '../../../../DiagnosticCode'; - -describe('IArguments', () => { - test('cannot be implemented', async () => { - helpers.compileString( - ` - class MyArray implements IArguments { - } - `, - { type: 'error' }, - ); - }); - - test.skip('cannot be referenced', async () => { - helpers.compileString( - ` - const y = () => { - const x = arguments; - } - `, - { type: 'error', code: DiagnosticCode.InvalidBuiltinReference }, - ); - }); -}); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/concat.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/concat.test.ts index 4ae5206fe7..c2a21d4446 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/concat.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/concat.test.ts @@ -70,7 +70,7 @@ describe('Array.prototype.concat', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x: ReadonlyArray = [0, 1, 2]; const y = x.concat; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/entries.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/entries.test.ts index 58863860a2..492b0e295b 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/entries.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/entries.test.ts @@ -88,7 +88,7 @@ describe('Array.prototype.entries', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x: ReadonlyArray = [0, 1, 2]; const y = x.entries; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/every.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/every.test.ts index 2aaccc5362..3677471ea8 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/every.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/every.test.ts @@ -20,6 +20,15 @@ describe('Array.prototype.every', () => { `); }); + test('should apply a function over an array - all false', async () => { + await helpers.executeString(` + const x = [0, 1, 2]; + const y = x.every((value) => false); + + assertEqual(y, false); + `); + }); + test('should apply a function over an array with index', async () => { await helpers.executeString(` const x = [1, 2, 3]; @@ -57,7 +66,7 @@ describe('Array.prototype.every', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x.every; @@ -67,7 +76,7 @@ describe('Array.prototype.every', () => { }); test('cannot be "referenced"', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x['every']; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/filter.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/filter.test.ts index 56ac551a98..8feb0ef4a2 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/filter.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/filter.test.ts @@ -40,7 +40,7 @@ describe('Array.prototype.filter', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x.filter; @@ -50,7 +50,7 @@ describe('Array.prototype.filter', () => { }); test('cannot be "referenced"', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x['filter']; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/forEach.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/forEach.test.ts index 1c839733e0..e4fe6ef9c2 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/forEach.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/forEach.test.ts @@ -30,7 +30,7 @@ describe('Array.prototype.forEach', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x.forEach; @@ -40,7 +40,7 @@ describe('Array.prototype.forEach', () => { }); test('cannot be "referenced"', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x['forEach']; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/index.test.ts index c8324dd797..4526e89475 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/index.test.ts @@ -12,7 +12,7 @@ describe('Array', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` class MyArray extends Array { } @@ -43,7 +43,7 @@ describe('Array', () => { }); test('cannot be ambiguously referenced - call', async () => { - helpers.compileString( + await helpers.compileString( ` interface Arr { readonly length: number; @@ -58,7 +58,7 @@ describe('Array', () => { }); test('cannot be ambiguously referenced - variable', async () => { - helpers.compileString( + await helpers.compileString( ` interface Arr { readonly length: number; @@ -71,7 +71,7 @@ describe('Array', () => { }); test('cannot be ambiguously referenced - assignment', async () => { - helpers.compileString( + await helpers.compileString( ` interface Arr { readonly length: number; @@ -105,7 +105,7 @@ describe('Array', () => { }); test('cannot be ambiguously referenced - arrow return value', async () => { - helpers.compileString( + await helpers.compileString( ` interface Arr { readonly length: number; @@ -149,7 +149,7 @@ describe('Array', () => { }); test('cannot be ambiguously referenced - function return value', async () => { - helpers.compileString( + await helpers.compileString( ` interface Arr { readonly length: number; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/iterator.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/iterator.test.ts index 49341d08e6..737d408a62 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/iterator.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/iterator.test.ts @@ -80,7 +80,7 @@ describe('Array.prototype[Symbol.iterator]', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x[Symbol.iterator]; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/join.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/join.test.ts index d68f69debc..2456f72d64 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/join.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/join.test.ts @@ -31,7 +31,7 @@ describe('Array.prototype.join', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x: ReadonlyArray = [0, 1, 2]; const y = x.join; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/length.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/length.test.ts index 386fe9b0ca..2f59e97d26 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/length.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/length.test.ts @@ -23,7 +23,7 @@ describe('Array.prototype.length', () => { }); test('cannot set the length of an array', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [1, 2, 3]; x.length = 4; @@ -33,7 +33,7 @@ describe('Array.prototype.length', () => { }); test('cannot set the "length" of an array', async () => { - helpers.compileString( + await helpers.compileString( ` const x: { length: number } | Array = [1, 2, 3] as { length: number } | Array; const a = 'length'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/map.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/map.test.ts index b77a225f25..d01e7c7e04 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/map.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/map.test.ts @@ -55,7 +55,7 @@ describe('Array.prototype.map', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x.map; @@ -65,7 +65,7 @@ describe('Array.prototype.map', () => { }); test('cannot be "referenced"', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x['map']; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/pop.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/pop.test.ts index 3c5318cc72..c6b5f6f948 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/pop.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/pop.test.ts @@ -25,7 +25,7 @@ describe('Array.prototype.pop', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x.pop; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/push.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/push.test.ts index dc126448fc..d8f7ce4d1e 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/push.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/push.test.ts @@ -44,7 +44,7 @@ describe('Array.prototype.push', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x.push; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/reduce.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/reduce.test.ts index 66505b5d50..225317924c 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/reduce.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/reduce.test.ts @@ -36,7 +36,7 @@ describe('Array.prototype.reduce', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x.reduce; @@ -46,7 +46,7 @@ describe('Array.prototype.reduce', () => { }); test('cannot be set', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; x.reduce = () => 0; @@ -56,7 +56,7 @@ describe('Array.prototype.reduce', () => { }); test('cannot be "set"', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; x['reduce'] = () => 0; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/slice.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/slice.test.ts index 3170f06539..45c58d3482 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/slice.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/slice.test.ts @@ -119,7 +119,7 @@ describe('Array.prototype.slice', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [1, 2, 3, 4]; const y = x.slice; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/some.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/some.test.ts index 559b5afcf7..7d34436014 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/some.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/some.test.ts @@ -57,7 +57,7 @@ describe('Array.prototype.some', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x.some; @@ -67,7 +67,7 @@ describe('Array.prototype.some', () => { }); test('cannot be "referenced"', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2]; const y = x['some']; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/toString.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/toString.test.ts index b80c58d866..150dc7170d 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/toString.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/array/toString.test.ts @@ -12,7 +12,7 @@ describe('Array.prototype.toString', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x: ReadonlyArray = [0, 1, 2]; const y = x.toString; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/boolean/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/boolean/index.test.ts index f082c78c7a..6ab9145dc0 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/boolean/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/boolean/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../__data__'; describe('Boolean', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` class MyBoolean implements Boolean { } @@ -12,7 +12,7 @@ describe('Boolean', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` class MyBoolean extends Boolean { } diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/concat.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/concat.test.ts index ad60850593..d7a2bc1d64 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/concat.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/concat.test.ts @@ -35,7 +35,7 @@ describe('Buffer.concat', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const keys = Buffer.concat; `, @@ -44,7 +44,7 @@ describe('Buffer.concat', () => { }); test('cannot be set', async () => { - helpers.compileString( + await helpers.compileString( ` Buffer.concat = (list: Buffer[]) => Buffer.from('', 'hex'); `, @@ -53,7 +53,7 @@ describe('Buffer.concat', () => { }); test('cannot be "referenced"', async () => { - helpers.compileString( + await helpers.compileString( ` const keys = Buffer['concat']; `, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/equals.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/equals.test.ts index b54c50af52..e331b6b9fe 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/equals.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/equals.test.ts @@ -23,7 +23,7 @@ describe('Buffer.prototype.equals', () => { }); test('cannot be set', async () => { - helpers.compileString( + await helpers.compileString( ` const x = Buffer.from('5946158ab93f5f4fd6ba230f1c6c235117eec5f83e65275ac6f93ada9ca60477', 'hex'); x.equals = (otherBuffer: Buffer) => true; @@ -33,7 +33,7 @@ describe('Buffer.prototype.equals', () => { }); test('cannot be "set"', async () => { - helpers.compileString( + await helpers.compileString( ` const x = Buffer.from('5946158ab93f5f4fd6ba230f1c6c235117eec5f83e65275ac6f93ada9ca60477', 'hex'); x['equals'] = (otherBuffer: Buffer) => true; @@ -43,7 +43,7 @@ describe('Buffer.prototype.equals', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = Buffer.from('5946158ab93f5f4fd6ba230f1c6c235117eec5f83e65275ac6f93ada9ca60477', 'hex'); const y = x.equals; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/from.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/from.test.ts index fb8ef2ea15..aca9aa37a0 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/from.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/from.test.ts @@ -33,7 +33,7 @@ describe('Buffer.from', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const keys = Buffer.from; `, @@ -42,7 +42,7 @@ describe('Buffer.from', () => { }); test('cannot be element referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const keys = Buffer['from']; `, @@ -51,7 +51,7 @@ describe('Buffer.from', () => { }); test('non-string is unsupported', async () => { - helpers.compileString( + await helpers.compileString( ` Buffer.from([]); `, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/index.test.ts index 4ce2db2cc6..1c8216de38 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../__data__'; describe('Buffer', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` class MyBuffer implements Buffer { } @@ -12,7 +12,7 @@ describe('Buffer', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` class MyBuffer extends Buffer { } diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/length.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/length.test.ts index 67b9a1a3a7..232859be13 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/length.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/length.test.ts @@ -23,7 +23,7 @@ describe('Buffer.prototype.length', () => { }); test('cannot set the length of a buffer', async () => { - helpers.compileString( + await helpers.compileString( ` const x = Buffer.from('3030', 'hex'); x.length = 4; @@ -33,7 +33,7 @@ describe('Buffer.prototype.length', () => { }); test('cannot set the "length" of a buffer', async () => { - helpers.compileString( + await helpers.compileString( ` const x: { length: number } | Buffer = Buffer.from('3030', 'hex') as { length: number } | Buffer; const a = 'length'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/slice.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/slice.test.ts index 066cc56487..5f6fdb7b57 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/slice.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/slice.test.ts @@ -120,7 +120,7 @@ describe('Buffer.prototype.slice', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = ${helpers.getBuffer(buffer)}; const y = x.slice; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/toInteger.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/toInteger.test.ts index 28a60170d2..f16ea67ba8 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/toInteger.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/toInteger.test.ts @@ -35,7 +35,7 @@ describe('Buffer.prototype.toInteger', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = Buffer.from('5946158ab93f5f4fd6ba230f1c6c235117eec5f83e65275ac6f93ada9ca60477', 'hex'); const y = x.toInteger; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/toString.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/toString.test.ts index 3285eb8ae0..4b399ea575 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/toString.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/buffer/toString.test.ts @@ -31,7 +31,7 @@ describe('Buffer.prototype.toString', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = Buffer.from('5946158ab93f5f4fd6ba230f1c6c235117eec5f83e65275ac6f93ada9ca60477', 'hex'); const y = x.toString; @@ -41,7 +41,7 @@ describe('Buffer.prototype.toString', () => { }); test('cannot have argument other than utf8', async () => { - helpers.compileString( + await helpers.compileString( ` Buffer.from('5946158ab93f5f4fd6ba230f1c6c235117eec5f83e65275ac6f93ada9ca60477', 'hex').toString('hex'); `, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/console/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/console/index.test.ts index 36faf564bf..a9b56cddb5 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/console/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/console/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../__data__'; describe('console', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` class MyConsole implements Console { } @@ -12,7 +12,7 @@ describe('console', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` class MyFunction extends Console { } diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/console/log.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/console/log.test.ts index e91b283ac9..2327b9ea52 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/console/log.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/console/log.test.ts @@ -7,9 +7,17 @@ import { DiagnosticCode } from '../../../../DiagnosticCode'; const getMessages = async (receiptIn: CallReceiptJSON, sourceMaps: SourceMaps): Promise> => { const receipt = convertCallReceipt(receiptIn); - return createConsoleLogMessages(receipt.actions, sourceMaps, { onlyFileName: true }); + return createConsoleLogMessages([...receipt.notifications, ...receipt.logs], sourceMaps, { onlyFileName: true }); }; +const properties = ` + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; +`; + describe('console.log', () => { test('should log strings', async () => { const { receipt, sourceMaps } = await helpers.executeString(` @@ -118,6 +126,7 @@ describe('console.log', () => { }); test('should log objects', async () => { + // TODO const { receipt, sourceMaps } = await helpers.executeString(` console.log({ a: 'a', @@ -152,43 +161,60 @@ describe('console.log', () => { }); test('should handle logs across contracts', async () => { + // TODO const node = await helpers.startNode(); const firstContract = await node.addContract( ` - const bar = () => { - console.log('bar'); + import { SmartContract } from '@neo-one/smart-contract'; + + export class FirstContract extends SmartContract { + ${properties} + + public run(): void { + const bar = () => { + console.log('bar'); + } + const foo = () => { + console.log('calling bar'); + bar(); + console.log('done calling bar'); + }; + + console.log('calling foo'); + foo(); + console.log('done calling foo'); + } } - const foo = () => { - console.log('calling bar'); - bar(); - console.log('done calling bar'); - }; - - console.log('calling foo'); - foo(); - console.log('done calling foo'); `, - { fileName: 'firstContract.ts' }, + { + fileName: 'firstContract.ts', + }, ); const secondContract = await node.addContract( ` import { Address, SmartContract } from '@neo-one/smart-contract'; - interface Contract { - readonly run: () => void; + export class SecondContract extends SmartContract { + ${properties} + + public run(): void { + interface Contract { + readonly run: () => void; + } + + const invoke = () => { + console.log('calling run'); + const contract = SmartContract.for(Address.from('${firstContract.address}')); + contract.run(); + console.log('done calling run'); + }; + + console.log('calling invoke'); + invoke(); + console.log('done calling invoke'); + } } - - const invoke = () => { - console.log('calling run'); - const contract = SmartContract.for(Address.from('${firstContract.address}')); - contract.run(); - console.log('done calling run'); - }; - - console.log('calling invoke'); - invoke(); - console.log('done calling invoke'); `, { fileName: 'secondContract.ts' }, ); @@ -206,7 +232,7 @@ describe('console.log', () => { console.log('done'); `); - const messages = await createConsoleLogMessages(receipt.actions, sourceMaps, { + const messages = await createConsoleLogMessages([...receipt.notifications, ...receipt.logs], sourceMaps, { onlyFileName: true, }); @@ -214,7 +240,7 @@ describe('console.log', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const log = console.log; `, @@ -223,7 +249,7 @@ describe('console.log', () => { }); test('cannot be referenced - object literal', async () => { - helpers.compileString( + await helpers.compileString( ` const { log } = console; `, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/asset.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/asset.test.ts.snap deleted file mode 100644 index c762845c18..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/asset.test.ts.snap +++ /dev/null @@ -1,47 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Asset cannot be implemented 1`] = ` -"snippetCode.ts (4,13): Class 'MyAsset' incorrectly implements interface 'Asset'. - Type 'MyAsset' is missing the following properties from type 'Asset': hash, type, amount, available, and 5 more. - - 2 | import { Asset } from '@neo-one/smart-contract'; - 3 | - > 4 | class MyAsset implements Asset { - | ^ - 5 | } - 6 | -" -`; - -exports[`Asset invalid "reference" 1`] = ` -"snippetCode.ts (4,25): Builtin properties cannot be referenced - - 2 | import { Asset } from '@neo-one/smart-contract'; - 3 | - > 4 | const for = Asset['for']; - | ^ - 5 | -" -`; - -exports[`Asset invalid reference - object 1`] = ` -"snippetCode.ts (4,15): Builtin properties cannot be referenced - - 2 | import { Asset } from '@neo-one/smart-contract'; - 3 | - > 4 | const { for } = Asset; - | ^ - 5 | -" -`; - -exports[`Asset invalid reference 1`] = ` -"snippetCode.ts (4,25): Builtin properties cannot be referenced - - 2 | import { Asset } from '@neo-one/smart-contract'; - 3 | - > 4 | const for = Asset.for; - | ^ - 5 | -" -`; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/attribute.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/attribute.test.ts.snap index c2f2f8abe8..c405632bc4 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/attribute.test.ts.snap +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/attribute.test.ts.snap @@ -2,7 +2,7 @@ exports[`Attribute cannot be implemented 1`] = ` "snippetCode.ts (4,13): Class 'MyAttribute' incorrectly implements interface 'AttributeBase'. - Type 'MyAttribute' is missing the following properties from type 'AttributeBase': usage, data, [OpaqueTagSymbol0] + Type 'MyAttribute' is missing the following properties from type 'AttributeBase': usage, [OpaqueTagSymbol0] 2 | import { AttributeBase } from '@neo-one/smart-contract'; 3 | diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/contract.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/contract.test.ts.snap index 5f71cedefe..df1001d9a7 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/contract.test.ts.snap +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/contract.test.ts.snap @@ -2,7 +2,7 @@ exports[`Contract cannot be implemented 1`] = ` "snippetCode.ts (4,13): Class 'MyContract' incorrectly implements interface 'Contract'. - Type 'MyContract' is missing the following properties from type 'Contract': script, payable, [OpaqueTagSymbol0] + Type 'MyContract' is missing the following properties from type 'Contract': script, manifest, hasStorage, payable, [OpaqueTagSymbol0] 2 | import { Contract } from '@neo-one/smart-contract'; 3 | diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/crypto.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/crypto.test.ts.snap index 523ed3b3f0..d1ee881b31 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/crypto.test.ts.snap +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/crypto.test.ts.snap @@ -44,24 +44,24 @@ exports[`crypto hash256 cannot be referenced 1`] = ` " `; -exports[`crypto sha1 cannot be referenced - object literal 1`] = ` +exports[`crypto ripemd160 cannot be referenced - object literal 1`] = ` "snippetCode.ts (4,15): Builtin properties cannot be referenced 2 | import { crypto } from '@neo-one/smart-contract'; 3 | - > 4 | const { sha1 } = crypto; + > 4 | const { ripemd160 } = crypto; | ^ 5 | " `; -exports[`crypto sha1 cannot be referenced 1`] = ` -"snippetCode.ts (4,27): Builtin properties cannot be referenced +exports[`crypto ripemd160 cannot be referenced 1`] = ` +"snippetCode.ts (4,32): Builtin properties cannot be referenced 2 | import { crypto } from '@neo-one/smart-contract'; 3 | - > 4 | const sha1 = crypto.sha1; - | ^ + > 4 | const ripemd160 = crypto.ripemd160; + | ^ 5 | " `; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/header.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/header.test.ts.snap deleted file mode 100644 index 2c6817a5ef..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/header.test.ts.snap +++ /dev/null @@ -1,47 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Header cannot be implemented 1`] = ` -"snippetCode.ts (4,13): Class 'MyHeader' incorrectly implements interface 'Header'. - Type 'MyHeader' is missing the following properties from type 'Header': hash, version, previousHash, index, and 4 more. - - 2 | import { Header } from '@neo-one/smart-contract'; - 3 | - > 4 | class MyHeader implements Header { - | ^ - 5 | } - 6 | -" -`; - -exports[`Header invalid "reference" 1`] = ` -"snippetCode.ts (4,26): Builtin properties cannot be referenced - - 2 | import { Header } from '@neo-one/smart-contract'; - 3 | - > 4 | const for = Header['for']; - | ^ - 5 | -" -`; - -exports[`Header invalid reference - object 1`] = ` -"snippetCode.ts (4,15): Builtin properties cannot be referenced - - 2 | import { Header } from '@neo-one/smart-contract'; - 3 | - > 4 | const { for } = Header; - | ^ - 5 | -" -`; - -exports[`Header invalid reference 1`] = ` -"snippetCode.ts (4,26): Builtin properties cannot be referenced - - 2 | import { Header } from '@neo-one/smart-contract'; - 3 | - > 4 | const for = Header.for; - | ^ - 5 | -" -`; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/input.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/input.test.ts.snap deleted file mode 100644 index 9711a9ca3d..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/input.test.ts.snap +++ /dev/null @@ -1,14 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Input cannot be implemented 1`] = ` -"snippetCode.ts (4,13): Class 'MyInput' incorrectly implements interface 'Input'. - Type 'MyInput' is missing the following properties from type 'Input': hash, index, [OpaqueTagSymbol0] - - 2 | import { Input } from '@neo-one/smart-contract'; - 3 | - > 4 | class MyInput implements Input { - | ^ - 5 | } - 6 | -" -`; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/output.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/output.test.ts.snap deleted file mode 100644 index eba011985e..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/output.test.ts.snap +++ /dev/null @@ -1,14 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Output cannot be implemented 1`] = ` -"snippetCode.ts (4,13): Class 'MyOutput' incorrectly implements interface 'Output'. - Type 'MyOutput' is missing the following properties from type 'Output': address, asset, value, [OpaqueTagSymbol0] - - 2 | import { Output } from '@neo-one/smart-contract'; - 3 | - > 4 | class MyOutput implements Output { - | ^ - 5 | } - 6 | -" -`; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/transaction.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/transaction.test.ts.snap index 1a62dc3d42..b1cebdb7cd 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/transaction.test.ts.snap +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/__snapshots__/transaction.test.ts.snap @@ -1,12 +1,12 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Transaction cannot be implemented 1`] = ` -"snippetCode.ts (4,13): Class 'MyTransaction' incorrectly implements interface 'TransactionBase'. - Type 'MyTransaction' is missing the following properties from type 'TransactionBase': hash, type, attributes, outputs, and 4 more. +"snippetCode.ts (4,13): Class 'MyTransaction' incorrectly implements interface 'Transaction'. + Type 'MyTransaction' is missing the following properties from type 'Transaction': hash, version, nonce, sender, and 6 more. - 2 | import { TransactionBase } from '@neo-one/smart-contract'; + 2 | import { Transaction } from '@neo-one/smart-contract'; 3 | - > 4 | class MyTransaction implements TransactionBase { + > 4 | class MyTransaction implements Transaction { | ^ 5 | } 6 | diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/account/__snapshots__/index.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/account/__snapshots__/index.test.ts.snap deleted file mode 100644 index 67bc1ee932..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/account/__snapshots__/index.test.ts.snap +++ /dev/null @@ -1,14 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Account cannot be implemented 1`] = ` -"snippetCode.ts (4,13): Class 'MyAccount' incorrectly implements interface 'Account'. - Type 'MyAccount' is missing the following properties from type 'Account': address, getBalance, [OpaqueTagSymbol0] - - 2 | import { Account } from '@neo-one/smart-contract'; - 3 | - > 4 | class MyAccount implements Account { - | ^ - 5 | } - 6 | -" -`; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/account/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/account/index.test.ts deleted file mode 100644 index ade28daab4..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/account/index.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { common } from '@neo-one/client-common'; -import { helpers } from '../../../../../__data__'; - -describe('Account', () => { - test('Account properties', async () => { - const node = await helpers.startNode(); - const account = await node.readClient.getAccount(node.masterWallet.userAccount.id.address); - await node.executeString(` - import { Account, Address, Hash256 } from '@neo-one/smart-contract'; - - const address = Address.from('${account.address}'); - const account = Account.for(address); - - account.address; - assertEqual(account.address.equals(address), true); - account.getBalance(Hash256.NEO); - assertEqual(account.getBalance(Hash256.NEO), ${helpers.getDecimal(account.balances[common.NEO_ASSET_HASH])}); - - interface AccountLike { getBalance: (value: Hash256) => number } - const accountLike: AccountLike | Account = account as AccountLike | Account; - assertEqual(accountLike['getBalance'](Hash256.GAS), ${helpers.getDecimal( - account.balances[common.GAS_ASSET_HASH], - )}); - assertEqual(account instanceof Account, true); - `); - }); - - test('cannot be implemented', async () => { - helpers.compileString( - ` - import { Account } from '@neo-one/smart-contract'; - - class MyAccount implements Account { - } - `, - { type: 'error' }, - ); - }); -}); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/address/from.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/address/from.test.ts index 533c17bf52..addc3dd417 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/address/from.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/address/from.test.ts @@ -15,7 +15,7 @@ describe('Address.from', () => { }); test('Reports error on invalid address', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address } from '@neo-one/smart-contract'; const keys = Address.from('abc'); @@ -25,7 +25,7 @@ describe('Address.from', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address } from '@neo-one/smart-contract'; const keys = Address.from; @@ -35,7 +35,7 @@ describe('Address.from', () => { }); test('cannot be referenced - object literal', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address } from '@neo-one/smart-contract'; const { from } = Address; @@ -45,7 +45,7 @@ describe('Address.from', () => { }); test('cannot be element referenced', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address } from '@neo-one/smart-contract'; const keys = Address['from']; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/address/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/address/index.test.ts index caf5055a48..36690618c8 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/address/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/address/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../../__data__'; describe('Address', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address } from '@neo-one/smart-contract'; class MyAddress implements Address { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/address/isCaller.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/address/isCaller.test.ts index 909fe59e97..27fe5d5e3b 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/address/isCaller.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/address/isCaller.test.ts @@ -1,12 +1,11 @@ import { helpers, keys } from '../../../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('Address.isCaller', () => { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/arrayStorage.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/arrayStorage.test.ts index 2470745891..bca5842989 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/arrayStorage.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/arrayStorage.test.ts @@ -4,6 +4,14 @@ import { ArrayStoragePop } from '../../../../compile/builtins/contract/arrayStor import { ArrayStoragePush } from '../../../../compile/builtins/contract/arrayStorage/push'; import { DiagnosticCode } from '../../../../DiagnosticCode'; +const properties = ` + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; +`; + describe('ArrayStorage', () => { test('length, push, pop, index', async () => { const node = await helpers.startNode(); @@ -60,12 +68,8 @@ describe('ArrayStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} + private readonly storage = ArrayStorage.for(); public run(): void { @@ -113,12 +117,7 @@ describe('ArrayStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} private readonly storage = ArrayStorage.for(); public run(): void { @@ -166,12 +165,7 @@ describe('ArrayStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} private readonly storage = ArrayStorage.for(); public run(): void { @@ -219,12 +213,7 @@ describe('ArrayStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} private readonly storage = ArrayStorage.for(); public run(): void { @@ -272,12 +261,7 @@ describe('ArrayStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} private readonly storage = ArrayStorage.for(); public run(): void { @@ -325,12 +309,7 @@ describe('ArrayStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} private readonly storage = ArrayStorage.for(); public run(): void { @@ -357,12 +336,7 @@ describe('ArrayStorage', () => { import { ArrayStorage, SmartContract } from '@neo-one/smart-contract'; export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} private readonly prefix = ArrayStorage.for(); public setupStorage(): void { @@ -475,8 +449,8 @@ describe('ArrayStorage', () => { expect(new ArrayStoragePop().canCall()).toEqual(true); }); - test('invalid create', () => { - helpers.compileString( + test('invalid create', async () => { + await helpers.compileString( ` import { ArrayStorage } from '@neo-one/smart-contract'; @@ -486,8 +460,8 @@ describe('ArrayStorage', () => { ); }); - test('invalid create - class', () => { - helpers.compileString( + test('invalid create - class', async () => { + await helpers.compileString( ` import { ArrayStorage } from '@neo-one/smart-contract'; @@ -499,8 +473,8 @@ describe('ArrayStorage', () => { ); }); - test('invalid reference', () => { - helpers.compileString( + test('invalid reference', async () => { + await helpers.compileString( ` import { ArrayStorage } from '@neo-one/smart-contract'; @@ -510,8 +484,8 @@ describe('ArrayStorage', () => { ); }); - test('invalid "reference"', () => { - helpers.compileString( + test('invalid "reference"', async () => { + await helpers.compileString( ` import { ArrayStorage } from '@neo-one/smart-contract'; @@ -521,8 +495,8 @@ describe('ArrayStorage', () => { ); }); - test('invalid reference - object', () => { - helpers.compileString( + test('invalid reference - object', async () => { + await helpers.compileString( ` import { ArrayStorage } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/asset.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/asset.test.ts deleted file mode 100644 index 132e7bb2fe..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/asset.test.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { common } from '@neo-one/client-common'; -import { helpers } from '../../../../__data__'; -import { DiagnosticCode } from '../../../../DiagnosticCode'; - -describe('Asset', () => { - test('properties', async () => { - const node = await helpers.startNode(); - const asset = await node.readClient.getAsset(common.NEO_ASSET_HASH); - await node.executeString(` - import { Asset, Hash256, AssetType, PublicKey, Address } from '@neo-one/smart-contract'; - - Asset.for(Hash256.NEO); - const asset = Asset.for(Hash256.NEO); - - assertEqual(asset.hash, Hash256.NEO); - assertEqual(asset.type, AssetType.Governing); - assertEqual(asset.amount, ${helpers.getDecimal(asset.amount)}); - assertEqual(asset.available, ${helpers.getDecimal(asset.available)}); - assertEqual(asset.precision, ${asset.precision}); - assertEqual(asset.owner, PublicKey.from('${asset.owner}')); - assertEqual(asset.admin, Address.from('${asset.admin}')); - assertEqual(asset.issuer, Address.from('${asset.issuer}')); - assertEqual(asset instanceof Asset, true); - `); - }); - - test('cannot be implemented', async () => { - helpers.compileString( - ` - import { Asset } from '@neo-one/smart-contract'; - - class MyAsset implements Asset { - } - `, - { type: 'error' }, - ); - }); - - test('invalid reference', () => { - helpers.compileString( - ` - import { Asset } from '@neo-one/smart-contract'; - - const for = Asset.for; - `, - { type: 'error', code: DiagnosticCode.InvalidBuiltinReference }, - ); - }); - - test('invalid "reference"', () => { - helpers.compileString( - ` - import { Asset } from '@neo-one/smart-contract'; - - const for = Asset['for']; - `, - { type: 'error', code: DiagnosticCode.InvalidBuiltinReference }, - ); - }); - - test('invalid reference - object', () => { - helpers.compileString( - ` - import { Asset } from '@neo-one/smart-contract'; - - const { for } = Asset; - `, - { type: 'error', code: DiagnosticCode.InvalidBuiltinReference }, - ); - }); -}); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/assetType.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/assetType.test.ts deleted file mode 100644 index 6ffe0f2475..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/assetType.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { helpers } from '../../../../__data__'; - -describe('AssetType', () => { - test('properties', async () => { - await helpers.executeString(` - import { AssetType } from '@neo-one/smart-contract'; - - const x = AssetType; - - assertEqual(x.Credit, 0x40); - assertEqual(AssetType.Duty, 0x80); - assertEqual(AssetType.Governing, 0x00); - assertEqual(AssetType.Utility, 0x01); - assertEqual(AssetType.Currency, 0x08); - assertEqual(AssetType.Share, 0x90); - assertEqual(AssetType.Invoice, 0x98); - assertEqual(AssetType.Token, 0x60); - `); - }); -}); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/attribute.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/attribute.test.ts index cfdddba97b..9b9df9d58f 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/attribute.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/attribute.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../__data__'; describe('Attribute', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` import { AttributeBase } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/attributeUsage.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/attributeUsage.test.ts index b8ed1ac200..88fb1b431c 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/attributeUsage.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/attributeUsage.test.ts @@ -5,44 +5,8 @@ describe('AttributeUsage', () => { await helpers.executeString(` import { AttributeUsage } from '@neo-one/smart-contract'; const x = AttributeUsage; - assertEqual(x.ContractHash, 0x00); - assertEqual(AttributeUsage.ECDH02, 0x02); - assertEqual(AttributeUsage.ECDH03, 0x03); - assertEqual(AttributeUsage.Script, 0x20); - assertEqual(AttributeUsage.Vote, 0x30); - assertEqual(AttributeUsage.DescriptionUrl, 0x81); - assertEqual(AttributeUsage.Description, 0x90); - assertEqual(AttributeUsage.Hash1, 0xa1); - assertEqual(AttributeUsage.Hash2, 0xa2); - assertEqual(AttributeUsage.Hash3, 0xa3); - assertEqual(AttributeUsage.Hash4, 0xa4); - assertEqual(AttributeUsage.Hash5, 0xa5); - assertEqual(AttributeUsage.Hash6, 0xa6); - assertEqual(AttributeUsage.Hash7, 0xa7); - assertEqual(AttributeUsage.Hash8, 0xa8); - assertEqual(AttributeUsage.Hash9, 0xa9); - assertEqual(AttributeUsage.Hash10, 0xaa); - assertEqual(AttributeUsage.Hash11, 0xab); - assertEqual(AttributeUsage.Hash12, 0xac); - assertEqual(AttributeUsage.Hash13, 0xad); - assertEqual(AttributeUsage.Hash14, 0xae); - assertEqual(AttributeUsage.Hash15, 0xaf); - assertEqual(AttributeUsage.Remark, 0xf0); - assertEqual(AttributeUsage.Remark1, 0xf1); - assertEqual(AttributeUsage.Remark2, 0xf2); - assertEqual(AttributeUsage.Remark3, 0xf3); - assertEqual(AttributeUsage.Remark4, 0xf4); - assertEqual(AttributeUsage.Remark5, 0xf5); - assertEqual(AttributeUsage.Remark6, 0xf6); - assertEqual(AttributeUsage.Remark7, 0xf7); - assertEqual(AttributeUsage.Remark8, 0xf8); - assertEqual(AttributeUsage.Remark9, 0xf9); - assertEqual(AttributeUsage.Remark10, 0xfa); - assertEqual(AttributeUsage.Remark11, 0xfb); - assertEqual(AttributeUsage.Remark12, 0xfc); - assertEqual(AttributeUsage.Remark13, 0xfd); - assertEqual(AttributeUsage.Remark14, 0xfe); - assertEqual(AttributeUsage.Remark15, 0xff); + assertEqual(AttributeUsage.HighPriority, 0x01); + assertEqual(x.HighPriority, 0x01); `); }); }); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/block.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/block.test.ts index e86f772698..282f91cdd1 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/block.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/block.test.ts @@ -2,13 +2,13 @@ import { helpers } from '../../../../__data__'; import { DiagnosticCode } from '../../../../DiagnosticCode'; describe('Block', () => { - test('properties', async () => { + test.only('properties', async () => { const node = await helpers.startNode(); const block = await node.readClient.getBlock(0); await node.executeString(` - import { Block, Header, Hash256, Address } from '@neo-one/smart-contract'; + import { Block, Hash256, Address } from '@neo-one/smart-contract'; - const genesisHash = Hash256.from('${block.hash}') + const genesisHash = Hash256.from('${block.hash}'); Block.for(0); Block.for(genesisHash); let block = Block.for(0); @@ -20,19 +20,13 @@ describe('Block', () => { assertEqual(block.index, ${block.index}); assertEqual(block.time, ${block.time}); assertEqual(block.nextConsensus, Address.from('${block.nextConsensus}')); - assertEqual(block.transactions.length, 5); - assertEqual(block.transactions[0].hash, Hash256.from('${block.transactions[0].hash}')); - assertEqual(block.transactions[1].hash, Hash256.from('${block.transactions[1].hash}')); - assertEqual(block.transactions[2].hash, Hash256.from('${block.transactions[2].hash}')); - assertEqual(block.transactions[3].hash, Hash256.from('${block.transactions[3].hash}')); - assertEqual(block.transactions[4].hash, Hash256.from('${block.transactions[4].hash}')); - assertEqual(block instanceof Header, false); + assertEqual(block.transactionsLength, 5); assertEqual(block instanceof Block, true); `); }); test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` import { Block } from '@neo-one/smart-contract'; @@ -43,8 +37,8 @@ describe('Block', () => { ); }); - test('invalid reference', () => { - helpers.compileString( + test('invalid reference', async () => { + await helpers.compileString( ` import { Block } from '@neo-one/smart-contract'; @@ -54,8 +48,8 @@ describe('Block', () => { ); }); - test('invalid "reference"', () => { - helpers.compileString( + test('invalid "reference"', async () => { + await helpers.compileString( ` import { Block } from '@neo-one/smart-contract'; @@ -65,8 +59,8 @@ describe('Block', () => { ); }); - test('invalid reference - object', () => { - helpers.compileString( + test('invalid reference - object', async () => { + await helpers.compileString( ` import { Block } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/blockchain.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/blockchain.test.ts index 0ab58f1c60..922e4f127b 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/blockchain.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/blockchain.test.ts @@ -15,7 +15,7 @@ describe('Blockchain', () => { }); test('set currentHeight', async () => { - helpers.compileString( + await helpers.compileString( ` import { Blockchain } from '@neo-one/smart-contract'; @@ -37,7 +37,7 @@ describe('Blockchain', () => { }); test('set currentBlockTime', async () => { - helpers.compileString( + await helpers.compileString( ` import { Blockchain } from '@neo-one/smart-contract'; @@ -47,54 +47,49 @@ describe('Blockchain', () => { ); }); + // TODO: fix test('currentTransaction', async () => { const node = await helpers.startNode(); - const data = Buffer.from('Hello World', 'utf8').toString('hex'); + const sender = 'NfdKztHauMe8n8HnSbzCUZCNfQY7gToy2q'; + const validUntilBlock = 2102400; + const systemFee = 0; + const networkFee = 0; + const script = `Vv/CYCOZCgAAShCzJ5AKAABFEM5KEM4YsycuAQAAEc5Bu6pgehDDS0GSbUzwJwgBAABLUFBBvSAgLFBOUBHAWErKnc4SzhPOEVARzhLOUM5KEc7BwEoQSxDOwcDQS8oTsycMAAAASxLOSxFR0FhQzxDONZf///9Y1EUQsyUmAAAAAlkAAAAMBXRyYWNlEsAMBXRyYWNlQZUBb2ERFCMLAAAAzyOE////RUoRsydKAAAARVhKyp3OEM4QzhBR0EVFWErKnc4QzhDOEM5FWErKnc4SzhLOQfm04jiXQel9OKAQs6wnCwAAADcjCAAAABAQQCNEAAAAShCzJyYAAABFWErKnc4QzhDOEFHQRUVYSsqdzhDOEM4QzhBAIxsAAABKErMnDAAAAEVFIwwAAABFRSP3/v//RhgQEsZKVNBOUBFQ0CNYCQAAShDOGrMnpAEAABHOEMNQQe1k9ydQS0GSbUzwJ3wBAABLUEtBvSAgLFFBDpSIukFSfNDfUVERwFhKyp3OEs4TzhFQEc4SzlDOShHOwcBKEEsQzsHA0EvKE7MnDAAAAEsSzksRUdBYUM8QzjVY/v//WNRFELMlJgAAAAIkAQAADAV0cmFjZRLADAV0cmFjZUGVAW9hERQjdQAAAFERwFhKyp3OEs4TzhFQEc4SzlDOShHOwcBKEEsQzsHA0EvKE7MnDAAAAEsSzksRUdBYUM8QzjXy/f//WNRFELMlJgAAAAJmAQAADAV0cmFjZRLADAV0cmFjZUGVAW9hERQjDwAAABLAS1DPIxD///9FShGzJ0oAAABFWErKnc4QzhDOEVHQRUVYSsqdzhDOEM4RzkVYSsqdzhLOEs5B+bTiOJdB6X04oBCzrCcLAAAANyMIAAAAEBBAI0QAAABKELMnJgAAAEVYSsqdzhDOEM4RUdBFRVhKyp3OEM4QzhHOEEAjGwAAAEoSsycMAAAARUUjDAAAAEVFI4P+//9GGhASxkpU0E5QEVDQI68HAABKEM4bsyc9AQAAEc4Qw1BB7WT3J1BLQZJtTPAnFQEAAEtQS0G9ICAsUUEOlIi6QVJ80N9RUUVOUBHAWErKnc4SzhPOEVARzhLOUM5KEc7BwEoQSxDOwcDQS8oTsycMAAAASxLOSxFR0FhQzxDONaz8//9Y1EUQsyUmAAAAAjgCAAAMBXRyYWNlEsAMBXRyYWNlQZUBb2ERFCMLAAAAzyN3////RUoRsydKAAAARVhKyp3OEM4QzhJR0EVFWErKnc4QzhDOEs5FWErKnc4SzhLOQfm04jiXQel9OKAQs6wnCwAAADcjCAAAABAQQCNEAAAAShCzJyYAAABFWErKnc4QzhDOElHQRUVYSsqdzhDOEM4SzhBAIxsAAABKErMnDAAAAEVFIwwAAABFRSPq/v//RhsQEsZKVNBOUBFQ0CNtBgAAShDOF7MnrAUAAEpKWErKnc4QzhDOE1HQEc4QzsxBu6pgehDDS0GSbUzwJ7wAAABLUFBBvSAgLFBLDAlfX3Byb3RvX1+XqicNAAAATlDPIwYAAABGI9D///9FShGzJ0oAAABFWErKnc4QzhDOFFHQRUVYSsqdzhDOEM4UzkVYSsqdzhLOEs5B+bTiOJdB6X04oBCzrCcLAAAANyMIAAAAEBBAI0QAAABKELMnJgAAAEVYSsqdzhDOEM4UUdBFRVhKyp3OEM4QzhTOEEAjGwAAAEoSsycMAAAARUUjDAAAAEVFI0P///9GQbuqYHoQw0tBkm1M8CcGAgAAS1BQQb0gICxQTlBYSsqdzhDOEM4TzlBLUNsoUEoRzhDOSlERzhDOShRNy6pRDAlfX3Byb3RvX1/LqyeWAAAARQwJX19wcm90b19fzhDOShHOEM5KURHOEM5KFE0jzv///0VKEbMnKQAAAEVYSsqdzhDOEM4VUdBYSsqdzhDOEM4VzhEUI/AAAAAjRwAAAEoQsycpAAAARVhKyp3OEM4QzhVR0FhKyp3OEM4QzhXOEBQjxAAAACMbAAAAShKzJwwAAABFRSMMAAAARUUjX////0ZOS8snkAAAAM5KyhKXJ34AAAAQzhFQEc4SzlDOwcBOSsoTsycMAAAARUUjBwAAAFDPEMNQShHOwcBKEEsQzsHA0EvKE7MnDAAAAEsSzksRUdBYUM8QzjW3+f//WNRFELMlJgAAAAIeBAAADAV0cmFjZRLADAV0cmFjZUGVAW9hERQjIgAAACMIAAAARhDOIw8AAABFRUUREBHGSlTQzyOG/v//RUoRsydKAAAARVhKyp3OEM4QzhZR0EVFWErKnc4QzhDOFs5FWErKnc4SzhLOQfm04jiXQel9OKAQs6wnCwAAADcjCAAAABAQQCNEAAAAShCzJyYAAABFWErKnc4QzhDOFlHQRUVYSsqdzhDOEM4WzhBAIxsAAABKErMnDAAAAEVFIwwAAABFRSP5/f//RkG7qmB6EMNLQZJtTPAnCAEAAEtQUEG9ICAsUE5QEcBYSsqdzhLOE84RUBHOEs5QzkoRzsHAShBLEM7BwNBLyhOzJwwAAABLEs5LEVHQWFDPEM41ivj//1jURRCzJSYAAAAC3wQAAAwFdHJhY2USwAwFdHJhY2VBlQFvYREUIwsAAADPI4T///9FShGzJ0oAAABFWErKnc4QzhDOF1HQRUVYSsqdzhDOEM4XzkVYSsqdzhLOEs5B+bTiOJdB6X04oBCzrCcLAAAANyMIAAAAEBBAI0QAAABKELMnJgAAAEVYSsqdzhDOEM4XUdBFRVhKyp3OEM4QzhfOEEAjGwAAAEoSsycMAAAARUUjDAAAAEVFI/f+//9GUBHOEM7MQbuqYHoQw0tBkm1M8Ce8AAAAS1BQQb0gICxQSwwJX19wcm90b19fl6onDQAAAE5QzyMGAAAARiPQ////RUoRsydKAAAARVhKyp3OEM4QzhhR0EVFWErKnc4QzhDOGM5FWErKnc4SzhLOQfm04jiXQel9OKAQs6wnCwAAADcjCAAAABAQQCNEAAAAShCzJyYAAABFWErKnc4QzhDOGFHQRUVYSsqdzhDOEM4YzhBAIxsAAABKErMnDAAAAEVFIwwAAABFRSND////RkG7qmB6EMNLQZJtTPAnrwAAAEtQUEG9ICAsUE5QFBASxkpU0E5QEVDQzyPd////RUoRsydKAAAARVhKyp3OEM4QzhlR0EVFWErKnc4QzhDOGc5FWErKnc4SzhLOQfm04jiXQel9OKAQs6wnCwAAADcjCAAAABAQQCNEAAAAShCzJyYAAABFWErKnc4QzhDOGVHQRUVYSsqdzhDOEM4ZzhBAIxsAAABKErMnDAAAAEVFIwwAAABFRSNQ////RhLAFxASxkpU0E5QEVDQI7wAAABKEM4Rs0sQzhKzrEsQzhOzrEsQzhazrEsQzhSzrEsQzhWzrEsQzhmzrCcKAAAAI4kAAABFDAlUeXBlRXJyb3IUEBLGSlTQTlARUNBKShDOFLMlCQAAABHOEM4RzgKcBgAAUAwFZXJyb3ITwAwFZXJyb3JBlQFvYQKjBgAADAV0cmFjZRLADAV0cmFjZUGVAW9hRVhKyp3OEs4SzkH5tOI4l0HpfTigELOsJwsAAAA3IwgAAAAQEEAQQDcREBHGSlTQERARxkpU0BDDE8BKWFDPEM7Iz0PAyE4QUdBKERDD0EoSQTlTbjzQSlhKyp3OTksSUNARUNBKEc7Iz0oTWErKnc7BwEoQS0vOwcDQEBLAyMjIE8AXEBLGSlTQTlARUNBOEVFREc4SzlFR0NBFQS1RCDAAExASxkpU0E5QEVDQWErKnc4QzhDOGlHQEBYQEsZKVNBOUBFQ0FhKyp3OEM4QzhrOEc4RzhYQEsZKVNBOUBFQ0E5LUBHO2yFQEc7bIbMnDAAAAEVFI/QAAAAMCiB0byBlcXVhbCAUEBLGSlTQTlARUNBRDAlFeHBlY3RlZCAUEBLGSlTQTlARUNAUwBgQEsZKVNBOUBFQ0N4RwFhKyp3OEs4TzhFQEc4SzlDOShHOwcBKEEsQzsHA0EvKE7MnDAAAAEsSzksRUdBYUM8QzjUm9P//WNRFELMlRQAAAALjBwAADAV0cmFjZRLADAV0cmFjZUGVAW9hRVhKyp3OEs4SzkH5tOI4l0HpfTigELOsJwsAAAA3IwgAAAAQEEBBPxwBJAIACAAADAtjb25zb2xlLmxvZxPADAtjb25zb2xlLmxvZ0GVAW9hN1hKyp3OEs5FWNRF`; await node.executeString( ` - import { AttributeUsage, Blockchain, TransactionType } from '@neo-one/smart-contract'; + import { Address, Blockchain, Transaction } from '@neo-one/smart-contract'; const { currentTransaction: transaction } = Blockchain; - assertEqual(transaction.type, TransactionType.Invocation); - - const attributes = transaction.attributes; - if (attributes.length !== 3 && attributes.length !== 4) { - throw 'Failure'; - } - - const attribute = attributes[0]; - - assertEqual(attribute.usage, AttributeUsage.Description); - assertEqual(attribute.data.equals(${helpers.getBufferHash(data)}), true) - - assertEqual(transaction.inputs.length, 1); - assertEqual(transaction.outputs.length, 2); - assertEqual(transaction.references.length, 1); - assertEqual(transaction.unspentOutputs.length, 2); + // assertEqual(transaction.height, 0); + assertEqual(transaction.version, 0); + assertEqual(typeof transaction.nonce, 'number'); + assertEqual(transaction.sender, Address.from('${sender}')); + assertEqual(transaction.validUntilBlock, ${validUntilBlock}); + assertEqual(transaction.systemFee, ${systemFee}); + assertEqual(transaction.networkFee, ${networkFee}); + assertEqual(transaction.script, ${helpers.getBufferHash(script, 'base64')}); + // assertEqual(transaction.notifications, []); + assertEqual(transaction instanceof Transaction, true); `, { + // TODO: UAPB.invokeRaw() currently doesn't add these to the transaction script. this currently does nothing transfers: [ { to: keys[0].address, amount: new BigNumber(10), - asset: common.NEO_ASSET_HASH, - }, - ], - attributes: [ - { - usage: 'Description', - data, + asset: common.nativeScriptHashes.NEO, }, ], + attributes: [], }, ); }); test('set currentTransaction', async () => { - helpers.compileString( + await helpers.compileString( ` import { Blockchain } from '@neo-one/smart-contract'; @@ -156,7 +151,7 @@ describe('Blockchain', () => { }); test('set currentCallerContract', async () => { - helpers.compileString( + await helpers.compileString( ` import { Blockchain } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/contract.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/contract.test.ts index d292ae788a..16ba89547b 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/contract.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/contract.test.ts @@ -19,13 +19,14 @@ describe('Contract', () => { } assertEqual(contract instanceof Contract, true); - assertEqual(contract.script, ${helpers.getBufferHash(contract.script)}); + assertEqual(contract.script, ${helpers.getBufferHash(contract.contract.script, 'base64')}); + assertEqual(typeof contract.manifest, "string"); assertEqual(contract.payable, true); `); }); test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` import { Contract } from '@neo-one/smart-contract'; @@ -36,8 +37,8 @@ describe('Contract', () => { ); }); - test('invalid reference', () => { - helpers.compileString( + test('invalid reference', async () => { + await helpers.compileString( ` import { Contract } from '@neo-one/smart-contract'; @@ -47,8 +48,8 @@ describe('Contract', () => { ); }); - test('invalid "reference"', () => { - helpers.compileString( + test('invalid "reference"', async () => { + await helpers.compileString( ` import { Contract } from '@neo-one/smart-contract'; @@ -58,8 +59,8 @@ describe('Contract', () => { ); }); - test('invalid reference - object', () => { - helpers.compileString( + test('invalid reference - object', async () => { + await helpers.compileString( ` import { Contract } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/createEventNotifier.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/createEventNotifier.test.ts index 0acf89fdd7..24104c1ec1 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/createEventNotifier.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/createEventNotifier.test.ts @@ -12,27 +12,32 @@ describe('createEventNotifier', () => { onTransfer(10, 'foo', true); `); - expect(result.actions.length).toEqual(1); - const action = result.actions[0]; + expect(result.notifications.length).toEqual(1); + const action = result.notifications[0]; if (action.type !== 'Notification') { expect(action.type).toEqual('Notification'); throw new Error('For TS'); } - expect(action.args.length).toEqual(4); + if (typeof action.state === 'string') { + expect(Array.isArray(action.state)).toBeTruthy(); + throw new Error('For TS'); + } + + expect(action.state.length).toEqual(4); // tslint:disable-next-line no-any const expectArg = (arg: any, type: string, value: any, mapValue: (val: any) => any) => { expect(arg.type).toEqual(type); expect(mapValue(arg.value)).toEqual(value); }; - expectArg(action.args[0], 'Buffer', 'event', (val) => Buffer.from(val, 'hex').toString('utf8')); - expectArg(action.args[1], 'Integer', '10', (val) => val.toString(10)); - expectArg(action.args[2], 'Buffer', 'foo', (val) => Buffer.from(val, 'hex').toString('utf8')); - expectArg(action.args[3], 'Integer', '1', (val) => val.toString(10)); + expectArg(action.state[0], 'Buffer', 'event', (val) => Buffer.from(val, 'hex').toString('utf8')); + expectArg(action.state[1], 'Integer', '10', (val) => val.toString(10)); + expectArg(action.state[2], 'Buffer', 'foo', (val) => Buffer.from(val, 'hex').toString('utf8')); + expectArg(action.state[3], 'Integer', '1', (val) => val.toString(10)); }); test('invalid event name', async () => { - helpers.compileString( + await helpers.compileString( ` import { createEventNotifier, SmartContract } from '@neo-one/smart-contract'; @@ -47,7 +52,7 @@ describe('createEventNotifier', () => { }); test('invalid event parameter type', async () => { - helpers.compileString( + await helpers.compileString( ` import { createEventNotifier, SmartContract } from '@neo-one/smart-contract'; @@ -63,7 +68,7 @@ describe('createEventNotifier', () => { }); test('invalid event parameter type - forward value', async () => { - helpers.compileString( + await helpers.compileString( ` import { createEventNotifier, SmartContract } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/crypto.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/crypto.test.ts index 587714222b..02b1f3ea5f 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/crypto.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/crypto.test.ts @@ -3,34 +3,34 @@ import { helpers } from '../../../../__data__'; import { DiagnosticCode } from '../../../../DiagnosticCode'; describe('crypto', () => { - test('sha1', async () => { + test('ripemd160', async () => { const value = Buffer.alloc(4, 0x10); - const expected = crypto.sha1(value); + const expected = crypto.rmd160(value); await helpers.executeString(` import { crypto } from '@neo-one/smart-contract'; - const result = crypto.sha1(${helpers.getBuffer(value)}) + const result = crypto.ripemd160(${helpers.getBuffer(value)}) assertEqual(result, ${helpers.getBuffer(expected)}) `); }); - test('sha1 cannot be referenced', async () => { - helpers.compileString( + test('ripemd160 cannot be referenced', async () => { + await helpers.compileString( ` import { crypto } from '@neo-one/smart-contract'; - const sha1 = crypto.sha1; + const ripemd160 = crypto.ripemd160; `, { type: 'error', code: DiagnosticCode.InvalidBuiltinReference }, ); }); - test('sha1 cannot be referenced - object literal', async () => { - helpers.compileString( + test('ripemd160 cannot be referenced - object literal', async () => { + await helpers.compileString( ` import { crypto } from '@neo-one/smart-contract'; - const { sha1 } = crypto; + const { ripemd160 } = crypto; `, { type: 'error', code: DiagnosticCode.InvalidBuiltinReference }, ); @@ -48,7 +48,7 @@ describe('crypto', () => { }); test('sha256 cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` import { crypto } from '@neo-one/smart-contract'; @@ -59,7 +59,7 @@ describe('crypto', () => { }); test('sha256 cannot be referenced - object literal', async () => { - helpers.compileString( + await helpers.compileString( ` import { crypto } from '@neo-one/smart-contract'; @@ -81,7 +81,7 @@ describe('crypto', () => { }); test('hash160 cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` import { crypto } from '@neo-one/smart-contract'; @@ -92,7 +92,7 @@ describe('crypto', () => { }); test('hash160 cannot be referenced - object literal', async () => { - helpers.compileString( + await helpers.compileString( ` import { crypto } from '@neo-one/smart-contract'; @@ -114,7 +114,7 @@ describe('crypto', () => { }); test('hash256 cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` import { crypto } from '@neo-one/smart-contract'; @@ -125,7 +125,7 @@ describe('crypto', () => { }); test('hash256 cannot be referenced - object literal', async () => { - helpers.compileString( + await helpers.compileString( ` import { crypto } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/declareEvent.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/declareEvent.test.ts index c188502133..417e19750f 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/declareEvent.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/declareEvent.test.ts @@ -13,15 +13,13 @@ describe('declareEvent', () => { } `); - expect(definition.abi.events).toHaveLength(1); - const events = definition.abi.events; - if (events !== undefined) { - expect(events[0].name).toEqual('event'); - } + expect(definition.manifest.abi.events).toHaveLength(1); + const events = definition.manifest.abi.events; + expect(events[0].name).toEqual('event'); }); test('invalid event name', async () => { - helpers.compileString( + await helpers.compileString( ` import { declareEvent, SmartContract } from '@neo-one/smart-contract'; @@ -37,7 +35,7 @@ describe('declareEvent', () => { }); test('invalid event parameter type', async () => { - helpers.compileString( + await helpers.compileString( ` import { declareEvent, SmartContract } from '@neo-one/smart-contract'; @@ -53,7 +51,7 @@ describe('declareEvent', () => { }); test('invalid event parameter type - forward value', async () => { - helpers.compileString( + await helpers.compileString( ` import { declareEvent, SmartContract } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/deploy/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/deploy/index.test.ts index 4988234968..d8f7f9e070 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/deploy/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/deploy/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../../__data__'; describe('Deploy', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` import { DeployConstructor } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/deploy/senderAddress.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/deploy/senderAddress.test.ts index 5a202a8d7c..87a4d81b66 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/deploy/senderAddress.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/deploy/senderAddress.test.ts @@ -3,7 +3,7 @@ import { DiagnosticCode } from '../../../../../DiagnosticCode'; describe('Deploy.senderAddress', () => { test('cannot be used in a function', async () => { - helpers.compileString( + await helpers.compileString( ` import { Deploy } from '@neo-one/smart-contract'; @@ -16,7 +16,7 @@ describe('Deploy.senderAddress', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` import { Deploy } from '@neo-one/smart-contract'; @@ -27,7 +27,7 @@ describe('Deploy.senderAddress', () => { }); test('cannot be referenced - object literal', async () => { - helpers.compileString( + await helpers.compileString( ` import { Deploy } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/forwardValue/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/forwardValue/index.test.ts index 07f2298497..2ab74b51b1 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/forwardValue/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/forwardValue/index.test.ts @@ -1,17 +1,16 @@ import { helpers, keys } from '../../../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('ForwardValue', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` import { ForwardValue } from '@neo-one/smart-contract'; @@ -23,7 +22,7 @@ describe('ForwardValue', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` import { ForwardValue } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/hash256/from.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/hash256/from.test.ts index 07c1985480..3f31aca533 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/hash256/from.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/hash256/from.test.ts @@ -1,20 +1,19 @@ -import { common } from '@neo-one/client-common'; -import { helpers } from '../../../../../__data__'; +import { hashes, helpers } from '../../../../../__data__'; import { DiagnosticCode } from '../../../../../DiagnosticCode'; describe('Hash256.from', () => { test('should return an address from literal hash', async () => { await helpers.executeString(` import { Hash256 } from '@neo-one/smart-contract'; - Hash256.from('${common.NEO_ASSET_HASH}'); - const x = Hash256.from('${common.NEO_ASSET_HASH}'); + Hash256.from('${hashes.OLD_NEO_ASSET_HASH}'); + const x = Hash256.from('${hashes.OLD_NEO_ASSET_HASH}'); assertEqual(x.equals(x), true); `); }); test('Reports error on invalid hash256', async () => { - helpers.compileString( + await helpers.compileString( ` import { Hash256 } from '@neo-one/smart-contract'; const keys = Hash256.from('abc'); @@ -24,7 +23,7 @@ describe('Hash256.from', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` import { Hash256 } from '@neo-one/smart-contract'; const keys = Hash256.from; @@ -34,7 +33,7 @@ describe('Hash256.from', () => { }); test('cannot be referenced - object literal', async () => { - helpers.compileString( + await helpers.compileString( ` import { Hash256 } from '@neo-one/smart-contract'; const { from } = Hash256; @@ -44,7 +43,7 @@ describe('Hash256.from', () => { }); test('cannot be element referenced', async () => { - helpers.compileString( + await helpers.compileString( ` import { Hash256 } from '@neo-one/smart-contract'; const keys = Hash256['from']; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/hash256/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/hash256/index.test.ts index d46dacb8c5..6f1a0187db 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/hash256/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/hash256/index.test.ts @@ -1,10 +1,9 @@ -import { common } from '@neo-one/client-common'; import { helpers } from '../../../../../__data__'; import { DiagnosticCode } from '../../../../../DiagnosticCode'; describe('Hash256', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` import { Hash256 } from '@neo-one/smart-contract'; class MyHash256 implements Hash256 { @@ -15,7 +14,7 @@ describe('Hash256', () => { }); test('cannot be called', async () => { - helpers.compileString( + await helpers.compileString( ` import { Hash256 } from '@neo-one/smart-contract'; @@ -24,30 +23,4 @@ describe('Hash256', () => { { type: 'error', code: DiagnosticCode.InvalidBuiltinCall }, ); }); - - test('Hash256.NEO', async () => { - await helpers.executeString(` - import { Hash256 } from '@neo-one/smart-contract'; - const x = Hash256.from('${common.NEO_ASSET_HASH}'); - - Hash256.NEO; - assertEqual(x.equals(Hash256.NEO), true); - - const { NEO } = Hash256; - assertEqual(NEO.equals(Hash256.NEO), true); - `); - }); - - test('Hash256.GAS', async () => { - await helpers.executeString(` - import { Hash256 } from '@neo-one/smart-contract'; - const x = Hash256.from('${common.GAS_ASSET_HASH}'); - - Hash256.GAS; - assertEqual(x.equals(Hash256.GAS), true); - - const { GAS } = Hash256; - assertEqual(GAS.equals(Hash256.GAS), true); - `); - }); }); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/header.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/header.test.ts deleted file mode 100644 index 29ef47a6b0..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/header.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { helpers } from '../../../../__data__'; -import { DiagnosticCode } from '../../../../DiagnosticCode'; - -describe('Header', () => { - test('properties', async () => { - const node = await helpers.startNode(); - const header = await node.readClient.getBlock(0); - await node.executeString(` - import { Header, Block, Hash256, Address } from '@neo-one/smart-contract'; - - const genesisHash = Hash256.from('${header.hash}') - Header.for(0); - Header.for(genesisHash); - let header = Header.for(0); - header = Header.for(genesisHash); - - assertEqual(header.hash, genesisHash); - assertEqual(header.version, ${header.version}); - assertEqual(header.previousHash, Hash256.from('${header.previousBlockHash}')); - assertEqual(header.index, ${header.index}); - assertEqual(header.time, ${header.time}); - assertEqual(header.nextConsensus, Address.from('${header.nextConsensus}')); - assertEqual(header instanceof Header, true); - assertEqual(header instanceof Block, false); - `); - }); - - test('cannot be implemented', async () => { - helpers.compileString( - ` - import { Header } from '@neo-one/smart-contract'; - - class MyHeader implements Header { - } - `, - { type: 'error' }, - ); - }); - - test('invalid reference', () => { - helpers.compileString( - ` - import { Header } from '@neo-one/smart-contract'; - - const for = Header.for; - `, - { type: 'error', code: DiagnosticCode.InvalidBuiltinReference }, - ); - }); - - test('invalid "reference"', () => { - helpers.compileString( - ` - import { Header } from '@neo-one/smart-contract'; - - const for = Header['for']; - `, - { type: 'error', code: DiagnosticCode.InvalidBuiltinReference }, - ); - }); - - test('invalid reference - object', () => { - helpers.compileString( - ` - import { Header } from '@neo-one/smart-contract'; - - const { for } = Header; - `, - { type: 'error', code: DiagnosticCode.InvalidBuiltinReference }, - ); - }); -}); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/input.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/input.test.ts deleted file mode 100644 index a86f6c449a..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/input.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { helpers } from '../../../../__data__'; - -describe('Input', () => { - test('cannot be implemented', async () => { - helpers.compileString( - ` - import { Input } from '@neo-one/smart-contract'; - - class MyInput implements Input { - } - `, - { type: 'error' }, - ); - }); -}); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/linkedSmartContract/for.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/linkedSmartContract/for.test.ts index 435257106b..89625e26d7 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/linkedSmartContract/for.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/linkedSmartContract/for.test.ts @@ -1,3 +1,4 @@ +import { scriptHashToAddress } from '@neo-one/client-common'; import { pathResolve } from '@neo-one/smart-contract-compiler-node'; import { normalizePath } from '@neo-one/utils'; import * as appRootDir from 'app-root-dir'; @@ -21,7 +22,7 @@ describe('LinkedSmartContract.for', () => { const barContract = await node.addContractFromSnippet(normalizePath(path.join('linked', 'Bar.ts')), { [fooFullPath]: { - Foo: fooContract.address, + Foo: scriptHashToAddress(fooContract.manifest.abi.hash), }, }); @@ -31,8 +32,10 @@ describe('LinkedSmartContract.for', () => { interface Contract { getFoo(address: Address): string; } - const expected = Address.from('${fooContract.address}'); - const contract = SmartContract.for(Address.from('${barContract.address}')); + const expected = Address.from('${scriptHashToAddress(fooContract.manifest.abi.hash)}'); + const contract = SmartContract.for(Address.from('${scriptHashToAddress( + barContract.manifest.abi.hash, + )}')); assertEqual(contract.getFoo(expected), 'foo'); `); }); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/mapStorage.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/mapStorage.test.ts index 01cc51eeeb..3fda852041 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/mapStorage.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/mapStorage.test.ts @@ -1,7 +1,14 @@ -import { common } from '@neo-one/client-common'; -import { helpers, keys } from '../../../../__data__'; +import { hashes, helpers, keys } from '../../../../__data__'; import { DiagnosticCode } from '../../../../DiagnosticCode'; +const properties = ` + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; +`; + describe('MapStorage', () => { test('get, set, delete, has', async () => { const node = await helpers.startNode(); @@ -48,12 +55,8 @@ describe('MapStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} + private readonly storage = MapStorage.for(); public run(): void { @@ -160,12 +163,8 @@ describe('MapStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} + private readonly storage = MapStorage.for(); public run(): void { @@ -185,14 +184,14 @@ describe('MapStorage', () => { `); }); - test('multi-tier', async () => { + test.only('multi-tier', async () => { const node = await helpers.startNode(); const contract = await node.addContract(` import { MapStorage, SmartContract, Address, Hash256 } from '@neo-one/smart-contract'; const addressA = Address.from('${keys[0].address}'); - const hashA = Hash256.from('${common.NEO_ASSET_HASH}'); + const hashA = Hash256.from('${hashes.OLD_NEO_ASSET_HASH}'); const keyA = 'keyA'; const valueA = 1; const valueB = 2; @@ -264,12 +263,8 @@ describe('MapStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} + private readonly storage = MapStorage.for<[Address, Hash256, string], number>(); public run(): void { @@ -298,8 +293,8 @@ describe('MapStorage', () => { const addressA = Address.from('${keys[0].address}'); const addressB = Address.from('${keys[1].address}'); - const hashA = Hash256.from('${common.NEO_ASSET_HASH}'); - const hashB = Hash256.from('${common.GAS_ASSET_HASH}'); + const hashA = Hash256.from('${hashes.OLD_NEO_ASSET_HASH}'); + const hashB = Hash256.from('${hashes.OLD_GAS_ASSET_HASH}'); const keyA = 'keyA'; const keyB = 'keyB'; const keyC = 'keyC'; @@ -385,12 +380,8 @@ describe('MapStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} + private readonly storage = MapStorage.for<[Address, Hash256, string], number>(); public run(): void { @@ -422,8 +413,8 @@ describe('MapStorage', () => { const addressA = Address.from('${keys[0].address}'); const addressB = Address.from('${keys[1].address}'); - const hashA = Hash256.from('${common.NEO_ASSET_HASH}'); - const hashB = Hash256.from('${common.GAS_ASSET_HASH}'); + const hashA = Hash256.from('${hashes.OLD_NEO_ASSET_HASH}'); + const hashB = Hash256.from('${hashes.OLD_GAS_ASSET_HASH}'); const keyA = 'keyA'; const keyB = 'keyB'; const keyC = 'keyC'; @@ -528,12 +519,8 @@ describe('MapStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} + private readonly storage = MapStorage.for<[Address, Hash256, string], number>(); public run(): void { @@ -566,8 +553,8 @@ describe('MapStorage', () => { const addressA = Address.from('${keys[0].address}'); const addressB = Address.from('${keys[1].address}'); - const hashA = Hash256.from('${common.NEO_ASSET_HASH}'); - const hashB = Hash256.from('${common.GAS_ASSET_HASH}'); + const hashA = Hash256.from('${hashes.OLD_NEO_ASSET_HASH}'); + const hashB = Hash256.from('${hashes.OLD_GAS_ASSET_HASH}'); const keyA = 'keyA'; const keyB = 'keyB'; const keyC = 'keyC'; @@ -726,12 +713,8 @@ describe('MapStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} + private readonly storage = MapStorage.for<[Address, Hash256, string], number>(); public run(): void { @@ -799,8 +782,8 @@ describe('MapStorage', () => { `); }); - test('invalid object value - method', () => { - helpers.compileString( + test('invalid object value - method', async () => { + await helpers.compileString( ` import { SmartContract, MapStorage } from '@neo-one/smart-contract'; @@ -822,8 +805,8 @@ describe('MapStorage', () => { ); }); - test('invalid create', () => { - helpers.compileString( + test('invalid create', async () => { + await helpers.compileString( ` import { MapStorage } from '@neo-one/smart-contract'; @@ -833,8 +816,8 @@ describe('MapStorage', () => { ); }); - test('invalid reference', () => { - helpers.compileString( + test('invalid reference', async () => { + await helpers.compileString( ` import { MapStorage } from '@neo-one/smart-contract'; @@ -844,8 +827,8 @@ describe('MapStorage', () => { ); }); - test('invalid "reference"', () => { - helpers.compileString( + test('invalid "reference"', async () => { + await helpers.compileString( ` import { MapStorage } from '@neo-one/smart-contract'; @@ -855,8 +838,8 @@ describe('MapStorage', () => { ); }); - test('invalid reference - object', () => { - helpers.compileString( + test('invalid reference - object', async () => { + await helpers.compileString( ` import { MapStorage } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/output.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/output.test.ts deleted file mode 100644 index f29bffedf7..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/output.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { helpers } from '../../../../__data__'; - -describe('Output', () => { - test('cannot be implemented', async () => { - helpers.compileString( - ` - import { Output } from '@neo-one/smart-contract'; - - class MyOutput implements Output { - } - `, - { type: 'error' }, - ); - }); -}); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/publicKey/from.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/publicKey/from.test.ts index 0764f01e9b..00c85a96a3 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/publicKey/from.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/publicKey/from.test.ts @@ -14,7 +14,7 @@ describe('PublicKey.from', () => { }); test('Reports error on invalid public key', async () => { - helpers.compileString( + await helpers.compileString( ` import { PublicKey } from '@neo-one/smart-contract'; const keys = PublicKey.from('abc'); @@ -24,7 +24,7 @@ describe('PublicKey.from', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` import { PublicKey } from '@neo-one/smart-contract'; const keys = PublicKey.from; @@ -34,7 +34,7 @@ describe('PublicKey.from', () => { }); test('cannot be referenced - object', async () => { - helpers.compileString( + await helpers.compileString( ` import { PublicKey } from '@neo-one/smart-contract'; const { from } = PublicKey; @@ -44,7 +44,7 @@ describe('PublicKey.from', () => { }); test('cannot be element referenced', async () => { - helpers.compileString( + await helpers.compileString( ` import { PublicKey } from '@neo-one/smart-contract'; const keys = PublicKey['from']; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/publicKey/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/publicKey/index.test.ts index 44b42eb465..ad5765f9e6 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/publicKey/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/publicKey/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../../__data__'; describe('PublicKey', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` import { PublicKey } from '@neo-one/smart-contract'; class MyPublicKey implements PublicKey { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/scriptBuilder.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/scriptBuilder.test.ts new file mode 100644 index 0000000000..69d5d3c424 --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/scriptBuilder.test.ts @@ -0,0 +1,45 @@ +import { common, ScriptBuilder } from '@neo-one/client-common'; +import { BigNumber } from 'bignumber.js'; +import { helpers } from '../../../../__data__'; + +const properties = ` + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; +`; + +describe('Calling contract', () => { + test('Call with script', async () => { + const node = await helpers.startNode(); + + const contract = await node.addContract(` + import { SmartContract } from '@neo-one/smart-contract'; + + export class StorageContract extends SmartContract { + ${properties} + + public run(): string { + return 'hi'; + } + } + `); + + const result = await node.client.__call('priv', contract.address, 'run', ['run', []]); + // console.log(result); + + expect(result.state).toEqual('HALT'); + + const sb = new ScriptBuilder().emitAppCall(common.stringToUInt160(contract.contract.hash), 'run', 'run', []); + const resultAgain = await node.userAccountProviders.memory.__execute(sb.build().toString('hex'), { + from: node.masterWallet.userAccount.id, + maxSystemFee: new BigNumber(-1), + maxNetworkFee: new BigNumber(-1), + }); + const final = await resultAgain.confirmed(); + // console.log(final); + + expect(final.state).toEqual('HALT'); + }); +}); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/setStorage.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/setStorage.test.ts index de6dcd1a5f..50315bcf14 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/setStorage.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/setStorage.test.ts @@ -1,7 +1,14 @@ -import { common } from '@neo-one/client-common'; -import { helpers, keys } from '../../../../__data__'; +import { hashes, helpers, keys } from '../../../../__data__'; import { DiagnosticCode } from '../../../../DiagnosticCode'; +const properties = ` + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; +`; + describe('SetStorage', () => { test('add, delete, has', async () => { const node = await helpers.startNode(); @@ -10,12 +17,8 @@ describe('SetStorage', () => { import { SetStorage, SmartContract } from '@neo-one/smart-contract'; export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} + private readonly storage = SetStorage.for(); public run(): void { @@ -72,12 +75,8 @@ describe('SetStorage', () => { import { SetStorage, SmartContract } from '@neo-one/smart-contract'; export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} + private readonly storage = SetStorage.for(); public run(): void { @@ -148,8 +147,8 @@ describe('SetStorage', () => { const addressA = Address.from('${keys[0].address}'); const addressB = Address.from('${keys[1].address}'); - const hashA = Hash256.from('${common.NEO_ASSET_HASH}'); - const hashB = Hash256.from('${common.GAS_ASSET_HASH}'); + const hashA = Hash256.from('${hashes.OLD_NEO_ASSET_HASH}'); + const hashB = Hash256.from('${hashes.OLD_GAS_ASSET_HASH}'); const keyA = 'keyA'; const keyB = 'keyB'; const keyC = 'keyC'; @@ -268,12 +267,8 @@ describe('SetStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} + private readonly storage = SetStorage.for<[Address, Hash256, string]>(); public run(): void { @@ -310,8 +305,8 @@ describe('SetStorage', () => { const addressA = Address.from('${keys[0].address}'); const addressB = Address.from('${keys[1].address}'); - const hashA = Hash256.from('${common.NEO_ASSET_HASH}'); - const hashB = Hash256.from('${common.GAS_ASSET_HASH}'); + const hashA = Hash256.from('${hashes.OLD_NEO_ASSET_HASH}'); + const hashB = Hash256.from('${hashes.OLD_GAS_ASSET_HASH}'); const keyA = 'keyA'; const keyB = 'keyB'; const keyC = 'keyC'; @@ -395,12 +390,8 @@ describe('SetStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} + private readonly storage = SetStorage.for<[Address, Hash256, string]>(); public run(): void { @@ -435,8 +426,8 @@ describe('SetStorage', () => { const addressA = Address.from('${keys[0].address}'); const addressB = Address.from('${keys[1].address}'); - const hashA = Hash256.from('${common.NEO_ASSET_HASH}'); - const hashB = Hash256.from('${common.GAS_ASSET_HASH}'); + const hashA = Hash256.from('${hashes.OLD_NEO_ASSET_HASH}'); + const hashB = Hash256.from('${hashes.OLD_GAS_ASSET_HASH}'); const keyA = 'keyA'; const keyB = 'keyB'; const keyC = 'keyC'; @@ -549,12 +540,8 @@ describe('SetStorage', () => { } export class StorageContract extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'StorageContract', - }; + ${properties} + private readonly storage = SetStorage.for<[Address, Hash256, string]>(); public run(): void { @@ -581,8 +568,8 @@ describe('SetStorage', () => { `); }); - test('invalid create', () => { - helpers.compileString( + test('invalid create', async () => { + await helpers.compileString( ` import { SetStorage } from '@neo-one/smart-contract'; @@ -592,8 +579,8 @@ describe('SetStorage', () => { ); }); - test('invalid reference', () => { - helpers.compileString( + test('invalid reference', async () => { + await helpers.compileString( ` import { SetStorage } from '@neo-one/smart-contract'; @@ -603,8 +590,8 @@ describe('SetStorage', () => { ); }); - test('invalid "reference"', () => { - helpers.compileString( + test('invalid "reference"', async () => { + await helpers.compileString( ` import { SetStorage } from '@neo-one/smart-contract'; @@ -614,8 +601,8 @@ describe('SetStorage', () => { ); }); - test('invalid reference - object', () => { - helpers.compileString( + test('invalid reference - object', async () => { + await helpers.compileString( ` import { SetStorage } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/smartContract/__snapshots__/for.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/smartContract/__snapshots__/for.test.ts.snap index 6c487f9419..3bc6d10bda 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/smartContract/__snapshots__/for.test.ts.snap +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/smartContract/__snapshots__/for.test.ts.snap @@ -9,7 +9,7 @@ exports[`SmartContract.for reports error on any parameter 1`] = ` | ^ 6 | } 7 | - 8 | const sc = SmartContract.for(Address.from('ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW')); + 8 | const sc = SmartContract.for(Address.from('NNWAo5vdVJz1oyCuNiaTBA3amBHnWCF4Yk')); " `; @@ -18,7 +18,7 @@ exports[`SmartContract.for reports error on any properties 1`] = ` 6 | } 7 | - > 8 | const sc = SmartContract.for(Address.from('ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW')); + > 8 | const sc = SmartContract.for(Address.from('NNWAo5vdVJz1oyCuNiaTBA3amBHnWCF4Yk')); | ^ 9 | sc.bar(0); 10 | @@ -34,7 +34,7 @@ exports[`SmartContract.for reports error on any return 1`] = ` | ^ 6 | } 7 | - 8 | const sc = SmartContract.for(Address.from('ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW')); + 8 | const sc = SmartContract.for(Address.from('NNWAo5vdVJz1oyCuNiaTBA3amBHnWCF4Yk')); " `; @@ -43,7 +43,7 @@ exports[`SmartContract.for reports error on any smart contract type 1`] = ` 2 | import { Address, SmartContract } from '@neo-one/smart-contract'; 3 | - > 4 | const sc = SmartContract.for(Address.from('ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW')); + > 4 | const sc = SmartContract.for(Address.from('NNWAo5vdVJz1oyCuNiaTBA3amBHnWCF4Yk')); | ^ 5 | sc.bar(0); 6 | @@ -55,7 +55,7 @@ exports[`SmartContract.for reports error on invalid argument return - Object 1`] 10 | } 11 | - > 12 | SmartContract.for(Address.from('ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW')); + > 12 | SmartContract.for(Address.from('NNWAo5vdVJz1oyCuNiaTBA3amBHnWCF4Yk')); | ^ 13 | " @@ -70,7 +70,7 @@ exports[`SmartContract.for reports error on invalid argument return - union stri | ^ 6 | } 7 | - 8 | const sc = SmartContract.for(Address.from('ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW')); + 8 | const sc = SmartContract.for(Address.from('NNWAo5vdVJz1oyCuNiaTBA3amBHnWCF4Yk')); " `; @@ -79,7 +79,7 @@ exports[`SmartContract.for reports error on invalid argument values - Object 1`] 10 | } 11 | - > 12 | SmartContract.for(Address.from('ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW')); + > 12 | SmartContract.for(Address.from('NNWAo5vdVJz1oyCuNiaTBA3amBHnWCF4Yk')); | ^ 13 | " @@ -90,7 +90,7 @@ exports[`SmartContract.for reports error on invalid argument values - optional O 10 | } 11 | - > 12 | SmartContract.for(Address.from('ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW')); + > 12 | SmartContract.for(Address.from('NNWAo5vdVJz1oyCuNiaTBA3amBHnWCF4Yk')); | ^ 13 | " @@ -105,7 +105,7 @@ exports[`SmartContract.for reports error on missing return 1`] = ` | ^ 6 | } 7 | - 8 | const sc = SmartContract.for(Address.from('ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW')); + 8 | const sc = SmartContract.for(Address.from('NNWAo5vdVJz1oyCuNiaTBA3amBHnWCF4Yk')); " `; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/smartContract/for.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/smartContract/for.test.ts index fc228dc18c..ea6fbc9a34 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/smartContract/for.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/smartContract/for.test.ts @@ -1,8 +1,16 @@ import { helpers, keys } from '../../../../../__data__'; +const properties = ` + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; +`; + describe('SmartContract.for', () => { test('reports error on invalid argument values - Object', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address, SmartContract } from '@neo-one/smart-contract'; @@ -21,7 +29,7 @@ describe('SmartContract.for', () => { }); test('reports error on invalid argument values - optional Object', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address, SmartContract } from '@neo-one/smart-contract'; @@ -40,7 +48,7 @@ describe('SmartContract.for', () => { }); test('reports error on invalid argument return - Object', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address, SmartContract } from '@neo-one/smart-contract'; @@ -59,7 +67,7 @@ describe('SmartContract.for', () => { }); test('reports error on invalid argument return - union string | number', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address, SmartContract } from '@neo-one/smart-contract'; @@ -75,7 +83,7 @@ describe('SmartContract.for', () => { }); test('reports error on multiple call signatures', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address, SmartContract } from '@neo-one/smart-contract'; @@ -92,7 +100,7 @@ describe('SmartContract.for', () => { }); test('reports error on any parameter', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address, SmartContract } from '@neo-one/smart-contract'; @@ -108,7 +116,7 @@ describe('SmartContract.for', () => { }); test('reports error on any return', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address, SmartContract } from '@neo-one/smart-contract'; @@ -124,7 +132,7 @@ describe('SmartContract.for', () => { }); test('reports error on missing return', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address, SmartContract } from '@neo-one/smart-contract'; @@ -140,7 +148,7 @@ describe('SmartContract.for', () => { }); test('reports error on any smart contract type', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address, SmartContract } from '@neo-one/smart-contract'; @@ -152,7 +160,7 @@ describe('SmartContract.for', () => { }); test('reports error on any properties', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address, SmartContract } from '@neo-one/smart-contract'; @@ -173,12 +181,7 @@ describe('SmartContract.for', () => { import { SmartContract } from '@neo-one/smart-contract'; export class Dynamic extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'Foo', - }; + ${properties} public run(value: number): string { assertEqual(value, 10); @@ -196,12 +199,7 @@ describe('SmartContract.for', () => { } export class DynamicCall extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'Foo', - }; + ${properties} public run(value: Address): string { const contract = SmartContract.for(value); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/smartContract/upgrade.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/smartContract/upgrade.test.ts index b87d7c0b43..7f19e16bfd 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/smartContract/upgrade.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/smartContract/upgrade.test.ts @@ -1,15 +1,12 @@ -import { common, ContractParameterTypeModel as ContractParameterType, crypto } from '@neo-one/client-common'; -import { ContractPropertyStateModel as ContractPropertyState } from '@neo-one/client-full-common'; +import { common, crypto } from '@neo-one/client-common'; +import { contractRegisterToContractModel } from '@neo-one/client-full-core'; import { helpers } from '../../../../../__data__'; describe('SmartContract#upgrade', () => { test('upgrade and destroy', async () => { const node = await helpers.startNode(); - const parameterList = Buffer.from([ContractParameterType.String]); - const { - contract: { script: newContract }, - } = node.compileScript(` + const { contract: contractOut } = await node.compileScript(` import { SmartContract } from '@neo-one/smart-contract'; export class Contract extends SmartContract { @@ -27,7 +24,7 @@ describe('SmartContract#upgrade', () => { } } `); - const newContractHash = common.uInt160ToString(crypto.toScriptHash(Buffer.from(newContract, 'hex'))); + const newContractHash = common.uInt160ToString(crypto.toScriptHash(Buffer.from(contractOut.script, 'hex'))); const contract = await node.addContract(` import { SmartContract } from '@neo-one/smart-contract'; @@ -67,15 +64,8 @@ describe('SmartContract#upgrade', () => { assertEqual(contract.deploy(), true); assertEqual(contract.test(), 10); const result = contract.upgrade( - ${helpers.getBufferHash(newContract)}, - ${helpers.getBufferHash(parameterList.toString('hex'))}, - ${ContractParameterType.ByteArray}, - ${ContractPropertyState.HasStorageDynamicInvokePayable}, - "ContractMigrated", - "2.0", - "me", - "me@me.com", - "migrated contract" + ${helpers.getBufferHash(contractOut.script)}, + ${helpers.getBufferHash(contractRegisterToContractModel(contractOut).serializeWire().toString('hex'))} ); assertEqual(result, true); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/transaction.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/transaction.test.ts index 8a4266a1ea..627f90a124 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/transaction.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/transaction.test.ts @@ -1,127 +1,44 @@ -import { Attribute, AttributeUsageModel as AttributeUsage, common, Input, Output } from '@neo-one/client-common'; -import BigNumber from 'bignumber.js'; -import { helpers, keys } from '../../../../__data__'; +import { helpers } from '../../../../__data__'; import { DiagnosticCode } from '../../../../DiagnosticCode'; describe('Transaction', () => { test('properties', async () => { const node = await helpers.startNode(); const block = await node.readClient.getBlock(0); - const { transaction: invocationTransaction } = await node.executeString( + const transaction = block.transactions[0]; + await node.executeString( ` - import { Hash256, TransactionType, Transaction, } from '@neo-one/smart-contract'; + import { Transaction, Address, Hash256 } from '@neo-one/smart-contract'; const transaction = Transaction.for(Hash256.from('${block.transactions[0].hash}')); - assertEqual(transaction.type, TransactionType.Miner); + assertEqual(transaction instanceof Transaction, true); + assertEqual(transaction.height, ${block.index}); + assertEqual(transaction.version, ${transaction.version}); + assertEqual(transaction.nonce, ${transaction.nonce}); + assertEqual(transaction.sender, Address.from('${transaction.sender}')); + assertEqual(transaction.validUntilBlock, ${transaction.validUntilBlock}); + assertEqual(transaction.systemFee, ${transaction.systemFee.toString()}); + assertEqual(transaction.networkFee, ${transaction.networkFee.toString()}); + assertEqual(transaction.script, ${helpers.getBufferHash(transaction.script, 'base64')}); `, ); - const { transaction, confirmed } = await node.client.transfer( - [ - { - to: keys[0].address, - amount: new BigNumber(10), - asset: common.NEO_ASSET_HASH, - }, - ], - { - attributes: [ - { - usage: 'Description', - data: Buffer.from('Hello World', 'utf8').toString('hex'), - }, - ], - }, - ); - await confirmed(); - - const getUsage = (attribute: Attribute) => AttributeUsage[attribute.usage]; - - const checkAttribute = (idx: number, attribute: Attribute) => ` - attribute = attributes[${idx}]; - - assertEqual(attribute.usage, ${getUsage(attribute)}); - assertEqual(attribute.data.equals(${helpers.getBufferHash(attribute.data)}), true) - assertEqual(attribute instanceof AttributeBase, true); - `; - - const checkInput = (idx: number, input: Input) => ` - input = inputs[${idx}]; - - assertEqual(input.hash.equals(Hash256.from('${input.hash}')), true) - assertEqual(input.index, ${input.index}) - assertEqual(input instanceof Input, true); - `; - - const checkOutput = (idx: number, output: Output) => ` - output = outputs[${idx}]; - - assertEqual(output.asset.equals(Hash256.from('${output.asset}')), true); - assertEqual(output.value, ${helpers.getDecimal(output.value)}); - assertEqual(output.address.equals(Address.from('${output.address}')), true); - assertEqual(output instanceof Output, true); - `; - - const references = await Promise.all(transaction.inputs.map(async (input) => node.readClient.getOutput(input))); - - await node.executeString(` - import { TransactionBase, TransactionType, Transaction, Address, Hash256, Attribute, Output, Input, InvocationTransaction, AttributeBase } from '@neo-one/smart-contract'; - - const invocationTransaction = Transaction.for(Hash256.from('${ - invocationTransaction.hash - }')) as InvocationTransaction; - assertEqual(invocationTransaction.script.equals(${helpers.getBufferHash(invocationTransaction.script)}), true); - - const transaction = Transaction.for(Hash256.from('${transaction.hash}')) as InvocationTransaction; - - assertEqual(transaction.type, TransactionType.Invocation); - - const attributes = transaction.attributes; - assertEqual(attributes.length, ${transaction.attributes.length}); - - let attribute: Attribute; - ${transaction.attributes.map((attribute, idx) => checkAttribute(idx, attribute)).join('')} - - const inputs = transaction.inputs; - assertEqual(inputs.length, ${transaction.inputs.length}); - - let input: Input; - ${transaction.inputs.map((input, idx) => checkInput(idx, input)).join('')} - - let outputs = transaction.outputs; - assertEqual(outputs.length, ${transaction.outputs.length}); - - let output: Output; - ${transaction.outputs.map((output, idx) => checkOutput(idx, output)).join('')} - - outputs = transaction.unspentOutputs; - assertEqual(outputs.length, ${transaction.outputs.length}); - - ${transaction.outputs.map((output, idx) => checkOutput(idx, output)).join('')} - - outputs = transaction.references; - assertEqual(outputs.length, ${references.length}); - - ${references.map((output, idx) => checkOutput(idx, output)).join('')} - - assertEqual(transaction instanceof TransactionBase, true); - `); }); test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` - import { TransactionBase } from '@neo-one/smart-contract'; + import { Transaction } from '@neo-one/smart-contract'; - class MyTransaction implements TransactionBase { + class MyTransaction implements Transaction { } `, { type: 'error' }, ); }); - test('invalid reference', () => { - helpers.compileString( + test('invalid reference', async () => { + await helpers.compileString( ` import { Transaction } from '@neo-one/smart-contract'; @@ -131,8 +48,8 @@ describe('Transaction', () => { ); }); - test('invalid "reference"', () => { - helpers.compileString( + test('invalid "reference"', async () => { + await helpers.compileString( ` import { Transaction } from '@neo-one/smart-contract'; @@ -142,8 +59,8 @@ describe('Transaction', () => { ); }); - test('invalid reference - object', () => { - helpers.compileString( + test('invalid reference - object', async () => { + await helpers.compileString( ` import { Transaction } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/transactionType.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/transactionType.test.ts deleted file mode 100644 index 8699332d5a..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/contract/transactionType.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { helpers } from '../../../../__data__'; - -describe('TransactionType', () => { - test('properties', async () => { - await helpers.executeString(` - import { TransactionType } from '@neo-one/smart-contract'; - - const x = TransactionType; - assertEqual(x.Miner, 0x00); - assertEqual(TransactionType.Issue, 0x01); - assertEqual(TransactionType.Claim, 0x02); - assertEqual(TransactionType.Enrollment, 0x20); - assertEqual(TransactionType.Register, 0x40); - assertEqual(TransactionType.Contract, 0x80); - assertEqual(TransactionType.State, 0x90); - assertEqual(TransactionType.Publish, 0xd0); - assertEqual(TransactionType.Invocation, 0xd1); - `); - }); -}); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/error/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/error/index.test.ts index ce64ab357a..ba7bf0d449 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/error/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/error/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../__data__'; describe('Error', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` class MyError implements Error { public readonly message: string = 'foo'; @@ -13,7 +13,7 @@ describe('Error', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` class MyError extends Error { public readonly message: string = 'foo'; @@ -24,7 +24,7 @@ describe('Error', () => { }); test('cannot be mixin extended complex', async () => { - helpers.compileString( + await helpers.compileString( ` const foo = (value: typeof Error) => { class MyMyError extends value {} @@ -41,7 +41,7 @@ describe('Error', () => { }); test.skip('cannot be mixin extended complex', async () => { - helpers.compileString( + await helpers.compileString( ` const foo = (value: typeof Error) => { class MyMyError extends value {} diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/function/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/function/index.test.ts index cba153a78b..b3fce68854 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/function/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/function/index.test.ts @@ -9,7 +9,7 @@ describe('Function', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` class MyFunction extends Function { } diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iterable/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iterable/index.test.ts index ba90f8d68f..fe35323204 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iterable/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iterable/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../__data__'; describe('Iterable', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` class MyIterable implements Iterable { public readonly [Symbol.iterator]: any = 10; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iterableIterator/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iterableIterator/index.test.ts index 8c6e427493..d841181e8d 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iterableIterator/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iterableIterator/index.test.ts @@ -3,7 +3,7 @@ import { Builtin } from '../../../../compile/builtins'; describe('IterableIterator', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` class MyIterableIterator implements IterableIterator { public readonly next: any = () => ({ diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iterator/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iterator/index.test.ts index b042bf11ef..09e32ff7d9 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iterator/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iterator/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../__data__'; describe('Iterator', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` class MyIterator implements Iterator { public readonly next: any = () => ({ diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iteratorResult/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iteratorResult/index.test.ts index 201dc4e39d..a48adf4927 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iteratorResult/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/iteratorResult/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../__data__'; describe('IteratorResult', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` class MyIteratorResult implements IteratorResult { public readonly done = true; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/forEach.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/forEach.test.ts index 5471caf539..842a486bb6 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/forEach.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/forEach.test.ts @@ -40,7 +40,7 @@ describe('Map.prototype.forEach', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Map(); const y = x.forEach; @@ -50,7 +50,7 @@ describe('Map.prototype.forEach', () => { }); test('cannot be referenced - object literal', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Map(); const { forEach } = x; @@ -60,7 +60,7 @@ describe('Map.prototype.forEach', () => { }); test('cannot be "referenced"', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Map(); const y = x['forEach']; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/getSetHasDelete.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/getSetHasDelete.test.ts index 0ea4889f08..b81c83994c 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/getSetHasDelete.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/getSetHasDelete.test.ts @@ -23,23 +23,23 @@ describe('Map.prototype.get/set/has/delete', () => { `); }); - test('should respect reference semantics', async () => { + test('should respect NOT reference semantics', async () => { await helpers.executeString(` const x = new Map, string>(); const y = [0]; const z = [0]; x.set(y, 'bar').set(z, 'baz'); - assertEqual(x.get(y), 'bar'); + assertEqual(x.get(y), 'baz'); assertEqual(x.has(y), true); assertEqual(x.get(z), 'baz'); assertEqual(x.has(z), true); - assertEqual(x.get([0]), undefined); - assertEqual(x.has([0]), false); - assertEqual(x.size, 2); + assertEqual(x.get([0]), 'baz'); + assertEqual(x.has([0]), true); + assertEqual(x.size, 1); x.delete(y); - assertEqual(x.delete(z), true); + assertEqual(x.delete(z), false); assertEqual(x.delete(z), false); assertEqual(x.size, 0); assertEqual(x.get(y), undefined); @@ -106,7 +106,7 @@ describe('Map.prototype.get/set/has/delete', () => { }); test('get cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Map(); const y = x.get; @@ -116,7 +116,7 @@ describe('Map.prototype.get/set/has/delete', () => { }); test('set cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Map(); const y = x.set; @@ -126,7 +126,7 @@ describe('Map.prototype.get/set/has/delete', () => { }); test('has cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Map(); const y = x.has; @@ -136,7 +136,7 @@ describe('Map.prototype.get/set/has/delete', () => { }); test('delete cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Map(); const y = x.delete; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/index.test.ts index da12d1b9b2..f1883ecdd5 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/index.test.ts @@ -12,7 +12,7 @@ describe('Map', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` class MyMap extends Map { } diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/iterator.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/iterator.test.ts index d58bf68aec..71ba4740f2 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/iterator.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/iterator.test.ts @@ -80,7 +80,7 @@ describe('Map.prototype[Symbol.iterator]', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Map(); const y = x[Symbol.iterator]; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/size.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/size.test.ts index 1757577f41..5d151ebf95 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/size.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/map/size.test.ts @@ -29,7 +29,7 @@ describe('Map.prototype.size', () => { }); test('cannot set the size of an map', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Map(); x.size = 4; @@ -39,7 +39,7 @@ describe('Map.prototype.size', () => { }); test('cannot set the "size" of an map', async () => { - helpers.compileString( + await helpers.compileString( ` const x: { size: number } | Map = new Map() as { size: number } | Map; const a = 'size'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/number/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/number/index.test.ts index 31fc6efe2e..0a70663c33 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/number/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/number/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../__data__'; describe('Number', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` class MyNumber implements Number { } @@ -12,7 +12,7 @@ describe('Number', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` class MyNumber extends Number { } diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/object/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/object/index.test.ts index b6e3dffeb9..2ac1e0b26b 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/object/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/object/index.test.ts @@ -9,7 +9,7 @@ describe('Object', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` class MyObject extends Object { } @@ -19,7 +19,7 @@ describe('Object', () => { }); test('cannot match shape and pass to function', async () => { - helpers.compileString( + await helpers.compileString( ` const Obj = { keys: (o: {}): string[] => [], diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/object/keys.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/object/keys.test.ts index e6fbf07f54..9e4ce39cbf 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/object/keys.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/object/keys.test.ts @@ -86,7 +86,7 @@ describe('Object.keys', () => { }); test('should throw a type error for undefined', async () => { - helpers.compileString( + await helpers.compileString( ` const foo: number | undefined = undefined as number | undefined; let error: string | undefined; @@ -105,7 +105,7 @@ describe('Object.keys', () => { }); test('cannot be property referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const keys = Object.keys; `, @@ -114,7 +114,7 @@ describe('Object.keys', () => { }); test('cannot be property referenced - object literal', async () => { - helpers.compileString( + await helpers.compileString( ` const { keys } = Object; `, @@ -123,7 +123,7 @@ describe('Object.keys', () => { }); test('cannot be element referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const keys = Object['keys']; `, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/one/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/one/index.test.ts index 6e9eb533ef..9d524ad555 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/one/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/one/index.test.ts @@ -3,7 +3,7 @@ import { DiagnosticCode } from '../../../../DiagnosticCode'; describe('one', () => { test('cannot be referenced - one0', async () => { - helpers.compileString( + await helpers.compileString( ` const x = one0; `, @@ -12,7 +12,7 @@ describe('one', () => { }); test('cannot be referenced - one1', async () => { - helpers.compileString( + await helpers.compileString( ` const x = one1; `, @@ -21,7 +21,7 @@ describe('one', () => { }); test('cannot be referenced in property - one0', async () => { - helpers.compileString( + await helpers.compileString( ` const x = { [one0]: 'hello' }; `, @@ -30,7 +30,7 @@ describe('one', () => { }); test('cannot be referenced in property - one1', async () => { - helpers.compileString( + await helpers.compileString( ` const x = { [one1]: 'hello' }; `, @@ -39,7 +39,7 @@ describe('one', () => { }); test('cannot be referenced in property access - one0', async () => { - helpers.compileString( + await helpers.compileString( ` const error = new Error(); const x = error[one0]; @@ -49,7 +49,7 @@ describe('one', () => { }); test('cannot be referenced in property access - one1', async () => { - helpers.compileString( + await helpers.compileString( ` const error = new Error(); const x = error[one1]; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/regexp/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/regexp/index.test.ts index b8fa06f60d..540e48804a 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/regexp/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/regexp/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../__data__'; describe('RegExp', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` class MyRegExp implements RegExp { } @@ -12,7 +12,7 @@ describe('RegExp', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` class MyRegExp extends RegExp { } diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/forEach.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/forEach.test.ts index 13414b4262..52f6a6e365 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/forEach.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/forEach.test.ts @@ -25,7 +25,7 @@ describe('Set.prototype.forEach', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Set(); const y = x.forEach; @@ -35,7 +35,7 @@ describe('Set.prototype.forEach', () => { }); test('cannot be "referenced"', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Set(); const y = x['forEach']; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/hasAddDelete.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/hasAddDelete.test.ts index a5b0a1f233..08e47432af 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/hasAddDelete.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/hasAddDelete.test.ts @@ -20,7 +20,7 @@ describe('Set.prototype.hasAddDelete', () => { `); }); - test('should respect reference semantics', async () => { + test('should NOT respect reference semantics', async () => { await helpers.executeString(` const x = new Set>(); const y = [0]; @@ -29,11 +29,11 @@ describe('Set.prototype.hasAddDelete', () => { assertEqual(x.has(y), true); assertEqual(x.has(z), true); - assertEqual(x.has([0]), false); - assertEqual(x.size, 2); + assertEqual(x.has([0]), true); + assertEqual(x.size, 1); x.delete(y); - assertEqual(x.delete(z), true); + assertEqual(x.delete(z), false); assertEqual(x.delete(z), false); assertEqual(x.size, 0); assertEqual(x.has(y), false); @@ -68,7 +68,7 @@ describe('Set.prototype.hasAddDelete', () => { }); test('add cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Set(); const y = x.add; @@ -78,7 +78,7 @@ describe('Set.prototype.hasAddDelete', () => { }); test('has cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Set(); const y = x.has; @@ -88,7 +88,7 @@ describe('Set.prototype.hasAddDelete', () => { }); test('delete cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Set(); const y = x.delete; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/index.test.ts index 3662da930d..c5329a141f 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/index.test.ts @@ -12,7 +12,7 @@ describe('Set', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` class MySet extends Set { } diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/iterator.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/iterator.test.ts index 99c5f27f5a..48272c2246 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/iterator.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/iterator.test.ts @@ -88,7 +88,7 @@ describe('Set.prototype[Symbol.iterator]', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Set(); const y = x[Symbol.iterator]; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/size.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/size.test.ts index 8ca170b06d..6879f0f67e 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/size.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/set/size.test.ts @@ -29,7 +29,7 @@ describe('Set.prototype.size', () => { }); test('cannot set the size of an set', async () => { - helpers.compileString( + await helpers.compileString( ` const x = new Set(); x.size = 4; @@ -39,7 +39,7 @@ describe('Set.prototype.size', () => { }); test('cannot set the "size" of an set', async () => { - helpers.compileString( + await helpers.compileString( ` const x: { size: number } | Set = new Set() as { size: number } | Set; const a = 'size'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/string/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/string/index.test.ts index a05f7328fe..232ddd3128 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/string/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/string/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../__data__'; describe('String', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` class MyString implements String { } @@ -12,7 +12,7 @@ describe('String', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` class MyString extends String { } diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/for.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/for.test.ts index c8d309a016..503cd53f66 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/for.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/for.test.ts @@ -22,7 +22,7 @@ describe('Symbol.for', () => { }); test('cannot be referenced', async () => { - helpers.compileString( + await helpers.compileString( ` const value = Symbol.for; `, @@ -31,7 +31,7 @@ describe('Symbol.for', () => { }); test('cannot be referenced - object literal', async () => { - helpers.compileString( + await helpers.compileString( ` const { for } = Symbol; `, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/index.test.ts index 9e93c9c5fd..a7ee0f3986 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../__data__'; describe('Symbol', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` class MySymbol implements Symbol { } @@ -12,7 +12,7 @@ describe('Symbol', () => { }); test('cannot be extended', async () => { - helpers.compileString( + await helpers.compileString( ` class MySymbol extends Symbol { } diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/iterator.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/iterator.test.ts index dd43ccfc1b..5345ee69c8 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/iterator.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/iterator.test.ts @@ -16,7 +16,7 @@ describe('Symbol.iterator', () => { }); test('cannot be set', async () => { - helpers.compileString( + await helpers.compileString( ` Symbol.iterator = Symbol.for('foo'); `, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/toPrimitive.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/toPrimitive.test.ts index 7b7fe54842..21decae1d0 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/toPrimitive.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/symbol/toPrimitive.test.ts @@ -14,7 +14,7 @@ describe('Symbol.toPrimitive', () => { }); test('cannot be set', async () => { - helpers.compileString( + await helpers.compileString( ` Symbol.toPrimitive = Symbol.for('foo'); `, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/templateStringsArray/index.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/templateStringsArray/index.test.ts index 674466f85c..c583f5eb4c 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/templateStringsArray/index.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/builtins/templateStringsArray/index.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../../__data__'; describe('TemplateStringsArray', () => { test('cannot be implemented', async () => { - helpers.compileString( + await helpers.compileString( ` class MyTemplateStringsArray implements TemplateStringsArray { } diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/declaration/ClassDeclarationCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/declaration/ClassDeclarationCompiler.test.ts index f081393406..8b999e00ab 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/declaration/ClassDeclarationCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/declaration/ClassDeclarationCompiler.test.ts @@ -106,7 +106,7 @@ describe('ClassDeclarationCompiler', () => { }); test('basic class with ECMAScript private member, inaccessible', async () => { - helpers.compileString( + await helpers.compileString( ` class Foo { #x: string = 'bar'; @@ -124,7 +124,7 @@ describe('ClassDeclarationCompiler', () => { }); test('ECMAScript private member, no public modifier allowed', async () => { - helpers.compileString( + await helpers.compileString( ` class Foo { public #x: string = 'bar'; @@ -135,7 +135,7 @@ describe('ClassDeclarationCompiler', () => { }); test('ECMAScript private member, no private modifier allowed', async () => { - helpers.compileString( + await helpers.compileString( ` class Foo { private #x: string = 'bar'; @@ -536,7 +536,7 @@ describe('ClassDeclarationCompiler', () => { }); test('decorators', async () => { - helpers.compileString( + await helpers.compileString( ` function verify(target: any, propertyKey: string, descriptor: any): void { throw new Error('This should be transpiled.'); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/declaration/EnumDeclarationCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/declaration/EnumDeclarationCompiler.test.ts index e705029d03..969b1ef4fc 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/declaration/EnumDeclarationCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/declaration/EnumDeclarationCompiler.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../__data__'; describe('EnumDeclarationCompiler', () => { test('enum Foo', async () => { - helpers.compileString( + await helpers.compileString( ` enum Foo { x = 0, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/declaration/ImportDeclarationCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/declaration/ImportDeclarationCompiler.test.ts index 180131465f..a13bebae43 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/declaration/ImportDeclarationCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/declaration/ImportDeclarationCompiler.test.ts @@ -8,7 +8,7 @@ describe('ImportDeclarationCompiler', () => { }); test('export = unsupported', async () => { - helpers.compileString( + await helpers.compileString( ` const x = 'foo'; @@ -19,7 +19,7 @@ describe('ImportDeclarationCompiler', () => { }); test('import = unsupported', async () => { - helpers.compileString( + await helpers.compileString( ` import x = require('x'); `, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ArrayLiteralExpressionCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ArrayLiteralExpressionCompiler.test.ts index c519fa71a7..9ff8d0cb13 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ArrayLiteralExpressionCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ArrayLiteralExpressionCompiler.test.ts @@ -1,12 +1,11 @@ import { helpers } from '../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('ArrayLiteralExpressionCompiler', () => { @@ -131,6 +130,7 @@ describe('ArrayLiteralExpressionCompiler', () => { `); }); + // TODO test('array storage spread', async () => { const node = await helpers.startNode(); const contract = await node.addContract(` @@ -171,6 +171,7 @@ describe('ArrayLiteralExpressionCompiler', () => { `); }); + // TODO test('map storage', async () => { const node = await helpers.startNode(); const contract = await node.addContract(` @@ -216,6 +217,7 @@ describe('ArrayLiteralExpressionCompiler', () => { `); }); + // TODO test('set storage spread', async () => { const node = await helpers.startNode(); const contract = await node.addContract(` diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/AwaitExpressionCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/AwaitExpressionCompiler.test.ts index 10f1ae4dcf..7b045c5a86 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/AwaitExpressionCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/AwaitExpressionCompiler.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../__data__'; describe('AwaitFunctionCompiler', () => { test('await', async () => { - helpers.compileString( + await helpers.compileString( ` await 2; `, @@ -11,7 +11,7 @@ describe('AwaitFunctionCompiler', () => { }); test('await', async () => { - helpers.compileString( + await helpers.compileString( ` await 2; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/BinaryExpressionCompiler2.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/BinaryExpressionCompiler2.test.ts index 53efa0f152..b23051c777 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/BinaryExpressionCompiler2.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/BinaryExpressionCompiler2.test.ts @@ -108,9 +108,9 @@ describe('BinaryExpressionCompiler', () => { `); }); - test('(128 ^ 5) === 388 [CaretToken]', async () => { + test('(128 ^ 5) === 133 [CaretToken]', async () => { await helpers.executeString(` - if ((128 ^ 5) !== 388) { + if ((128 ^ 5) !== 133) { throw 'Failure'; } `); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/CallExpressionCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/CallExpressionCompiler.test.ts index 037dacb501..7d990abb00 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/CallExpressionCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/CallExpressionCompiler.test.ts @@ -370,7 +370,8 @@ describe('CallExpressionCompiler', () => { const baz = 2; const bar: { [foo]: { [baz]: (() => number) | null | undefined } } = { [foo]: { [baz]: undefined } } as unknown as { [foo]: { [baz]: (() => number) | null | undefined } }; - assertEqual(bar[foo][baz]?.(), undefined); + bar[foo]; + // assertEqual(bar[foo][baz]?.(), undefined); `); }); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/DeleteExpressionCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/DeleteExpressionCompiler.test.ts index 2101b284b6..552b52bfe4 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/DeleteExpressionCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/DeleteExpressionCompiler.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../__data__'; describe('DeleteExpressionCompiler', () => { test('unsupported', async () => { - helpers.compileString( + await helpers.compileString( ` const x = { foo: string }; delete x.foo; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ElementAccessExpressionCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ElementAccessExpressionCompiler.test.ts index cc0961a1d7..2fc12aee5a 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ElementAccessExpressionCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ElementAccessExpressionCompiler.test.ts @@ -26,7 +26,7 @@ describe('ElementAccessExpressionCompiler', () => { }); test('[0, 1, 2]["idx"]', async () => { - helpers.compileString( + await helpers.compileString( ` const x = [0, 1, 2] x['0']; @@ -56,7 +56,7 @@ describe('ElementAccessExpressionCompiler', () => { }); test('Buffer.from([0, 1, 2])["idx"]', async () => { - helpers.compileString( + await helpers.compileString( ` const x = ${helpers.getBuffer(buffer)}; x['0']; @@ -138,7 +138,7 @@ describe('ElementAccessExpressionCompiler', () => { }); test('Object["keys"]', async () => { - helpers.compileString( + await helpers.compileString( ` const x = Object['keys']; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ImportExpressionCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ImportExpressionCompiler.test.ts index c3bee7a3cc..9b955533dd 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ImportExpressionCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ImportExpressionCompiler.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../__data__'; describe('ImportExpressionCompiler', () => { test('import("foo")', async () => { - helpers.compileString( + await helpers.compileString( ` import('foo'); `, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/MetaPropertyCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/MetaPropertyCompiler.test.ts index 396dcc221b..cce7425e93 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/MetaPropertyCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/MetaPropertyCompiler.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../__data__'; describe('MetaPropertyCompiler', () => { test('import.meta', async () => { - helpers.compileString( + await helpers.compileString( ` import.meta; `, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ObjectLiteralExpressionCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ObjectLiteralExpressionCompiler.test.ts index 60b5daff4e..a7893e14e0 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ObjectLiteralExpressionCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/ObjectLiteralExpressionCompiler.test.ts @@ -119,7 +119,7 @@ describe('ObjectLiteralExpressionCompiler', () => { }); test('object with spread override errors', async () => { - helpers.compileString( + await helpers.compileString( ` const y = { a: 0, @@ -141,7 +141,7 @@ describe('ObjectLiteralExpressionCompiler', () => { }); test('private field identifier fails outside class', async () => { - helpers.compileString( + await helpers.compileString( ` const y = { a: 0, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/RegularExpressionLiteralCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/RegularExpressionLiteralCompiler.test.ts index 4170665085..2f5df7f32c 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/RegularExpressionLiteralCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/RegularExpressionLiteralCompiler.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../__data__'; describe('RegularExpressionLiteralCompiler', () => { test('/foo/', async () => { - helpers.compileString( + await helpers.compileString( ` /foo/ `, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/YieldExpressionCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/YieldExpressionCompiler.test.ts index 5a1ee44dc8..a5eef3eb13 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/YieldExpressionCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/expression/YieldExpressionCompiler.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../__data__'; describe('YieldExpressionCompiler', () => { test.skip('yield', async () => { - helpers.compileString( + await helpers.compileString( ` function* foo() { yield 'foo'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/bind/ObjectBindingHelper.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/bind/ObjectBindingHelper.test.ts index f74df23b6f..5be0543698 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/bind/ObjectBindingHelper.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/bind/ObjectBindingHelper.test.ts @@ -37,7 +37,7 @@ describe('ObjectBindingHelper', () => { }); test('builtin value computed property', async () => { - helpers.compileString( + await helpers.compileString( ` import { Blockchain } from '@neo-one/smart-contract'; const { ['currentTransaction']: currentTransaction } = Blockchain; @@ -49,7 +49,7 @@ describe('ObjectBindingHelper', () => { }); test('builtin value rest property', async () => { - helpers.compileString( + await helpers.compileString( ` import { Blockchain } from '@neo-one/smart-contract'; const { currentTransaction, ...rest } = Blockchain; @@ -61,7 +61,7 @@ describe('ObjectBindingHelper', () => { }); test('builtin value unknown property', async () => { - helpers.compileString( + await helpers.compileString( ` import { Blockchain } from '@neo-one/smart-contract'; const { 0: something } = Blockchain; @@ -73,7 +73,7 @@ describe('ObjectBindingHelper', () => { }); test('builtin value method property', async () => { - helpers.compileString( + await helpers.compileString( ` import { Address } from '@neo-one/smart-contract'; const { isSender } = Address; @@ -84,44 +84,46 @@ describe('ObjectBindingHelper', () => { ); }); + // TODO: come back to this when notifications are implemented test('builtin instance value', async () => { await helpers.executeString(` import { Blockchain } from '@neo-one/smart-contract'; - const { currentTransaction: { references } } = Blockchain; + const { currentTransaction: { notifications } } = Blockchain; assertEqual(references !== undefined, true); assertEqual(references.length, 0); `); }); + // TODO: come back to this when notifications are implemented test('builtin value string property', async () => { await helpers.executeString(` - import { Blockchain, Output } from '@neo-one/smart-contract'; - const { 'currentTransaction': { 'references': [value] } } = Blockchain; + import { Blockchain } from '@neo-one/smart-contract'; + const { 'currentTransaction': { 'notifications': [value] } } = Blockchain; - assertEqual(value as Output | undefined, undefined); + assertEqual(value !== undefined, true); `); }); test('builtin value instance computed property', async () => { - helpers.compileString( + await helpers.compileString( ` import { Blockchain } from '@neo-one/smart-contract'; - const { ['references']: references } = Blockchain.currentTransaction; + const { ['signers']: signers } = Blockchain.currentTransaction; - assertEqual(references !== undefined, true); + assertEqual(signers !== undefined, true); `, { type: 'error', code: DiagnosticCode.UnsupportedSyntax }, ); }); test('builtin instance value method property', async () => { - helpers.compileString( + await helpers.compileString( ` - import { Account, Address } from '@neo-one/smart-contract'; - const { getBalance } = Account.for(Address.from('${keys[0].address}')); + import { ArrayStorage } from '@neo-one/smart-contract'; + const { forEach } = ArrayStorage.for(); - assertEqual(getBalance !== undefined, true); + assertEqual(forEach !== undefined, true); `, { type: 'error', code: DiagnosticCode.InvalidBuiltinReference }, ); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/bind/__snapshots__/ObjectBindingHelper.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/bind/__snapshots__/ObjectBindingHelper.test.ts.snap index e0266ed21a..3c8d3b919d 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/bind/__snapshots__/ObjectBindingHelper.test.ts.snap +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/bind/__snapshots__/ObjectBindingHelper.test.ts.snap @@ -4,11 +4,11 @@ exports[`ObjectBindingHelper variable builtin instance value method property 1`] "snippetCode.ts (3,17): Builtin properties cannot be referenced 1 | - 2 | import { Account, Address } from '@neo-one/smart-contract'; - > 3 | const { getBalance } = Account.for(Address.from('ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW')); + 2 | import { ArrayStorage } from '@neo-one/smart-contract'; + > 3 | const { forEach } = ArrayStorage.for(); | ^ 4 | - 5 | assertEqual(getBalance !== undefined, true); + 5 | assertEqual(forEach !== undefined, true); 6 | " `; @@ -31,10 +31,10 @@ exports[`ObjectBindingHelper variable builtin value instance computed property 1 1 | 2 | import { Blockchain } from '@neo-one/smart-contract'; - > 3 | const { ['references']: references } = Blockchain.currentTransaction; + > 3 | const { ['signers']: signers } = Blockchain.currentTransaction; | ^ 4 | - 5 | assertEqual(references !== undefined, true); + 5 | assertEqual(signers !== undefined, true); 6 | " `; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper0.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper0.test.ts index 24a90a7845..835d05bcf0 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper0.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper0.test.ts @@ -1,16 +1,15 @@ import { helpers } from '../../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('InvokeSmartContractHelper', () => { - test('basic class no constructor', async () => { + test.only('basic class no constructor', async () => { const node = await helpers.startNode(); const contract = await node.addContract(` import { SmartContract } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper1.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper1.test.ts index 0b870c30bd..fe059c1cb2 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper1.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper1.test.ts @@ -1,12 +1,11 @@ import { helpers } from '../../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('InvokeSmartContractHelper', () => { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper10.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper10.test.ts index 67384a158e..619c225967 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper10.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper10.test.ts @@ -1,12 +1,11 @@ import { helpers } from '../../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('InvokeSmartContractHelper', () => { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper11.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper11.test.ts index edbd4363ab..00d4a3d362 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper11.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper11.test.ts @@ -3,12 +3,11 @@ import BigNumber from 'bignumber.js'; import { helpers, keys } from '../../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('InvokeSmartContractHelper', () => { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper2.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper2.test.ts index d73d2da672..8ca59dfb0b 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper2.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper2.test.ts @@ -1,12 +1,11 @@ import { helpers } from '../../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('InvokeSmartContractHelper', () => { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper3.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper3.test.ts index 51107880af..01c62e7e8a 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper3.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper3.test.ts @@ -1,12 +1,11 @@ import { helpers } from '../../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('InvokeSmartContractHelper', () => { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper4.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper4.test.ts index 647195dd3e..57236db42b 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper4.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper4.test.ts @@ -1,12 +1,11 @@ import { helpers } from '../../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('InvokeSmartContractHelper', () => { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper5.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper5.test.ts index a143168c3c..1fa8151dfc 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper5.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper5.test.ts @@ -1,12 +1,11 @@ import { helpers } from '../../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('InvokeSmartContractHelper', () => { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper6.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper6.test.ts index 977c5a6706..3b8c1a597c 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper6.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper6.test.ts @@ -5,10 +5,9 @@ import { helpers } from '../../../../__data__'; const properties = ` public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', + groups: [], + permissions: [], + trusts: "*", }; `; @@ -340,12 +339,8 @@ describe('InvokeSmartContractHelper', () => { } export class Token extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'NEO•ONE Token', - }; + ${properties} + public readonly name = 'One'; public readonly symbol = 'ONE'; public readonly decimals = 8; @@ -422,12 +417,8 @@ describe('InvokeSmartContractHelper', () => { ); export class Escrow extends SmartContract { - public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'Escrow account', - }; + ${properties} + private readonly balances = MapStorage.for<[Address, Address, Address], Fixed<8>>(); @constant diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper7.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper7.test.ts index b5e1fda0b7..a04fb9cbbc 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper7.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper7.test.ts @@ -1,12 +1,11 @@ import { helpers } from '../../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('InvokeSmartContractHelper', () => { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper8.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper8.test.ts index 7cf5b79d9a..626431cbfd 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper8.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper8.test.ts @@ -1,12 +1,11 @@ import { helpers } from '../../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('InvokeSmartContractHelper', () => { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper9.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper9.test.ts index 99e2922701..940838ef4b 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper9.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/contract/InvokeSmartContractHelper9.test.ts @@ -1,12 +1,11 @@ import { helpers } from '../../../../__data__'; const properties = ` -public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', -}; + public readonly properties = { + groups: [], + permissions: [], + trusts: "*", + }; `; describe('InvokeSmartContractHelper', () => { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/types/number/ToNumberHelper.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/types/number/ToNumberHelper.test.ts index ddf9dedc42..1edb054f21 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/types/number/ToNumberHelper.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/types/number/ToNumberHelper.test.ts @@ -48,7 +48,7 @@ describe('ToNumberHelper', () => { }); test('null', async () => { - helpers.compileString( + await helpers.compileString( ` const value: null = null; @@ -167,7 +167,7 @@ describe('ToNumberHelper', () => { }); test('symbol', async () => { - helpers.compileString( + await helpers.compileString( ` +Symbol.for('a'); `, @@ -176,7 +176,7 @@ describe('ToNumberHelper', () => { }); test('undefined', async () => { - helpers.compileString( + await helpers.compileString( ` const value: undefined = undefined; @@ -233,7 +233,7 @@ describe('ToNumberHelper', () => { }); test('null or number', async () => { - helpers.compileString( + await helpers.compileString( ` const value: null | number = null as null | number; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/types/string/ToStringHelper.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/types/string/ToStringHelper.test.ts index 156e00029b..e32c2ce38a 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/types/string/ToStringHelper.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/helper/types/string/ToStringHelper.test.ts @@ -98,7 +98,7 @@ describe('ToStringHelper', () => { }); test('symbol', async () => { - helpers.compileString( + await helpers.compileString( ` '' + Symbol.for('a'); `, diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/BreakStatementCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/BreakStatementCompiler.test.ts index 877b2093dc..1bf727a7e8 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/BreakStatementCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/BreakStatementCompiler.test.ts @@ -79,7 +79,7 @@ describe('BreakStatementCompiler', () => { }); test('break label', async () => { - helpers.compileString( + await helpers.compileString( ` let result = 0; foo: diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/ContinueStatementCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/ContinueStatementCompiler.test.ts index 65c0df0ef9..a27134be9e 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/ContinueStatementCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/ContinueStatementCompiler.test.ts @@ -37,7 +37,7 @@ describe('ContinueStatementCompiler', () => { }); test('continue label', async () => { - helpers.compileString( + await helpers.compileString( ` let result = 0; foo: diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/DebuggerStatementCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/DebuggerStatementCompiler.test.ts index b7a9f350c5..be5ac42a6b 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/DebuggerStatementCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/DebuggerStatementCompiler.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../__data__'; describe('DebuggerStatementCompiler', () => { test('simple', async () => { - helpers.compileString( + await helpers.compileString( ` let result = 0; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/LabeledStatementCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/LabeledStatementCompiler.test.ts index 7e1fd9845f..067da145eb 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/LabeledStatementCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/LabeledStatementCompiler.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../__data__'; describe('LabeledStatementCompiler', () => { test('simple', async () => { - helpers.compileString( + await helpers.compileString( ` loop1: for (let i = 0; i < 3; i++) { diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/SwitchStatementCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/SwitchStatementCompiler.test.ts index eb82772dd1..abd8a81ed2 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/SwitchStatementCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/SwitchStatementCompiler.test.ts @@ -125,7 +125,7 @@ describe('SwitchStatementCompiler', () => { export class TestSmartContract extends SmartContract { - public foo(): number { + public foo(): void { const attribute: number = 0; switch(attribute) { @@ -135,7 +135,7 @@ describe('SwitchStatementCompiler', () => { } // checking that this code runs after the break statement - return 10; + assertEqual(attribute, 0); } } `); @@ -145,11 +145,13 @@ describe('SwitchStatementCompiler', () => { interface Contract { deploy(): boolean; - foo(): number; + foo(): void; } const contract = SmartContract.for(Address.from('${contract.address}')); - assertEqual(contract.foo(), 10); + contract.foo(); + + // assertEqual(contract.foo(), 10); `); }); }); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/WithStatementCompiler.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/WithStatementCompiler.test.ts index 62855a29c8..0614de1e5f 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/WithStatementCompiler.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/compile/statement/WithStatementCompiler.test.ts @@ -2,7 +2,7 @@ import { helpers } from '../../../__data__'; describe('WithStatementCompiler', () => { test('simple', async () => { - helpers.compileString( + await helpers.compileString( ` let result = 0; const x = { y: 1 }; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/contract/ABISmartContractProcessor.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/contract/ABISmartContractProcessor.test.ts index 69f98c572f..35d6b68b06 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/contract/ABISmartContractProcessor.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/contract/ABISmartContractProcessor.test.ts @@ -3,16 +3,15 @@ import { DiagnosticCode } from '../../DiagnosticCode'; const properties = ` public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', + trusts: '*', + permissions: [], + groups: [], }; `; describe('ABISmartContractProcessor', () => { - test('no duplicate events', () => { - helpers.compileString( + test('no duplicate events', async () => { + await helpers.compileString( ` import { SmartContract, createEventNotifier } from '@neo-one/smart-contract'; @@ -30,8 +29,8 @@ describe('ABISmartContractProcessor', () => { ); }); - test('invalid method parameter', () => { - helpers.compileString( + test('invalid method parameter', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -49,8 +48,8 @@ describe('ABISmartContractProcessor', () => { ); }); - test('invalid method return', () => { - helpers.compileString( + test('invalid method return', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -68,8 +67,8 @@ describe('ABISmartContractProcessor', () => { ); }); - test('invalid method return - union', () => { - helpers.compileString( + test('invalid method return - union', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -90,8 +89,8 @@ describe('ABISmartContractProcessor', () => { ); }); - test('invalid getter', () => { - helpers.compileString( + test('invalid getter', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -109,8 +108,8 @@ describe('ABISmartContractProcessor', () => { ); }); - test('invalid setter', () => { - helpers.compileString( + test('invalid setter', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -132,8 +131,8 @@ describe('ABISmartContractProcessor', () => { ); }); - test('invalid getter + setter', () => { - helpers.compileString( + test('invalid getter + setter', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/contract/ContractInfoProcessor.test.ts b/packages/neo-one-smart-contract-compiler/src/__tests__/contract/ContractInfoProcessor.test.ts index fa0f223cc6..39b8289173 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/contract/ContractInfoProcessor.test.ts +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/contract/ContractInfoProcessor.test.ts @@ -3,10 +3,9 @@ import { DiagnosticCode } from '../../DiagnosticCode'; const properties = ` public readonly properties = { - codeVersion: '1.0', - author: 'dicarlo2', - email: 'alex.dicarlo@neotracker.io', - description: 'The TestSmartContract', + trusts: '*', + permissions: [], + groups: [], }; `; @@ -22,8 +21,8 @@ describe('ContractInfoProcessor', () => { `); }); - test('no symbol properties', () => { - helpers.compileString( + test('no symbol properties', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -36,8 +35,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('no computed properties', () => { - helpers.compileString( + test('no computed properties', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -50,8 +49,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('no computed methods', () => { - helpers.compileString( + test('no computed methods', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -66,8 +65,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('no static properties', () => { - helpers.compileString( + test('no static properties', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -80,8 +79,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('no static methods', () => { - helpers.compileString( + test('no static methods', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -96,8 +95,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('no method decorators', () => { - helpers.compileString( + test('no method decorators', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -118,8 +117,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('no method parameter decorators', () => { - helpers.compileString( + test('no method parameter decorators', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -139,8 +138,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('no get accessor method decorators', () => { - helpers.compileString( + test('no get accessor method decorators', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -166,8 +165,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('no set accessor method decorators', () => { - helpers.compileString( + test('no set accessor method decorators', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -193,8 +192,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('no set accessor parameter decorators', () => { - helpers.compileString( + test('no set accessor parameter decorators', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -219,8 +218,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('no deploy method', () => { - helpers.compileString( + test('no deploy method', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -236,8 +235,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('multiple smart contracts', () => { - helpers.compileString( + test('multiple smart contracts', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -253,8 +252,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('abstract smart contracts', () => { - helpers.compileString( + test('abstract smart contracts', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -266,8 +265,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('new SmartContract()', () => { - helpers.compileString( + test('new SmartContract()', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -281,8 +280,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('@receive with @constant', () => { - helpers.compileString( + test('@receive with @constant', async () => { + await helpers.compileString( ` import { SmartContract, receive, constant } from '@neo-one/smart-contract'; @@ -300,46 +299,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('@sendUnsafe with @constant', () => { - helpers.compileString( - ` - import { SmartContract, sendUnsafe, constant } from '@neo-one/smart-contract'; - - export class TestSmartContract extends SmartContract { - ${properties} - - @sendUnsafe - @constant - public verify(): boolean { - return true; - } - } - `, - { type: 'error', code: DiagnosticCode.InvalidContractMethod }, - ); - }); - - test('@claim with @constant', () => { - helpers.compileString( - ` - import { SmartContract, claim, constant } from '@neo-one/smart-contract'; - - export class TestSmartContract extends SmartContract { - ${properties} - - @claim - @constant - public verify(): boolean { - return true; - } - } - `, - { type: 'error', code: DiagnosticCode.InvalidContractMethod }, - ); - }); - - test('structured storage set in constructor', () => { - helpers.compileString( + test('structured storage set in constructor', async () => { + await helpers.compileString( ` import { SmartContract, MapStorage } from '@neo-one/smart-contract'; @@ -356,8 +317,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('structured storage set public', () => { - helpers.compileString( + test('structured storage set public', async () => { + await helpers.compileString( ` import { SmartContract, MapStorage } from '@neo-one/smart-contract'; @@ -370,8 +331,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('structured storage private modifiable', () => { - helpers.compileString( + test('structured storage private modifiable', async () => { + await helpers.compileString( ` import { SmartContract, MapStorage } from '@neo-one/smart-contract'; @@ -384,8 +345,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('structured storage protected abstract', () => { - helpers.compileString( + test('structured storage protected abstract', async () => { + await helpers.compileString( ` import { SmartContract, MapStorage } from '@neo-one/smart-contract'; @@ -398,8 +359,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('invalid storage type', () => { - helpers.compileString( + test('invalid storage type', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -414,8 +375,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('invalid storage structured array type', () => { - helpers.compileString( + test('invalid storage structured array type', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -430,8 +391,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('invalid storage structured map type', () => { - helpers.compileString( + test('invalid storage structured map type', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -446,8 +407,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('invalid storage structured set type', () => { - helpers.compileString( + test('invalid storage structured set type', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -462,8 +423,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('invalid property function not readonly', () => { - helpers.compileString( + test('invalid property function not readonly', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -478,8 +439,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('invalid property function set in constructor', () => { - helpers.compileString( + test('invalid property function set in constructor', async () => { + await helpers.compileString( ` import { SmartContract } from '@neo-one/smart-contract'; @@ -499,26 +460,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('invalid @sendUnsafe method with ForwardValue', () => { - helpers.compileString( - ` - import { SmartContract, ForwardValue, sendUnsafe } from '@neo-one/smart-contract'; - - export class TestSmartContract extends SmartContract { - ${properties} - - @sendUnsafe - public foo(value: ForwardValue): boolean { - return true; - } - } - `, - { type: 'error', code: DiagnosticCode.InvalidContractType }, - ); - }); - - test('invalid @receive method with ForwardValue', () => { - helpers.compileString( + test('invalid @receive method with ForwardValue', async () => { + await helpers.compileString( ` import { SmartContract, ForwardValue, receive } from '@neo-one/smart-contract'; @@ -535,43 +478,8 @@ describe('ContractInfoProcessor', () => { ); }); - test('invalid @claim method with ForwardValue', () => { - helpers.compileString( - ` - import { SmartContract, ForwardValue, claim } from '@neo-one/smart-contract'; - - export class TestSmartContract extends SmartContract { - ${properties} - - @claim - public foo(value: ForwardValue): void { - } - } - `, - { type: 'error', code: DiagnosticCode.InvalidContractType }, - ); - }); - - test('invalid @sendUnsafe method with ForwardedValue', () => { - helpers.compileString( - ` - import { SmartContract, ForwardedValue, sendUnsafe } from '@neo-one/smart-contract'; - - export class TestSmartContract extends SmartContract { - ${properties} - - @sendUnsafe - public foo(value: ForwardedValue): boolean { - return true; - } - } - `, - { type: 'error', code: DiagnosticCode.InvalidContractType }, - ); - }); - - test('invalid @receive method with ForwardedValue', () => { - helpers.compileString( + test('invalid @receive method with ForwardedValue', async () => { + await helpers.compileString( ` import { SmartContract, ForwardedValue, receive } from '@neo-one/smart-contract'; @@ -587,21 +495,4 @@ describe('ContractInfoProcessor', () => { { type: 'error', code: DiagnosticCode.InvalidContractType }, ); }); - - test('invalid @claim method with ForwardedValue', () => { - helpers.compileString( - ` - import { SmartContract, ForwardedValue, claim } from '@neo-one/smart-contract'; - - export class TestSmartContract extends SmartContract { - ${properties} - - @claim - public foo(value: ForwardedValue): void { - } - } - `, - { type: 'error', code: DiagnosticCode.InvalidContractType }, - ); - }); }); diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/contract/__snapshots__/ABISmartContractProcessor.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/contract/__snapshots__/ABISmartContractProcessor.test.ts.snap index 1f6b72ac00..5e64f07dca 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/contract/__snapshots__/ABISmartContractProcessor.test.ts.snap +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/contract/__snapshots__/ABISmartContractProcessor.test.ts.snap @@ -40,15 +40,15 @@ exports[`ABISmartContractProcessor invalid method parameter 1`] = ` `; exports[`ABISmartContractProcessor invalid method return - union 1`] = ` -"snippetCode.ts (15,9): Invalid SmartContract type. See https://neo-one.io/docs/methods#Parameter-and-Return-Types for valid parameter and return types. +"snippetCode.ts (14,9): Invalid SmartContract type. See https://neo-one.io/docs/methods#Parameter-and-Return-Types for valid parameter and return types. - 13 | private foo: boolean = true; - 14 | - > 15 | public test() { + 12 | private foo: boolean = true; + 13 | + > 14 | public test() { | ^ - 16 | if (this.foo) { - 17 | return ''; - 18 | } + 15 | if (this.foo) { + 16 | return ''; + 17 | } " `; diff --git a/packages/neo-one-smart-contract-compiler/src/__tests__/contract/__snapshots__/ContractInfoProcessor.test.ts.snap b/packages/neo-one-smart-contract-compiler/src/__tests__/contract/__snapshots__/ContractInfoProcessor.test.ts.snap index 2c86bd59e4..503089f8cc 100644 --- a/packages/neo-one-smart-contract-compiler/src/__tests__/contract/__snapshots__/ContractInfoProcessor.test.ts.snap +++ b/packages/neo-one-smart-contract-compiler/src/__tests__/contract/__snapshots__/ContractInfoProcessor.test.ts.snap @@ -1,18 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`ContractInfoProcessor @claim with @constant 1`] = ` -"snippetCode.ts (15,9): SmartContract methods marked with @send, @sendUnsafe, @receive or @claim cannot be @constant. - - 13 | - 14 | @claim - > 15 | @constant - | ^ - 16 | public verify(): boolean { - 17 | return true; - 18 | } -" -`; - exports[`ContractInfoProcessor @receive with @constant 1`] = ` "snippetCode.ts (15,9): SmartContract methods marked with @send, @sendUnsafe, @receive or @claim cannot be @constant. @@ -26,19 +13,6 @@ exports[`ContractInfoProcessor @receive with @constant 1`] = ` " `; -exports[`ContractInfoProcessor @sendUnsafe with @constant 1`] = ` -"snippetCode.ts (15,9): SmartContract methods marked with @send, @sendUnsafe, @receive or @claim cannot be @constant. - - 13 | - 14 | @sendUnsafe - > 15 | @constant - | ^ - 16 | public verify(): boolean { - 17 | return true; - 18 | } -" -`; - exports[`ContractInfoProcessor abstract smart contracts 1`] = ` "snippetCode.ts (4,7): Cannot compile abstract SmartContract. @@ -48,33 +22,7 @@ exports[`ContractInfoProcessor abstract smart contracts 1`] = ` | ^ 5 | 6 | public readonly properties = { - 7 | codeVersion: '1.0', -" -`; - -exports[`ContractInfoProcessor invalid @claim method with ForwardValue 1`] = ` -"snippetCode.ts (15,20): Cannot use ForwardValue or ForwardedValue as parameters for methods marked with @send, @sendUnsafe, @receive or @claim. - - 13 | - 14 | @claim - > 15 | public foo(value: ForwardValue): void { - | ^ - 16 | } - 17 | } - 18 | -" -`; - -exports[`ContractInfoProcessor invalid @claim method with ForwardedValue 1`] = ` -"snippetCode.ts (15,20): Cannot use ForwardValue or ForwardedValue as parameters for methods marked with @send, @sendUnsafe, @receive or @claim. - - 13 | - 14 | @claim - > 15 | public foo(value: ForwardedValue): void { - | ^ - 16 | } - 17 | } - 18 | + 7 | trusts: '*', " `; @@ -104,315 +52,289 @@ exports[`ContractInfoProcessor invalid @receive method with ForwardedValue 1`] = " `; -exports[`ContractInfoProcessor invalid @sendUnsafe method with ForwardValue 1`] = ` -"snippetCode.ts (15,20): Cannot use ForwardValue or ForwardedValue as parameters for methods marked with @send, @sendUnsafe, @receive or @claim. - - 13 | - 14 | @sendUnsafe - > 15 | public foo(value: ForwardValue): boolean { - | ^ - 16 | return true; - 17 | } - 18 | } -" -`; - -exports[`ContractInfoProcessor invalid @sendUnsafe method with ForwardedValue 1`] = ` -"snippetCode.ts (15,20): Cannot use ForwardValue or ForwardedValue as parameters for methods marked with @send, @sendUnsafe, @receive or @claim. - - 13 | - 14 | @sendUnsafe - > 15 | public foo(value: ForwardedValue): boolean { - | ^ - 16 | return true; - 17 | } - 18 | } -" -`; - exports[`ContractInfoProcessor invalid property function not readonly 1`] = ` -"snippetCode.ts (13,9): Invalid SmartContract storage type. See https://neo-one.io/docs/properties-and-storage#Storage-Types for valid storage types. +"snippetCode.ts (12,9): Invalid SmartContract storage type. See https://neo-one.io/docs/properties-and-storage#Storage-Types for valid storage types. - 11 | }; - 12 | - > 13 | private foo = () => { + 10 | }; + 11 | + > 12 | private foo = () => { | ^ - 14 | // do nothing - 15 | } - 16 | } + 13 | // do nothing + 14 | } + 15 | } " `; exports[`ContractInfoProcessor invalid property function set in constructor 1`] = ` -"snippetCode.ts (13,9): Invalid SmartContract storage type. See https://neo-one.io/docs/properties-and-storage#Storage-Types for valid storage types. +"snippetCode.ts (12,9): Invalid SmartContract storage type. See https://neo-one.io/docs/properties-and-storage#Storage-Types for valid storage types. - 11 | }; - 12 | - > 13 | private readonly foo: () => void; + 10 | }; + 11 | + > 12 | private readonly foo: () => void; | ^ - 14 | - 15 | public constructor() { - 16 | super(); + 13 | + 14 | public constructor() { + 15 | super(); " `; exports[`ContractInfoProcessor invalid storage structured array type 1`] = ` -"snippetCode.ts (15,9): Invalid SmartContract storage type. See https://neo-one.io/docs/properties-and-storage#Storage-Types for valid storage types. +"snippetCode.ts (14,9): Invalid SmartContract storage type. See https://neo-one.io/docs/properties-and-storage#Storage-Types for valid storage types. - 13 | }; - 14 | - > 15 | private readonly foo: Array = [new Foo()]; + 12 | }; + 13 | + > 14 | private readonly foo: Array = [new Foo()]; | ^ - 16 | } - 17 | + 15 | } + 16 | " `; exports[`ContractInfoProcessor invalid storage structured map type 1`] = ` -"snippetCode.ts (15,9): Invalid SmartContract storage type. See https://neo-one.io/docs/properties-and-storage#Storage-Types for valid storage types. +"snippetCode.ts (14,9): Invalid SmartContract storage type. See https://neo-one.io/docs/properties-and-storage#Storage-Types for valid storage types. - 13 | }; - 14 | - > 15 | private readonly foo: Array> = [new Map().set('foo', new Foo())]; + 12 | }; + 13 | + > 14 | private readonly foo: Array> = [new Map().set('foo', new Foo())]; | ^ - 16 | } - 17 | + 15 | } + 16 | " `; exports[`ContractInfoProcessor invalid storage structured set type 1`] = ` -"snippetCode.ts (15,9): Invalid SmartContract storage type. See https://neo-one.io/docs/properties-and-storage#Storage-Types for valid storage types. +"snippetCode.ts (14,9): Invalid SmartContract storage type. See https://neo-one.io/docs/properties-and-storage#Storage-Types for valid storage types. - 13 | }; - 14 | - > 15 | private readonly foo: Set> = new Set([new Map().set('foo', new Foo())]); + 12 | }; + 13 | + > 14 | private readonly foo: Set> = new Set([new Map().set('foo', new Foo())]); | ^ - 16 | } - 17 | + 15 | } + 16 | " `; exports[`ContractInfoProcessor invalid storage type 1`] = ` -"snippetCode.ts (15,9): Invalid SmartContract storage type. See https://neo-one.io/docs/properties-and-storage#Storage-Types for valid storage types. +"snippetCode.ts (14,9): Invalid SmartContract storage type. See https://neo-one.io/docs/properties-and-storage#Storage-Types for valid storage types. - 13 | }; - 14 | - > 15 | private readonly foo: Foo = new Foo(); + 12 | }; + 13 | + > 14 | private readonly foo: Foo = new Foo(); | ^ - 16 | } - 17 | + 15 | } + 16 | " `; exports[`ContractInfoProcessor multiple smart contracts 1`] = ` -"snippetCode.ts (15,7): Multiple exported SmartContracts in one file is not supported. +"snippetCode.ts (14,7): Multiple exported SmartContracts in one file is not supported. - 13 | } - 14 | - > 15 | export class TestSmartContract2 extends SmartContract { + 12 | } + 13 | + > 14 | export class TestSmartContract2 extends SmartContract { | ^ - 16 | - 17 | public readonly properties = { - 18 | codeVersion: '1.0', + 15 | + 16 | public readonly properties = { + 17 | trusts: '*', " `; exports[`ContractInfoProcessor new SmartContract() 1`] = ` -"snippetCode.ts (15,7): Cannot construct a SmartContract +"snippetCode.ts (14,7): Cannot construct a SmartContract - 13 | } - 14 | - > 15 | new TestSmartContract(); + 12 | } + 13 | + > 14 | new TestSmartContract(); | ^ - 16 | + 15 | " `; exports[`ContractInfoProcessor no computed methods 1`] = ` -"snippetCode.ts (13,16): SmartContracts cannot have computed methods or properties. +"snippetCode.ts (12,16): SmartContracts cannot have computed methods or properties. - 11 | }; - 12 | - > 13 | public ['foo'](): string { + 10 | }; + 11 | + > 12 | public ['foo'](): string { | ^ - 14 | return 'foo'; - 15 | } - 16 | } + 13 | return 'foo'; + 14 | } + 15 | } " `; exports[`ContractInfoProcessor no computed properties 1`] = ` -"snippetCode.ts (13,25): SmartContracts cannot have computed methods or properties. +"snippetCode.ts (12,25): SmartContracts cannot have computed methods or properties. - 11 | }; - 12 | - > 13 | public readonly ['foo']: string = 'foo'; + 10 | }; + 11 | + > 12 | public readonly ['foo']: string = 'foo'; | ^ - 14 | } - 15 | + 13 | } + 14 | " `; exports[`ContractInfoProcessor no deploy method 1`] = ` -"snippetCode.ts (14,16): deploy is a reserved method name in SmartContracts. +"snippetCode.ts (13,16): deploy is a reserved method name in SmartContracts. + 11 | 12 | - 13 | - > 14 | public deploy(): void { + > 13 | public deploy(): void { | ^ - 15 | // do nothing - 16 | } - 17 | } + 14 | // do nothing + 15 | } + 16 | } " `; exports[`ContractInfoProcessor no get accessor method decorators 1`] = ` -"snippetCode.ts (19,9): Custom decorators are not supported +"snippetCode.ts (18,9): Custom decorators are not supported - 17 | private x: string = 'foo'; - 18 | - > 19 | @dec + 16 | private x: string = 'foo'; + 17 | + > 18 | @dec | ^ - 20 | public get foo(): string { - 21 | return this.x; - 22 | } + 19 | public get foo(): string { + 20 | return this.x; + 21 | } " `; exports[`ContractInfoProcessor no method decorators 1`] = ` -"snippetCode.ts (18,9): Custom decorators are not supported +"snippetCode.ts (17,9): Custom decorators are not supported + 15 | 16 | - 17 | - > 18 | @dec + > 17 | @dec | ^ - 19 | public foo() { - 20 | return 'foo'; - 21 | } + 18 | public foo() { + 19 | return 'foo'; + 20 | } " `; exports[`ContractInfoProcessor no method parameter decorators 1`] = ` -"snippetCode.ts (18,20): Custom decorators are not supported +"snippetCode.ts (17,20): Custom decorators are not supported + 15 | 16 | - 17 | - > 18 | public foo(@dec value: string) { + > 17 | public foo(@dec value: string) { | ^ - 19 | return 'foo'; - 20 | } - 21 | } + 18 | return 'foo'; + 19 | } + 20 | } " `; exports[`ContractInfoProcessor no set accessor method decorators 1`] = ` -"snippetCode.ts (23,9): Custom decorators are not supported +"snippetCode.ts (22,9): Custom decorators are not supported - 21 | } - 22 | - > 23 | @dec + 20 | } + 21 | + > 22 | @dec | ^ - 24 | public set foo(value: string) { - 25 | this.x = value; - 26 | } + 23 | public set foo(value: string) { + 24 | this.x = value; + 25 | } " `; exports[`ContractInfoProcessor no set accessor parameter decorators 1`] = ` -"snippetCode.ts (23,24): Custom decorators are not supported +"snippetCode.ts (22,24): Custom decorators are not supported - 21 | } - 22 | - > 23 | public set foo(@dec value: string) { + 20 | } + 21 | + > 22 | public set foo(@dec value: string) { | ^ - 24 | this.x = value; - 25 | } - 26 | } + 23 | this.x = value; + 24 | } + 25 | } " `; exports[`ContractInfoProcessor no static methods 1`] = ` -"snippetCode.ts (13,16): SmartContracts cannot have static methods or properties. +"snippetCode.ts (12,16): SmartContracts cannot have static methods or properties. - 11 | }; - 12 | - > 13 | public static foo() { + 10 | }; + 11 | + > 12 | public static foo() { | ^ - 14 | return 'foo'; - 15 | } - 16 | } + 13 | return 'foo'; + 14 | } + 15 | } " `; exports[`ContractInfoProcessor no static properties 1`] = ` -"snippetCode.ts (13,16): SmartContracts cannot have static methods or properties. +"snippetCode.ts (12,16): SmartContracts cannot have static methods or properties. - 11 | }; - 12 | - > 13 | public static readonly foo = 'foo'; + 10 | }; + 11 | + > 12 | public static readonly foo = 'foo'; | ^ - 14 | } - 15 | + 13 | } + 14 | " `; exports[`ContractInfoProcessor no symbol properties 1`] = ` -"snippetCode.ts (13,25): SmartContracts cannot have computed methods or properties. +"snippetCode.ts (12,25): SmartContracts cannot have computed methods or properties. - 11 | }; - 12 | - > 13 | public readonly [Symbol.iterator]: string = 'foo'; + 10 | }; + 11 | + > 12 | public readonly [Symbol.iterator]: string = 'foo'; | ^ - 14 | } - 15 | + 13 | } + 14 | " `; exports[`ContractInfoProcessor structured storage private modifiable 1`] = ` -"snippetCode.ts (13,9): Persistent storage classes may only be used as SmartContract private or protected readonly properties with a property initializer. +"snippetCode.ts (12,9): Persistent storage classes may only be used as SmartContract private or protected readonly properties with a property initializer. - 11 | }; - 12 | - > 13 | private foo = MapStorage.for(); + 10 | }; + 11 | + > 12 | private foo = MapStorage.for(); | ^ - 14 | } - 15 | + 13 | } + 14 | " `; exports[`ContractInfoProcessor structured storage protected abstract 1`] = ` -"snippetCode.ts (13,9): Persistent storage classes may only be used as SmartContract private or protected readonly properties with a property initializer. +"snippetCode.ts (12,9): Persistent storage classes may only be used as SmartContract private or protected readonly properties with a property initializer. - 11 | }; - 12 | - > 13 | protected abstract readonly foo: MapStorage; + 10 | }; + 11 | + > 12 | protected abstract readonly foo: MapStorage; | ^ - 14 | } - 15 | + 13 | } + 14 | " `; exports[`ContractInfoProcessor structured storage set in constructor 1`] = ` -"snippetCode.ts (13,9): Persistent storage classes may only be used as SmartContract private or protected readonly properties with a property initializer. +"snippetCode.ts (12,9): Persistent storage classes may only be used as SmartContract private or protected readonly properties with a property initializer. - 11 | }; - 12 | - > 13 | private readonly foo: MapStorage; + 10 | }; + 11 | + > 12 | private readonly foo: MapStorage; | ^ - 14 | public constructor() { - 15 | super(); - 16 | this.foo = MapStorage.for(); + 13 | public constructor() { + 14 | super(); + 15 | this.foo = MapStorage.for(); " `; exports[`ContractInfoProcessor structured storage set public 1`] = ` -"snippetCode.ts (13,9): Persistent storage classes may only be used as SmartContract private or protected readonly properties with a property initializer. +"snippetCode.ts (12,9): Persistent storage classes may only be used as SmartContract private or protected readonly properties with a property initializer. - 11 | }; - 12 | - > 13 | public readonly foo = MapStorage.for(); + 10 | }; + 11 | + > 12 | public readonly foo = MapStorage.for(); | ^ - 14 | } - 15 | + 13 | } + 14 | " `; diff --git a/packages/neo-one-smart-contract-compiler/src/api.ts b/packages/neo-one-smart-contract-compiler/src/api.ts index ec89521f88..0b6ea86e97 100644 --- a/packages/neo-one-smart-contract-compiler/src/api.ts +++ b/packages/neo-one-smart-contract-compiler/src/api.ts @@ -11,14 +11,14 @@ export const getSemanticDiagnostics = ( host: CompilerHost, ): ReadonlyArray => getSemanticDiagnosticsBase({ filePath, languageService, host }); -export const compileContract = ( +export const compileContract = async ( filePath: string, _contractName: string, host: CompilerHost, linked: LinkedContracts = {}, ignoreWarnings = false, -): CompileContractResult => { - const result = compileContractBase({ filePath, host, linked }); +): Promise => { + const result = await compileContractBase({ filePath, host, linked }); throwOnDiagnosticErrorOrWarning(result.diagnostics, ignoreWarnings); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/arguments/index.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/arguments/index.ts deleted file mode 100644 index 3f54adf6c5..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/arguments/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { BuiltinInterface } from '../BuiltinInterface'; -import { Builtins } from '../Builtins'; - -class ArgumentsInstance extends BuiltinInterface {} - -// tslint:disable-next-line export-name -export const add = (builtins: Builtins): void => { - builtins.addInterface('IArguments', new ArgumentsInstance()); -}; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/concat.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/concat.ts index 057d312156..6c46f5ac4b 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/concat.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/concat.ts @@ -75,13 +75,8 @@ export class ArrayConcat extends BuiltinInstanceMemberCall { iterable: handleOther, iterableIterator: handleOther, transaction: handleOther, - output: handleOther, attribute: handleOther, - input: handleOther, - account: handleOther, - asset: handleOther, contract: handleOther, - header: handleOther, block: handleOther, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/entries.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/entries.ts index efb19cb478..348b583788 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/entries.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/entries.ts @@ -34,7 +34,7 @@ export class ArrayEntries extends BuiltinInstanceMemberCall { // [arr] sb.emitHelper(node, options, sb.helpers.unwrapArray); // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [val] sb.emitHelper( node, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/iterator.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/iterator.ts index c5f834c2f9..52ee68270b 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/iterator.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/iterator.ts @@ -34,7 +34,7 @@ export class ArrayIterator extends BuiltinInstanceMemberCall { // [arr] sb.emitHelper(node, options, sb.helpers.unwrapArray); // [iterator] - sb.emitSysCall(node, 'Neo.Enumerator.Create'); + sb.emitSysCall(node, 'System.Enumerator.Create'); // [val] sb.emitHelper(node, options, sb.helpers.createEnumeratorIterableIterator({})); } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/pop.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/pop.ts index ab48a5f282..082ab8b095 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/pop.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/pop.ts @@ -34,7 +34,7 @@ export class ArrayPop extends BuiltinInstanceMemberCall { // [arr, arr] sb.emitOp(node, 'DUP'); // [number, arr] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [0, number, arr] sb.emitPushInt(node, 0); // [boolean, arr] @@ -50,7 +50,7 @@ export class ArrayPop extends BuiltinInstanceMemberCall { // [arr, arr] sb.emitOp(node, 'DUP'); // [size, arr] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [size - 1, arr] sb.emitOp(node, 'DEC'); // [arr, size - 1] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/push.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/push.ts index 2a028fb970..de18032dcf 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/push.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/array/push.ts @@ -37,7 +37,7 @@ export class ArrayPush extends BuiltinInstanceMemberCall { sb.emitOp(node, 'APPEND'); }); // [number] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); if (optionsIn.pushValue) { // [val] sb.emitHelper(node, options, sb.helpers.wrapNumber); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/assertEqual/index.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/assertEqual/index.ts index d395815ded..dab01e88e0 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/assertEqual/index.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/assertEqual/index.ts @@ -64,7 +64,7 @@ export class AssertEqual extends BuiltinCall { // [] sb.emitHelper(node, options, sb.helpers.consoleLog); // [] - sb.emitOp(received, 'THROW'); + sb.emitOp(received, 'ABORT'); }, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/buffer/equals.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/buffer/equals.ts index c63350db3d..2b2cef97ce 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/buffer/equals.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/buffer/equals.ts @@ -1,5 +1,7 @@ +import { StackItemType } from '@neo-one/client-common'; import { tsUtils } from '@neo-one/ts-utils'; import ts from 'typescript'; +import { Types } from '../../constants'; import { isBuffer } from '../../helper/types'; import { ScriptBuilder } from '../../sb'; import { VisitOptions } from '../../types'; @@ -40,6 +42,16 @@ export class BufferEquals extends BuiltinInstanceMemberCall { // [bufferVal, bufferVal] sb.visit(tsUtils.argumented.getArguments(node)[0], options); + // [buffer, bufferVal] + sb.emitHelper(node, options, sb.helpers.unwrapVal({ type: Types.Buffer })); + // [bytestring, bufferVal] + sb.emitOp(node, 'CONVERT', Buffer.from([StackItemType.ByteString])); + // [bufferVal, bytestring] + sb.emitOp(node, 'SWAP'); + // [buffer, bytestring] + sb.emitHelper(node, options, sb.helpers.unwrapVal({ type: Types.Buffer })); + // [bytestring, bytestring] + sb.emitOp(node, 'CONVERT', Buffer.from([StackItemType.ByteString])); // [boolean] sb.emitOp(node, 'EQUAL'); if (optionsIn.pushValue) { diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/BuiltinInstanceIndexValue.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/BuiltinInstanceIndexValue.ts new file mode 100644 index 0000000000..2055026deb --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/BuiltinInstanceIndexValue.ts @@ -0,0 +1,26 @@ +import { WrappableType } from '../../constants'; +import { ScriptBuilder } from '../../sb'; +import { VisitOptions } from '../../types'; +import { BuiltinInstanceMemberValue } from '../BuiltinInstanceMemberValue'; +import { MemberLikeExpression } from '../types'; + +export class BuiltinInstanceIndexValue extends BuiltinInstanceMemberValue { + public constructor( + private readonly index: number, + private readonly valueType: WrappableType, + private readonly type: WrappableType, + ) { + super(); + } + + protected emit(sb: ScriptBuilder, node: MemberLikeExpression, options: VisitOptions): void { + // [blockchainObject] + sb.emitHelper(node, options, sb.helpers.unwrapVal({ type: this.valueType })); + // [index, blockchainObject] + sb.emitPushInt(node, this.index); + // [property] + sb.emitOp(node, 'PICKITEM'); + // [val] + sb.emitHelper(node, options, sb.helpers.wrapVal({ type: this.type })); + } +} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/SmartContractForBase.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/SmartContractForBase.ts index f3e6ed4a70..cc67536389 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/SmartContractForBase.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/SmartContractForBase.ts @@ -123,8 +123,7 @@ export abstract class SmartContractForBase extends BuiltinMemberCall { // [string, params] sb.emitPushString(prop, getSetterName(propName)); - const callBuffer = Buffer.from([0, 2]); - this.emitInvoke(sb, func, node, prop, addressName, callBuffer, sb.noPushValueOptions(innerOptions)); + this.emitInvoke(sb, func, node, prop, addressName, sb.noPushValueOptions(innerOptions)); // [val] sb.emitHelper(prop, innerOptions, sb.helpers.wrapUndefined); // [] @@ -162,8 +161,7 @@ export abstract class SmartContractForBase extends BuiltinMemberCall { sb.emitPushString(prop, propName); const isVoidReturn = propReturnType !== undefined && tsUtils.type_.isVoid(propReturnType); - const callBuffer = Buffer.from([isVoidReturn ? 0 : 1, 2]); - this.emitInvoke(sb, func, node, prop, addressName, callBuffer, innerOptions); + this.emitInvoke(sb, func, node, prop, addressName, innerOptions); if (isVoidReturn) { sb.emitHelper(prop, innerOptions, sb.helpers.wrapUndefined); @@ -237,7 +235,6 @@ export abstract class SmartContractForBase extends BuiltinMemberCall { node: ts.CallExpression, prop: ts.Declaration, addressName: Name, - callBuffer: Buffer, optionsIn: VisitOptions, ): void; } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/SysCallInstanceMemberIndex.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/SysCallInstanceMemberIndex.ts new file mode 100644 index 0000000000..217f40e1ea --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/SysCallInstanceMemberIndex.ts @@ -0,0 +1,30 @@ +import { SysCallName } from '@neo-one/client-common'; +import { WrappableType } from '../../constants'; +import { ScriptBuilder } from '../../sb'; +import { VisitOptions } from '../../types'; +import { BuiltinInstanceMemberValue } from '../BuiltinInstanceMemberValue'; +import { MemberLikeExpression } from '../types'; + +export class SysCallInstanceMemberIndex extends BuiltinInstanceMemberValue { + public constructor( + private readonly syscall: SysCallName, + private readonly index: number, + private readonly valueType: WrappableType, + private readonly type: WrappableType, + ) { + super(); + } + + protected emit(sb: ScriptBuilder, node: MemberLikeExpression, options: VisitOptions): void { + // [blockchainObject] + sb.emitHelper(node, options, sb.helpers.unwrapVal({ type: this.valueType })); + // [index, blockchainObject] + sb.emitPushInt(node, this.index); + // [property] + sb.emitOp(node, 'PICKITEM'); + // [arr] + sb.emitSysCall(node, this.syscall); + // [arrayVal] + sb.emitHelper(node, options, sb.helpers.wrapVal({ type: this.type })); + } +} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/account/getBalance.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/account/getBalance.ts deleted file mode 100644 index 4571e91003..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/account/getBalance.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { tsUtils } from '@neo-one/ts-utils'; -import ts from 'typescript'; -import { ScriptBuilder } from '../../../sb'; -import { VisitOptions } from '../../../types'; -import { BuiltinInstanceMemberCall } from '../../BuiltinInstanceMemberCall'; -import { CallMemberLikeExpression } from '../../types'; - -// tslint:disable-next-line export-name -export class AccountGetBalance extends BuiltinInstanceMemberCall { - public canCall(_sb: ScriptBuilder, _func: CallMemberLikeExpression, node: ts.CallExpression): boolean { - return tsUtils.argumented.getArguments(node).length === 1; - } - - public emitCall( - sb: ScriptBuilder, - func: CallMemberLikeExpression, - node: ts.CallExpression, - optionsIn: VisitOptions, - visited: boolean, - ): void { - const options = sb.pushValueOptions(optionsIn); - if (!visited) { - // [arrayVal] - sb.visit(tsUtils.expression.getExpression(func), options); - } - - if (tsUtils.argumented.getArguments(node).length < 1) { - /* istanbul ignore next */ - return; - } - - // [account] - sb.emitHelper(node, options, sb.helpers.unwrapBuffer); - // [bufferVal, account] - sb.visit(tsUtils.argumented.getArguments(node)[0], options); - // [buffer, account] - sb.emitHelper(tsUtils.argumented.getArguments(node)[0], options, sb.helpers.unwrapBuffer); - // [account, buffer] - sb.emitOp(node, 'SWAP'); - // [number] - sb.emitSysCall(node, 'Neo.Account.GetBalance'); - if (optionsIn.pushValue) { - // [booleanVal] - sb.emitHelper(node, options, sb.helpers.wrapNumber); - } else { - // [] - sb.emitOp(node, 'DROP'); - } - } -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/account/index.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/account/index.ts deleted file mode 100644 index e369b08fe3..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/account/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Types } from '../../../constants'; -import { BuiltinInterface } from '../../BuiltinInterface'; -import { Builtins } from '../../Builtins'; -import { SysCallInstanceMemberPrimitive } from '../SysCallInstanceMemberPrimitive'; -import { ValueFor } from '../ValueFor'; -import { ValueInstanceOf } from '../ValueInstanceOf'; -import { AccountGetBalance } from './getBalance'; - -class AccountInterface extends BuiltinInterface {} -class AccountConstructorInterface extends BuiltinInterface {} - -// tslint:disable-next-line export-name -export const add = (builtins: Builtins): void => { - builtins.addContractInterface('Account', new AccountInterface()); - builtins.addContractValue('Account', new ValueInstanceOf('AccountConstructor', (sb) => sb.helpers.isAccount)); - builtins.addContractMember( - 'Account', - 'address', - new SysCallInstanceMemberPrimitive('Neo.Account.GetScriptHash', Types.Account, Types.Buffer), - ); - builtins.addContractMember('Account', 'getBalance', new AccountGetBalance()); - builtins.addContractInterface('AccountConstructor', new AccountConstructorInterface()); - builtins.addContractMember( - 'AccountConstructor', - 'for', - new ValueFor('Neo.Blockchain.GetAccount', (sb, node, options) => { - sb.emitHelper(node, options, sb.helpers.wrapAccount); - }), - ); -}; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/address/index.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/address/index.ts index 809eff4c55..beb4d2faa3 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/address/index.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/address/index.ts @@ -1,3 +1,5 @@ +import { common } from '@neo-one/client-common'; +import { BuiltinConstantBufferMemberValue } from '../../BuiltinConstantBufferMemberValue'; import { BuiltinInterface } from '../../BuiltinInterface'; import { Builtins } from '../../Builtins'; import { BuiltinValueObject } from '../../BuiltinValueObject'; @@ -19,4 +21,19 @@ export const add = (builtins: Builtins): void => { builtins.addContractMember('AddressConstructor', 'from', new AddressFrom()); builtins.addContractMember('AddressConstructor', 'isSender', new AddressIsSender()); builtins.addContractMember('AddressConstructor', 'isCaller', new AddressIsCaller()); + builtins.addContractMember( + 'AddressConstructor', + 'NEO', + new BuiltinConstantBufferMemberValue(common.nativeHashes.NEO), + ); + builtins.addContractMember( + 'AddressConstructor', + 'GAS', + new BuiltinConstantBufferMemberValue(common.nativeHashes.GAS), + ); + builtins.addContractMember( + 'AddressConstructor', + 'Policy', + new BuiltinConstantBufferMemberValue(common.nativeHashes.Policy), + ); }; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/address/isSender.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/address/isSender.ts index 320a7691da..21d9ec2c82 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/address/isSender.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/address/isSender.ts @@ -27,7 +27,7 @@ export class AddressIsSender extends BuiltinMemberCall { // [buffer, buffer] sb.emitOp(node, 'DUP'); // [boolean, buffer] - sb.emitSysCall(node, 'Neo.Runtime.CheckWitness'); + sb.emitSysCall(node, 'System.Runtime.CheckWitness'); // [buffer, boolean] sb.emitOp(node, 'SWAP'); // [buffer, buffer, boolean] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/arrayStorage/pop.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/arrayStorage/pop.ts index a233a51829..a3338e5e36 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/arrayStorage/pop.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/arrayStorage/pop.ts @@ -98,10 +98,16 @@ export class ArrayStoragePop extends BuiltinInstanceMemberCall { knownKeyType: Types.Number, }), ); - // [5, deletedVal, idxVal, val, idx, val] + // [deletedVal, deletedVal, idxVal, val, idx, val] + sb.emitOp(node, 'DUP'); + // [6, deletedVal, deletedVal, idxVal, val, idx, val] + sb.emitPushInt(node, 6); + // [val, idx, val, idxVal, deletedVal, deleteVal] + sb.emitOp(node, 'REVERSEN'); + // [5, val, idx, val, idxVal, deletedVal, deleteVal] sb.emitPushInt(node, 5); // [deletedVal, idxVal, val, idx, val, deletedVal] - sb.emitOp(node, 'XTUCK'); + sb.emitOp(node, 'REVERSEN'); // [idxVal, val, idx, val, deletedVal] sb.emitOp(node, 'DROP'); } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/asset.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/asset.ts deleted file mode 100644 index 5ecebe9264..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/asset.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Types } from '../../constants'; -import { BuiltinInterface } from '../BuiltinInterface'; -import { Builtins } from '../Builtins'; -import { SysCallInstanceMemberPrimitive } from './SysCallInstanceMemberPrimitive'; -import { ValueFor } from './ValueFor'; -import { ValueInstanceOf } from './ValueInstanceOf'; - -class AssetInterface extends BuiltinInterface {} -class AssetConstructorInterface extends BuiltinInterface {} - -// tslint:disable-next-line export-name -export const add = (builtins: Builtins): void => { - builtins.addContractInterface('Asset', new AssetInterface()); - builtins.addContractValue('Asset', new ValueInstanceOf('AssetConstructor', (sb) => sb.helpers.isAsset)); - builtins.addContractMember( - 'Asset', - 'hash', - new SysCallInstanceMemberPrimitive('Neo.Asset.GetAssetId', Types.Asset, Types.Buffer), - ); - builtins.addContractMember( - 'Asset', - 'type', - new SysCallInstanceMemberPrimitive('Neo.Asset.GetAssetType', Types.Asset, Types.Number), - ); - builtins.addContractMember( - 'Asset', - 'amount', - new SysCallInstanceMemberPrimitive('Neo.Asset.GetAmount', Types.Asset, Types.Number), - ); - builtins.addContractMember( - 'Asset', - 'available', - new SysCallInstanceMemberPrimitive('Neo.Asset.GetAvailable', Types.Asset, Types.Number), - ); - builtins.addContractMember( - 'Asset', - 'precision', - new SysCallInstanceMemberPrimitive('Neo.Asset.GetPrecision', Types.Asset, Types.Number), - ); - builtins.addContractMember( - 'Asset', - 'owner', - new SysCallInstanceMemberPrimitive('Neo.Asset.GetOwner', Types.Asset, Types.Buffer), - ); - builtins.addContractMember( - 'Asset', - 'admin', - new SysCallInstanceMemberPrimitive('Neo.Asset.GetAdmin', Types.Asset, Types.Buffer), - ); - builtins.addContractMember( - 'Asset', - 'issuer', - new SysCallInstanceMemberPrimitive('Neo.Asset.GetIssuer', Types.Asset, Types.Buffer), - ); - - builtins.addContractInterface('AssetConstructor', new AssetConstructorInterface()); - builtins.addContractMember( - 'AssetConstructor', - 'for', - new ValueFor('Neo.Blockchain.GetAsset', (sb, node, options) => { - sb.emitHelper(node, options, sb.helpers.wrapAsset); - }), - ); -}; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/assetType.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/assetType.ts deleted file mode 100644 index 7354c643dd..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/assetType.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { AssetTypeModel as AssetType } from '@neo-one/client-common'; -import { BuiltinBase } from '../BuiltinBase'; -import { BuiltinConstantNumberMemberValue } from '../BuiltinConstantNumberMemberValue'; -import { Builtins } from '../Builtins'; - -class AssetTypeValue extends BuiltinBase {} - -// tslint:disable-next-line export-name -export const add = (builtins: Builtins): void => { - builtins.addContractValue('AssetType', new AssetTypeValue()); - builtins.addContractMember('AssetType', 'Credit', new BuiltinConstantNumberMemberValue(AssetType.CreditFlag)); - builtins.addContractMember('AssetType', 'Duty', new BuiltinConstantNumberMemberValue(AssetType.DutyFlag)); - builtins.addContractMember('AssetType', 'Governing', new BuiltinConstantNumberMemberValue(AssetType.GoverningToken)); - builtins.addContractMember('AssetType', 'Utility', new BuiltinConstantNumberMemberValue(AssetType.UtilityToken)); - builtins.addContractMember('AssetType', 'Currency', new BuiltinConstantNumberMemberValue(AssetType.Currency)); - builtins.addContractMember('AssetType', 'Share', new BuiltinConstantNumberMemberValue(AssetType.Share)); - builtins.addContractMember('AssetType', 'Invoice', new BuiltinConstantNumberMemberValue(AssetType.Invoice)); - builtins.addContractMember('AssetType', 'Token', new BuiltinConstantNumberMemberValue(AssetType.Token)); -}; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/attribute.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/attribute.ts index 3d287d0bdf..f23f1e1ebe 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/attribute.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/attribute.ts @@ -11,26 +11,6 @@ class PublicKeyAttributeInterface extends BuiltinInterface {} class AddressAttributeInterface extends BuiltinInterface {} class Hash256AttributeInterface extends BuiltinInterface {} +// TODO: revisit if NEO implements a usage for these again // tslint:disable-next-line export-name -export const add = (builtins: Builtins): void => { - builtins.addContractInterface('AttributeBase', new AttributeBaseInterface()); - builtins.addContractInterface('AttributeBaseConstructor', new AttributeBaseConstructorInterface()); - builtins.addContractValue( - 'AttributeBase', - new ValueInstanceOf('AttributeConstructor', (sb) => sb.helpers.isAttribute), - ); - builtins.addContractMember( - 'AttributeBase', - 'usage', - new SysCallInstanceMemberPrimitive('Neo.Attribute.GetUsage', Types.Attribute, Types.Number), - ); - builtins.addContractMember( - 'AttributeBase', - 'data', - new SysCallInstanceMemberPrimitive('Neo.Attribute.GetData', Types.Attribute, Types.Buffer), - ); - builtins.addContractInterface('BufferAttribute', new BufferAttributeInterface()); - builtins.addContractInterface('PublicKeyAttribute', new PublicKeyAttributeInterface()); - builtins.addContractInterface('AddressAttribute', new AddressAttributeInterface()); - builtins.addContractInterface('Hash256Attribute', new Hash256AttributeInterface()); -}; +export const add = (builtins: Builtins): void => {}; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/attributeUsage.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/attributeUsage.ts index b15ea723a2..445abbb7ea 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/attributeUsage.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/attributeUsage.ts @@ -1,4 +1,4 @@ -import { AttributeUsageModel as AttributeUsage } from '@neo-one/client-common'; +import { AttributeTypeModel as AttributeUsage } from '@neo-one/client-common'; import { BuiltinBase } from '../BuiltinBase'; import { BuiltinConstantNumberMemberValue } from '../BuiltinConstantNumberMemberValue'; import { Builtins } from '../Builtins'; @@ -10,76 +10,7 @@ export const add = (builtins: Builtins): void => { builtins.addContractValue('AttributeUsage', new AttributeUsageValue()); builtins.addContractMember( 'AttributeUsage', - 'ContractHash', - new BuiltinConstantNumberMemberValue(AttributeUsage.ContractHash), - ); - builtins.addContractMember('AttributeUsage', 'ECDH02', new BuiltinConstantNumberMemberValue(AttributeUsage.ECDH02)); - builtins.addContractMember('AttributeUsage', 'ECDH03', new BuiltinConstantNumberMemberValue(AttributeUsage.ECDH03)); - builtins.addContractMember('AttributeUsage', 'Script', new BuiltinConstantNumberMemberValue(AttributeUsage.Script)); - builtins.addContractMember('AttributeUsage', 'Vote', new BuiltinConstantNumberMemberValue(AttributeUsage.Vote)); - builtins.addContractMember( - 'AttributeUsage', - 'DescriptionUrl', - new BuiltinConstantNumberMemberValue(AttributeUsage.DescriptionUrl), - ); - builtins.addContractMember( - 'AttributeUsage', - 'Description', - new BuiltinConstantNumberMemberValue(AttributeUsage.Description), - ); - builtins.addContractMember('AttributeUsage', 'Hash1', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash1)); - builtins.addContractMember('AttributeUsage', 'Hash2', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash2)); - builtins.addContractMember('AttributeUsage', 'Hash3', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash3)); - builtins.addContractMember('AttributeUsage', 'Hash4', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash4)); - builtins.addContractMember('AttributeUsage', 'Hash5', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash5)); - builtins.addContractMember('AttributeUsage', 'Hash6', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash6)); - builtins.addContractMember('AttributeUsage', 'Hash7', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash7)); - builtins.addContractMember('AttributeUsage', 'Hash8', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash8)); - builtins.addContractMember('AttributeUsage', 'Hash9', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash9)); - builtins.addContractMember('AttributeUsage', 'Hash10', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash10)); - builtins.addContractMember('AttributeUsage', 'Hash11', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash11)); - builtins.addContractMember('AttributeUsage', 'Hash12', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash12)); - builtins.addContractMember('AttributeUsage', 'Hash13', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash13)); - builtins.addContractMember('AttributeUsage', 'Hash14', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash14)); - builtins.addContractMember('AttributeUsage', 'Hash15', new BuiltinConstantNumberMemberValue(AttributeUsage.Hash15)); - builtins.addContractMember('AttributeUsage', 'Remark', new BuiltinConstantNumberMemberValue(AttributeUsage.Remark)); - builtins.addContractMember('AttributeUsage', 'Remark1', new BuiltinConstantNumberMemberValue(AttributeUsage.Remark1)); - builtins.addContractMember('AttributeUsage', 'Remark2', new BuiltinConstantNumberMemberValue(AttributeUsage.Remark2)); - builtins.addContractMember('AttributeUsage', 'Remark3', new BuiltinConstantNumberMemberValue(AttributeUsage.Remark3)); - builtins.addContractMember('AttributeUsage', 'Remark4', new BuiltinConstantNumberMemberValue(AttributeUsage.Remark4)); - builtins.addContractMember('AttributeUsage', 'Remark5', new BuiltinConstantNumberMemberValue(AttributeUsage.Remark5)); - builtins.addContractMember('AttributeUsage', 'Remark6', new BuiltinConstantNumberMemberValue(AttributeUsage.Remark6)); - builtins.addContractMember('AttributeUsage', 'Remark7', new BuiltinConstantNumberMemberValue(AttributeUsage.Remark7)); - builtins.addContractMember('AttributeUsage', 'Remark8', new BuiltinConstantNumberMemberValue(AttributeUsage.Remark8)); - builtins.addContractMember('AttributeUsage', 'Remark9', new BuiltinConstantNumberMemberValue(AttributeUsage.Remark9)); - builtins.addContractMember( - 'AttributeUsage', - 'Remark10', - new BuiltinConstantNumberMemberValue(AttributeUsage.Remark10), - ); - builtins.addContractMember( - 'AttributeUsage', - 'Remark11', - new BuiltinConstantNumberMemberValue(AttributeUsage.Remark11), - ); - builtins.addContractMember( - 'AttributeUsage', - 'Remark12', - new BuiltinConstantNumberMemberValue(AttributeUsage.Remark12), - ); - builtins.addContractMember( - 'AttributeUsage', - 'Remark13', - new BuiltinConstantNumberMemberValue(AttributeUsage.Remark13), - ); - builtins.addContractMember( - 'AttributeUsage', - 'Remark14', - new BuiltinConstantNumberMemberValue(AttributeUsage.Remark14), - ); - builtins.addContractMember( - 'AttributeUsage', - 'Remark15', - new BuiltinConstantNumberMemberValue(AttributeUsage.Remark15), + 'HighPriority', + new BuiltinConstantNumberMemberValue(AttributeUsage.HighPriority), ); }; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/block.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/block.ts index df6948d80e..1b8bb21757 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/block.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/block.ts @@ -1,7 +1,7 @@ import { Types } from '../../constants'; import { BuiltinInterface } from '../BuiltinInterface'; import { Builtins } from '../Builtins'; -import { SysCallInstanceMemberArray } from './SysCallInstanceMemberArray'; +import { BuiltinInstanceIndexValue } from './BuiltinInstanceIndexValue'; import { ValueFor } from './ValueFor'; import { ValueInstanceOf } from './ValueInstanceOf'; @@ -12,17 +12,24 @@ class BlockConstructorInterface extends BuiltinInterface {} export const add = (builtins: Builtins): void => { builtins.addContractInterface('Block', new BlockInterface()); builtins.addContractValue('Block', new ValueInstanceOf('BlockConstructor', (sb) => sb.helpers.isBlock)); + builtins.addContractMember('Block', 'hash', new BuiltinInstanceIndexValue(0, Types.Block, Types.Buffer)); + builtins.addContractMember('Block', 'version', new BuiltinInstanceIndexValue(1, Types.Block, Types.Number)); + builtins.addContractMember('Block', 'previousHash', new BuiltinInstanceIndexValue(2, Types.Block, Types.Buffer)); + builtins.addContractMember('Block', 'merkleRoot', new BuiltinInstanceIndexValue(3, Types.Block, Types.Buffer)); + builtins.addContractMember('Block', 'time', new BuiltinInstanceIndexValue(4, Types.Block, Types.Number)); + builtins.addContractMember('Block', 'index', new BuiltinInstanceIndexValue(5, Types.Block, Types.Number)); + builtins.addContractMember('Block', 'nextConsensus', new BuiltinInstanceIndexValue(6, Types.Block, Types.Buffer)); builtins.addContractMember( 'Block', - 'transactions', - new SysCallInstanceMemberArray('Neo.Block.GetTransactions', Types.Block, Types.Transaction), + 'transactionsLength', + new BuiltinInstanceIndexValue(7, Types.Block, Types.Number), ); builtins.addContractInterface('BlockConstructor', new BlockConstructorInterface()); builtins.addContractMember( 'BlockConstructor', 'for', - new ValueFor('Neo.Blockchain.GetBlock', (sb, node, options) => { + new ValueFor('System.Blockchain.GetBlock', (sb, node, options) => { sb.emitHelper(node, options, sb.helpers.wrapBlock); }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/blockchain.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/blockchain.ts index 8c8ad95cc5..eddb6cf36f 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/blockchain.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/blockchain.ts @@ -21,7 +21,7 @@ class BlockchainCurrentCallerContract extends BuiltinMemberValue { // [buffer, buffer] sb.emitOp(node, 'DUP'); // [contract, buffer] - sb.emitSysCall(node, 'Neo.Blockchain.GetContract'); + sb.emitSysCall(node, 'System.Blockchain.GetContract'); sb.emitHelper( node, options, @@ -55,17 +55,17 @@ export const add = (builtins: Builtins): void => { builtins.addContractMember( 'BlockchainConstructor', 'currentBlockTime', - new SysCallMemberValue('Neo.Runtime.GetTime', Types.Number), + new SysCallMemberValue('System.Runtime.GetTime', Types.Number), ); builtins.addContractMember( 'BlockchainConstructor', 'currentHeight', - new SysCallMemberValue('Neo.Blockchain.GetHeight', Types.Number), + new SysCallMemberValue('System.Blockchain.GetHeight', Types.Number), ); builtins.addContractMember( 'BlockchainConstructor', 'currentTransaction', - new SysCallMemberValue('System.ExecutionEngine.GetScriptContainer', Types.Transaction), + new SysCallMemberValue('System.Runtime.GetScriptContainer', Types.Transaction), ); builtins.addContractMember('BlockchainConstructor', 'currentCallerContract', new BlockchainCurrentCallerContract()); }; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/contract.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/contract.ts index 251ce6236e..3446bf2127 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/contract.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/contract.ts @@ -1,7 +1,7 @@ import { Types } from '../../constants'; import { BuiltinInterface } from '../BuiltinInterface'; import { Builtins } from '../Builtins'; -import { SysCallInstanceMemberPrimitive } from './SysCallInstanceMemberPrimitive'; +import { BuiltinInstanceIndexValue } from './BuiltinInstanceIndexValue'; import { ValueFor } from './ValueFor'; import { ValueInstanceOf } from './ValueInstanceOf'; @@ -12,22 +12,15 @@ class ContractConstructorInterface extends BuiltinInterface {} export const add = (builtins: Builtins): void => { builtins.addContractInterface('Contract', new ContractInterface()); builtins.addContractValue('Contract', new ValueInstanceOf('ContractConstructor', (sb) => sb.helpers.isContract)); - builtins.addContractMember( - 'Contract', - 'script', - new SysCallInstanceMemberPrimitive('Neo.Contract.GetScript', Types.Contract, Types.Buffer), - ); - builtins.addContractMember( - 'Contract', - 'payable', - new SysCallInstanceMemberPrimitive('Neo.Contract.IsPayable', Types.Contract, Types.Boolean), - ); - + builtins.addContractMember('Contract', 'script', new BuiltinInstanceIndexValue(0, Types.Contract, Types.Buffer)); + builtins.addContractMember('Contract', 'manifest', new BuiltinInstanceIndexValue(1, Types.Contract, Types.String)); + builtins.addContractMember('Contract', 'hasStorage', new BuiltinInstanceIndexValue(2, Types.Contract, Types.Boolean)); + builtins.addContractMember('Contract', 'payable', new BuiltinInstanceIndexValue(3, Types.Contract, Types.Boolean)); builtins.addContractInterface('ContractConstructor', new ContractConstructorInterface()); builtins.addContractMember( 'ContractConstructor', 'for', - new ValueFor('Neo.Blockchain.GetContract', (sb, node, options) => { + new ValueFor('System.Blockchain.GetContract', (sb, node, options) => { sb.emitHelper( node, options, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/createEventNotifier.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/createEventNotifier.ts index b7e95f7442..430f1815cd 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/createEventNotifier.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/createEventNotifier.ts @@ -67,8 +67,10 @@ class CreateEventNotifier extends BuiltinCall { sb.emitOp(node, 'INC'); // [arr] sb.emitOp(node, 'PACK'); + // [eventName, arr] + sb.emitPushString(node, eventName); // [] - sb.emitSysCall(node, 'Neo.Runtime.Notify'); + sb.emitSysCall(node, 'System.Runtime.Notify'); // [val] sb.emitHelper(node, innerOptions, sb.helpers.wrapUndefined); // [] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/crypto.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/crypto.ts index 215e4d8dfa..e4460b2b28 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/crypto.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/crypto.ts @@ -14,8 +14,10 @@ class CryptoValue extends BuiltinValueObject { public readonly type = 'CryptoConstructor'; } -class HashOp extends BuiltinMemberCall { - public constructor(private readonly op: 'SHA1' | 'SHA256' | 'HASH160' | 'HASH256') { +type hashSysCall = 'Neo.Crypto.RIPEMD160' | 'Neo.Crypto.SHA256'; + +class HashSysCall extends BuiltinMemberCall { + public constructor(private readonly firstHash: hashSysCall, private readonly secondHash?: hashSysCall) { super(); } public emitCall( @@ -69,18 +71,16 @@ class HashOp extends BuiltinMemberCall { iterable: throwTypeError, iterableIterator: throwTypeError, transaction: throwTypeError, - output: throwTypeError, attribute: throwTypeError, - input: throwTypeError, - account: throwTypeError, - asset: throwTypeError, contract: throwTypeError, - header: throwTypeError, block: throwTypeError, }), ); // [buffer] - sb.emitOp(node, this.op); + sb.emitSysCall(node, this.firstHash); + if (this.secondHash !== undefined) { + sb.emitSysCall(node, this.secondHash); + } // [val] sb.emitHelper(node, optionsIn, sb.helpers.wrapBuffer); } @@ -89,9 +89,13 @@ class HashOp extends BuiltinMemberCall { // tslint:disable-next-line export-name export const add = (builtins: Builtins): void => { builtins.addContractInterface('CryptoConstructor', new CryptoInterface()); - builtins.addContractMember('CryptoConstructor', 'sha1', new HashOp('SHA1')); - builtins.addContractMember('CryptoConstructor', 'sha256', new HashOp('SHA256')); - builtins.addContractMember('CryptoConstructor', 'hash160', new HashOp('HASH160')); - builtins.addContractMember('CryptoConstructor', 'hash256', new HashOp('HASH256')); + builtins.addContractMember('CryptoConstructor', 'ripemd160', new HashSysCall('Neo.Crypto.RIPEMD160')); + builtins.addContractMember('CryptoConstructor', 'sha256', new HashSysCall('Neo.Crypto.SHA256')); + builtins.addContractMember( + 'CryptoConstructor', + 'hash160', + new HashSysCall('Neo.Crypto.SHA256', 'Neo.Crypto.RIPEMD160'), + ); + builtins.addContractMember('CryptoConstructor', 'hash256', new HashSysCall('Neo.Crypto.SHA256', 'Neo.Crypto.SHA256')); builtins.addContractValue('crypto', new CryptoValue()); }; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/hash256/index.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/hash256/index.ts index 41b8edb544..42be727c30 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/hash256/index.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/hash256/index.ts @@ -1,5 +1,3 @@ -import { common } from '@neo-one/client-common'; -import { BuiltinConstantBufferMemberValue } from '../../BuiltinConstantBufferMemberValue'; import { BuiltinInterface } from '../../BuiltinInterface'; import { Builtins } from '../../Builtins'; import { BuiltinValueObject } from '../../BuiltinValueObject'; @@ -17,14 +15,4 @@ export const add = (builtins: Builtins): void => { builtins.addContractValue('Hash256', new Hash256Value()); builtins.addContractInterface('Hash256Constructor', new Hash256ConstructorInterface()); builtins.addContractMember('Hash256Constructor', 'from', new Hash256From()); - builtins.addContractMember( - 'Hash256Constructor', - 'NEO', - new BuiltinConstantBufferMemberValue(common.stringToUInt256(common.NEO_ASSET_HASH)), - ); - builtins.addContractMember( - 'Hash256Constructor', - 'GAS', - new BuiltinConstantBufferMemberValue(common.stringToUInt256(common.GAS_ASSET_HASH)), - ); }; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/header.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/header.ts deleted file mode 100644 index 2fb6e1e128..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/header.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Types } from '../../constants'; -import { BuiltinInterface } from '../BuiltinInterface'; -import { Builtins } from '../Builtins'; -import { SysCallInstanceMemberPrimitive } from './SysCallInstanceMemberPrimitive'; -import { ValueFor } from './ValueFor'; -import { ValueInstanceOf } from './ValueInstanceOf'; - -class HeaderInterface extends BuiltinInterface {} -class HeaderConstructorInterface extends BuiltinInterface {} - -// tslint:disable-next-line export-name -export const add = (builtins: Builtins): void => { - builtins.addContractInterface('Header', new HeaderInterface()); - builtins.addContractValue('Header', new ValueInstanceOf('HeaderConstructor', (sb) => sb.helpers.isHeader)); - builtins.addContractMember( - 'Header', - 'hash', - new SysCallInstanceMemberPrimitive('Neo.Header.GetHash', Types.Header, Types.Buffer), - ); - builtins.addContractMember( - 'Header', - 'version', - new SysCallInstanceMemberPrimitive('Neo.Header.GetVersion', Types.Header, Types.Number), - ); - builtins.addContractMember( - 'Header', - 'previousHash', - new SysCallInstanceMemberPrimitive('Neo.Header.GetPrevHash', Types.Header, Types.Buffer), - ); - builtins.addContractMember( - 'Header', - 'index', - new SysCallInstanceMemberPrimitive('Neo.Header.GetIndex', Types.Header, Types.Number), - ); - builtins.addContractMember( - 'Header', - 'merkleRoot', - new SysCallInstanceMemberPrimitive('Neo.Header.GetMerkleRoot', Types.Header, Types.Buffer), - ); - builtins.addContractMember( - 'Header', - 'time', - new SysCallInstanceMemberPrimitive('Neo.Header.GetTimestamp', Types.Header, Types.Number), - ); - builtins.addContractMember( - 'Header', - 'nextConsensus', - new SysCallInstanceMemberPrimitive('Neo.Header.GetNextConsensus', Types.Header, Types.Buffer), - ); - - builtins.addContractInterface('HeaderConstructor', new HeaderConstructorInterface()); - builtins.addContractMember( - 'HeaderConstructor', - 'for', - new ValueFor('Neo.Blockchain.GetHeader', (sb, node, options) => { - sb.emitHelper(node, options, sb.helpers.wrapHeader); - }), - ); -}; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/index.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/index.ts index cfb8ddc8a1..ba20a93dfe 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/index.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/index.ts @@ -1,9 +1,6 @@ import { Builtins } from '../Builtins'; -import { add as addAccount } from './account'; import { add as addAddress } from './address'; import { add as addArrayStorage } from './arrayStorage'; -import { add as addAsset } from './asset'; -import { add as addAssetType } from './assetType'; import { add as addAttribute } from './attribute'; import { add as addAttributeUsage } from './attributeUsage'; import { add as addBlock } from './block'; @@ -15,26 +12,17 @@ import { add as addDeclareEvent } from './declareEvent'; import { add as addDeploy } from './deploy'; import { add as addForwardValue } from './forwardValue'; import { add as addHash256 } from './hash256'; -import { add as addHeader } from './header'; -import { add as addInput } from './input'; import { add as addLinkedSmartContract } from './linkedSmartContract'; import { add as addMapStorage } from './mapStorage'; -import { add as addOutput } from './output'; import { add as addPublicKey } from './publicKey'; import { add as addSetStorage } from './setStorage'; import { add as addSmartContract } from './smartContract'; import { add as addTransaction } from './transaction'; -import { add as addTransactionType } from './transactionType'; // tslint:disable-next-line export-name export const add = (builtins: Builtins): void => { - addAccount(builtins); addAddress(builtins); addArrayStorage(builtins); - addAsset(builtins); - addAssetType(builtins); - addAttribute(builtins); - addAttributeUsage(builtins); addBlock(builtins); addBlockchain(builtins); addContract(builtins); @@ -44,14 +32,14 @@ export const add = (builtins: Builtins): void => { addDeploy(builtins); addForwardValue(builtins); addHash256(builtins); - addHeader(builtins); - addInput(builtins); addLinkedSmartContract(builtins); addMapStorage(builtins); - addOutput(builtins); addPublicKey(builtins); addSetStorage(builtins); addSmartContract(builtins); addTransaction(builtins); - addTransactionType(builtins); + + // void calls saved for later implementations + addAttribute(builtins); + addAttributeUsage(builtins); }; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/input.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/input.ts deleted file mode 100644 index 4c365e7bb7..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/input.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Types } from '../../constants'; -import { BuiltinInterface } from '../BuiltinInterface'; -import { Builtins } from '../Builtins'; -import { SysCallInstanceMemberPrimitive } from './SysCallInstanceMemberPrimitive'; -import { ValueInstanceOf } from './ValueInstanceOf'; - -class InputInterface extends BuiltinInterface {} -class InputConstructorInterface extends BuiltinInterface {} - -// tslint:disable-next-line export-name -export const add = (builtins: Builtins): void => { - builtins.addContractInterface('Input', new InputInterface()); - builtins.addContractValue('Input', new ValueInstanceOf('InputConstructor', (sb) => sb.helpers.isInput)); - builtins.addContractInterface('InputConstructor', new InputConstructorInterface()); - builtins.addContractMember( - 'Input', - 'hash', - new SysCallInstanceMemberPrimitive('Neo.Input.GetHash', Types.Input, Types.Buffer), - ); - builtins.addContractMember( - 'Input', - 'index', - new SysCallInstanceMemberPrimitive('Neo.Input.GetIndex', Types.Input, Types.Number), - ); -}; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/linkedSmartContract/for.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/linkedSmartContract/for.ts index f2f8a4ccba..8f129e2eb8 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/linkedSmartContract/for.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/linkedSmartContract/for.ts @@ -38,13 +38,23 @@ export class LinkedSmartContractFor extends SmartContractForBase { node: ts.CallExpression, prop: ts.Declaration, _addressName: Name, - callBuffer: Buffer, _options: VisitOptions, ): void { const scriptHash = this.getScriptHash(sb, node); if (scriptHash !== undefined) { + // TODO: remove this and change how we call smart contracts, including our own + // [string, params, string] + sb.emitOp(node, 'TUCK'); + // [2, string, params, string] + sb.emitPushInt(node, 2); + // [[string, params], string] + sb.emitOp(node, 'PACK'); + // [string, [string, params]] + sb.emitOp(node, 'SWAP'); + // [buffer, string, params] + sb.emitPushBuffer(prop, scriptHash); // [result] - sb.emitOp(prop, 'CALL_E', Buffer.concat([callBuffer, scriptHash])); + sb.emitSysCall(prop, 'System.Contract.Call'); } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/notification.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/notification.ts new file mode 100644 index 0000000000..17dd480ac9 --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/notification.ts @@ -0,0 +1,41 @@ +import { Types } from '../../constants'; +import { BuiltinInterface } from '../BuiltinInterface'; +import { Builtins } from '../Builtins'; +import { BuiltinInstanceIndexValue } from './BuiltinInstanceIndexValue'; +import { ValueInstanceOf } from './ValueInstanceOf'; + +// class NotificationInterface extends BuiltinInterface {} +// class NotificationConstructorInterface extends BuiltinInterface {} + +// tslint:disable-next-line export-name +// export const add = (builtins: Builtins): void => { +// builtins.addContractInterface('Notification', new NotificationInterface()); +// builtins.addContractValue( +// 'Notification', +// new ValueInstanceOf('NotificationConstructor', (sb) => sb.helpers.isNotification), +// ); +// builtins.addContractInterface('NotificationConstructor', new NotificationConstructorInterface()); +// builtins.addContractMember( +// 'Notification', +// 'scriptHash', +// new BuiltinInstanceIndexValue(0, Types.Notification, Types.Buffer), +// ); +// builtins.addContractMember( +// 'Notification', +// 'eventName', +// new BuiltinInstanceIndexValue(1, Types.Notification, Types.String), +// ); +// TODO: need to create another builtin here to handle the stackitems? +// Look for other instances in old code where there was a nested array +// Look for other instances where the output was a generic stackitem? +// What if we only did this for transfer notifications? Then we could assume what the +// array is made up of without guessing types. We can do ISNULL to handle possible nulls +// could also do SIZE to get array size +// Use ISTYPE opcode +// builtins.addContractMember( +// 'Notification', +// 'state', +// // TODO: Need to see how SysCallInstanceMemberArray handles the array part and integrate into index value one +// new BuiltinInstanceIndexValue(2, Types.Notification, Types.StackItem), +// ); +// }; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/output.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/output.ts deleted file mode 100644 index e199908e4d..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/output.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Types } from '../../constants'; -import { BuiltinInterface } from '../BuiltinInterface'; -import { Builtins } from '../Builtins'; -import { SysCallInstanceMemberPrimitive } from './SysCallInstanceMemberPrimitive'; -import { ValueInstanceOf } from './ValueInstanceOf'; - -class OutputInterface extends BuiltinInterface {} -class OutputConstructorInterface extends BuiltinInterface {} - -// tslint:disable-next-line export-name -export const add = (builtins: Builtins): void => { - builtins.addContractInterface('Output', new OutputInterface()); - builtins.addContractValue('Output', new ValueInstanceOf('OutputConstructor', (sb) => sb.helpers.isOutput)); - builtins.addContractMember( - 'Output', - 'address', - new SysCallInstanceMemberPrimitive('Neo.Output.GetScriptHash', Types.Output, Types.Buffer), - ); - builtins.addContractMember( - 'Output', - 'asset', - new SysCallInstanceMemberPrimitive('Neo.Output.GetAssetId', Types.Output, Types.Buffer), - ); - builtins.addContractMember( - 'Output', - 'value', - new SysCallInstanceMemberPrimitive('Neo.Output.GetValue', Types.Output, Types.Number), - ); - builtins.addContractInterface('OutputConstructor', new OutputConstructorInterface()); -}; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/address.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/address.ts index e1ec538bb2..683f3b10b2 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/address.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/address.ts @@ -48,7 +48,7 @@ export class SmartContractAddress implements BuiltinInstanceMemberValue { if (options.pushValue) { // [value] - sb.emitSysCall(node, 'System.ExecutionEngine.GetExecutingScriptHash'); + sb.emitSysCall(node, 'System.Runtime.GetExecutingScriptHash'); // [val] sb.emitHelper(node, options, sb.helpers.wrapBuffer); } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/destroy.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/destroy.ts index b82c601950..5996540fc2 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/destroy.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/destroy.ts @@ -23,7 +23,7 @@ export class SmartContractDestroy extends BuiltinInstanceMemberCall { sb.emitOp(node, 'DROP'); } - sb.emitSysCall(node, 'Neo.Contract.Destroy'); + sb.emitSysCall(node, 'System.Contract.Destroy'); if (optionsIn.pushValue) { // [val] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/for.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/for.ts index 3c510a101d..b19f71035a 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/for.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/for.ts @@ -33,7 +33,6 @@ export class SmartContractFor extends SmartContractForBase { node: ts.CallExpression, prop: ts.Declaration, addressName: Name, - callBuffer: Buffer, options: VisitOptions, ): void { if (tsUtils.argumented.getArguments(node).length < 1) { @@ -43,16 +42,27 @@ export class SmartContractFor extends SmartContractForBase { const arg = tsUtils.argumented.getArguments(node)[0]; const scriptHash = sb.context.analysis.extractLiteralAddress(arg); + // TODO: remove this and change how we call smart contracts, including our own + // [string, params, string] + sb.emitOp(node, 'TUCK'); + // [2, string, params, string] + sb.emitPushInt(node, 2); + // [[string, params], string] + sb.emitOp(node, 'PACK'); + // [string, [string, params]] + sb.emitOp(node, 'SWAP'); if (scriptHash === undefined) { // [bufferVal, string, params] sb.scope.get(sb, arg, options, addressName); // [buffer, string, params] sb.emitHelper(prop, options, sb.helpers.unwrapBuffer); // [result] - sb.emitOp(prop, 'CALL_ED', callBuffer); + sb.emitSysCall(node, 'System.Contract.Call'); } else { + // [buffer, string, params] + sb.emitPushBuffer(prop, scriptHash); // [result] - sb.emitOp(prop, 'CALL_E', Buffer.concat([callBuffer, scriptHash])); + sb.emitSysCall(node, 'System.Contract.Call'); } } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/index.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/index.ts index 24d126d64c..05027a3270 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/index.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/index.ts @@ -1,8 +1,6 @@ import { ContractPropertyName } from '../../../../constants'; -import { StructuredStorageType } from '../../../constants'; import { BuiltinBase } from '../../BuiltinBase'; import { BuiltinInstanceMemberStorageProperty } from '../../BuiltinInstanceMemberStorageProperty'; -import { BuiltinInstanceMemberStructuredStorageProperty } from '../../BuiltinInstanceMemberStructuredStorageProperty'; import { Builtins } from '../../Builtins'; import { SmartContractAddress } from './address'; import { SmartContractDestroy } from './destroy'; @@ -20,21 +18,5 @@ export const add = (builtins: Builtins): void => { ContractPropertyName.deployed, new BuiltinInstanceMemberStorageProperty(ContractPropertyName.deployed), ); - builtins.addContractMember( - 'SmartContract', - ContractPropertyName.processedTransactions, - new BuiltinInstanceMemberStructuredStorageProperty( - StructuredStorageType.SetStorage, - ContractPropertyName.processedTransactions, - ), - ); - builtins.addContractMember( - 'SmartContract', - ContractPropertyName.claimedTransactions, - new BuiltinInstanceMemberStructuredStorageProperty( - StructuredStorageType.MapStorage, - ContractPropertyName.claimedTransactions, - ), - ); builtins.addContractMember('SmartContract', ContractPropertyName.destroy, new SmartContractDestroy()); }; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/transaction.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/transaction.ts index 433b69d1ac..b15cf8116a 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/transaction.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/transaction.ts @@ -1,93 +1,72 @@ import { Types } from '../../constants'; import { BuiltinInterface } from '../BuiltinInterface'; import { Builtins } from '../Builtins'; -import { BuiltinValueObject } from '../BuiltinValueObject'; -import { SysCallInstanceMemberArray } from './SysCallInstanceMemberArray'; +import { BuiltinInstanceIndexValue } from './BuiltinInstanceIndexValue'; +import { SysCallInstanceMemberIndex } from './SysCallInstanceMemberIndex'; import { SysCallInstanceMemberPrimitive } from './SysCallInstanceMemberPrimitive'; import { ValueFor } from './ValueFor'; import { ValueInstanceOf } from './ValueInstanceOf'; -class TransactionBaseInterface extends BuiltinInterface {} -class TransactionBaseConstructorInterface extends BuiltinInterface {} -class TransactionValue extends BuiltinValueObject { - public readonly type = 'TransactionConstructor'; -} +class TransactionInterface extends BuiltinInterface {} class TransactionConstructorInterface extends BuiltinInterface {} -class MinerTransactionInterface extends BuiltinInterface {} -class IssueTransactionInterface extends BuiltinInterface {} -class ClaimTransactionInterface extends BuiltinInterface {} -class EnrollmentTransactionInterface extends BuiltinInterface {} -class RegisterTransactionInterface extends BuiltinInterface {} -class ContractTransactionInterface extends BuiltinInterface {} -class StateTransactionInterface extends BuiltinInterface {} -class PublishTransactionInterface extends BuiltinInterface {} -class InvocationTransactionInterface extends BuiltinInterface {} // tslint:disable-next-line export-name export const add = (builtins: Builtins): void => { - builtins.addContractInterface('TransactionBase', new TransactionBaseInterface()); + builtins.addContractInterface('Transaction', new TransactionInterface()); + builtins.addContractInterface('TransactionConstructor', new TransactionConstructorInterface()); builtins.addContractValue( - 'TransactionBase', - new ValueInstanceOf('TransactionBaseConstructor', (sb) => sb.helpers.isTransaction), - ); - builtins.addContractInterface('TransactionBaseConstructor', new TransactionBaseConstructorInterface()); - builtins.addContractMember( - 'TransactionBase', - 'type', - new SysCallInstanceMemberPrimitive('Neo.Transaction.GetType', Types.Transaction, Types.Number), + 'Transaction', + new ValueInstanceOf('TransactionConstructor', (sb) => sb.helpers.isTransaction), ); builtins.addContractMember( - 'TransactionBase', - 'hash', - new SysCallInstanceMemberPrimitive('Neo.Transaction.GetHash', Types.Transaction, Types.Buffer), + 'Transaction', + 'height', + new SysCallInstanceMemberIndex('System.Blockchain.GetTransactionHeight', 0, Types.Transaction, Types.Number), ); + builtins.addContractMember('Transaction', 'hash', new BuiltinInstanceIndexValue(0, Types.Transaction, Types.Buffer)); builtins.addContractMember( - 'TransactionBase', - 'attributes', - new SysCallInstanceMemberArray('Neo.Transaction.GetAttributes', Types.Transaction, Types.Attribute), + 'Transaction', + 'version', + new BuiltinInstanceIndexValue(1, Types.Transaction, Types.Number), ); + builtins.addContractMember('Transaction', 'nonce', new BuiltinInstanceIndexValue(2, Types.Transaction, Types.Number)); builtins.addContractMember( - 'TransactionBase', - 'outputs', - new SysCallInstanceMemberArray('Neo.Transaction.GetOutputs', Types.Transaction, Types.Output), + 'Transaction', + 'sender', + new BuiltinInstanceIndexValue(3, Types.Transaction, Types.Buffer), ); builtins.addContractMember( - 'TransactionBase', - 'inputs', - new SysCallInstanceMemberArray('Neo.Transaction.GetInputs', Types.Transaction, Types.Input), + 'Transaction', + 'systemFee', + new BuiltinInstanceIndexValue(4, Types.Transaction, Types.Number), ); builtins.addContractMember( - 'TransactionBase', - 'references', - new SysCallInstanceMemberArray('Neo.Transaction.GetReferences', Types.Transaction, Types.Output), + 'Transaction', + 'networkFee', + new BuiltinInstanceIndexValue(5, Types.Transaction, Types.Number), ); builtins.addContractMember( - 'TransactionBase', - 'unspentOutputs', - new SysCallInstanceMemberArray('Neo.Transaction.GetUnspentCoins', Types.Transaction, Types.Output), + 'Transaction', + 'validUntilBlock', + new BuiltinInstanceIndexValue(6, Types.Transaction, Types.Number), ); - - builtins.addContractInterface('InvocationTransaction', new InvocationTransactionInterface()); builtins.addContractMember( - 'InvocationTransaction', + 'Transaction', 'script', - new SysCallInstanceMemberPrimitive('Neo.InvocationTransaction.GetScript', Types.Transaction, Types.Buffer), + new BuiltinInstanceIndexValue(7, Types.Transaction, Types.Buffer), ); - builtins.addContractInterface('MinerTransaction', new MinerTransactionInterface()); - builtins.addContractInterface('IssueTransaction', new IssueTransactionInterface()); - builtins.addContractInterface('ClaimTransaction', new ClaimTransactionInterface()); - builtins.addContractInterface('EnrollmentTransaction', new EnrollmentTransactionInterface()); - builtins.addContractInterface('RegisterTransaction', new RegisterTransactionInterface()); - builtins.addContractInterface('ContractTransaction', new ContractTransactionInterface()); - builtins.addContractInterface('StateTransaction', new StateTransactionInterface()); - builtins.addContractInterface('PublishTransaction', new PublishTransactionInterface()); - - builtins.addContractValue('Transaction', new TransactionValue()); - builtins.addContractInterface('TransactionConstructor', new TransactionConstructorInterface()); + // TODO: notification is an array stack item which needs to be split up by index + // Need to input a Hash160 to get the notification + // Hash160 is script hash? SHA160 the script? + // builtins.addContractMember( + // 'Transaction', + // 'notifications', + // new SysCallInstanceMemberArray('System.Runtime.GetNotifications', Types.Transaction, Types.Notification), + // ); builtins.addContractMember( 'TransactionConstructor', 'for', - new ValueFor('Neo.Blockchain.GetTransaction', (sb, node, options) => { + new ValueFor('System.Blockchain.GetTransaction', (sb, node, options) => { sb.emitHelper(node, options, sb.helpers.wrapTransaction); }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/transactionType.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/transactionType.ts deleted file mode 100644 index 5891250b19..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/transactionType.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { TransactionTypeModel as TransactionType } from '@neo-one/client-common'; -import { BuiltinBase } from '../BuiltinBase'; -import { BuiltinConstantNumberMemberValue } from '../BuiltinConstantNumberMemberValue'; -import { Builtins } from '../Builtins'; - -class TransactionTypeValue extends BuiltinBase {} - -// tslint:disable-next-line export-name -export const add = (builtins: Builtins): void => { - builtins.addContractValue('TransactionType', new TransactionTypeValue()); - builtins.addContractMember('TransactionType', 'Miner', new BuiltinConstantNumberMemberValue(TransactionType.Miner)); - builtins.addContractMember('TransactionType', 'Issue', new BuiltinConstantNumberMemberValue(TransactionType.Issue)); - builtins.addContractMember('TransactionType', 'Claim', new BuiltinConstantNumberMemberValue(TransactionType.Claim)); - builtins.addContractMember( - 'TransactionType', - 'Enrollment', - new BuiltinConstantNumberMemberValue(TransactionType.Enrollment), - ); - builtins.addContractMember( - 'TransactionType', - 'Register', - new BuiltinConstantNumberMemberValue(TransactionType.Register), - ); - builtins.addContractMember( - 'TransactionType', - 'Contract', - new BuiltinConstantNumberMemberValue(TransactionType.Contract), - ); - builtins.addContractMember('TransactionType', 'State', new BuiltinConstantNumberMemberValue(TransactionType.State)); - builtins.addContractMember( - 'TransactionType', - 'Publish', - new BuiltinConstantNumberMemberValue(TransactionType.Publish), - ); - builtins.addContractMember( - 'TransactionType', - 'Invocation', - new BuiltinConstantNumberMemberValue(TransactionType.Invocation), - ); -}; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/createBuiltins.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/createBuiltins.ts index d91a36a541..1d931db990 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/createBuiltins.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/createBuiltins.ts @@ -1,5 +1,4 @@ import { Context } from '../../Context'; -import { add as addArguments } from './arguments'; import { add as addArray } from './array'; import { add as addAssertEqual } from './assertEqual'; import { add as addBoolean } from './boolean'; @@ -27,7 +26,6 @@ import { add as addTypedPropertyDescriptor } from './typedPropertyDescriptor'; export const createBuiltins = (context: Context): Builtins => { const builtins = new Builtins(context); - addArguments(builtins); addArray(builtins); addAssertEqual(builtins); addBoolean(builtins); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/delete.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/delete.ts index d2993ef6e6..d246290e82 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/delete.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/delete.ts @@ -33,6 +33,8 @@ export class MapDelete extends BuiltinInstanceMemberCall { sb.emitHelper(node, options, sb.helpers.unwrapMap); // [keyVal, map] sb.visit(tsUtils.argumented.getArguments(node)[0], options); + // [key, map] + sb.emitSysCall(node, 'System.Binary.Serialize'); // [val] sb.emitHelper(node, optionsIn, sb.helpers.mapDelete); } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/forEach.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/forEach.ts index bc49e89b4e..d32d40ef4d 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/forEach.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/forEach.ts @@ -32,11 +32,11 @@ export class MapForEach extends BuiltinInstanceMemberCall { // [map] sb.emitHelper(node, options, sb.helpers.unwrapMap); // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [objectVal, iterator] sb.visit(tsUtils.argumented.getArguments(node)[0], options); // [] - sb.emitHelper(node, options, sb.helpers.rawIteratorForEachFunc); + sb.emitHelper(node, options, sb.helpers.rawIteratorForEachFunc({ deserializeKey: true })); if (optionsIn.pushValue) { // [val] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/get.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/get.ts index 0e84d2ae81..a61f988a6b 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/get.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/get.ts @@ -33,6 +33,8 @@ export class MapGet extends BuiltinInstanceMemberCall { sb.emitHelper(node, options, sb.helpers.unwrapMap); // [keyVal, map] sb.visit(tsUtils.argumented.getArguments(node)[0], options); + // [key, map] + sb.emitSysCall(node, 'System.Binary.Serialize'); // [map, keyVal] sb.emitOp(node, 'SWAP'); // [map, keyVal, map] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/has.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/has.ts index d3f47c47bf..e5e56bfece 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/has.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/has.ts @@ -33,6 +33,8 @@ export class MapHas extends BuiltinInstanceMemberCall { sb.emitHelper(node, options, sb.helpers.unwrapMap); // [keyVal, map] sb.visit(tsUtils.argumented.getArguments(node)[0], options); + // [key, map] + sb.emitSysCall(node, 'System.Binary.Serialize'); // [boolean] sb.emitOp(node, 'HASKEY'); // [booleanVal] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/iterator.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/iterator.ts index 1058d69691..ea5d034ba7 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/iterator.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/iterator.ts @@ -34,8 +34,8 @@ export class MapIterator extends BuiltinInstanceMemberCall { // [map] sb.emitHelper(node, options, sb.helpers.unwrapMap); // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [val] - sb.emitHelper(node, options, sb.helpers.createIteratorIterableIterator({})); + sb.emitHelper(node, options, sb.helpers.createIteratorIterableIterator({ deserializeKey: true })); } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/set.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/set.ts index e2d4e0a568..dce27c93c9 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/set.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/set.ts @@ -37,6 +37,8 @@ export class MapSet extends BuiltinInstanceMemberCall { sb.emitHelper(node, options, sb.helpers.unwrapMap); // [keyVal, map] sb.visit(tsUtils.argumented.getArguments(node)[0], options); + // [key, map] + sb.emitSysCall(node, 'System.Binary.Serialize'); // [valVal, keyVal, map] sb.visit(tsUtils.argumented.getArguments(node)[1], options); // [] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/size.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/size.ts index 6eb0800bcf..03618e3716 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/size.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/map/size.ts @@ -9,7 +9,7 @@ export class MapSize extends BuiltinInstanceMemberValue { // [map] sb.emitHelper(node, options, sb.helpers.unwrapMap); // [number] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [val] sb.emitHelper(node, options, sb.helpers.wrapNumber); } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/object/keys.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/object/keys.ts index c902355c98..2e651ab943 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/object/keys.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/object/keys.ts @@ -26,7 +26,7 @@ export class ObjectKeys extends BuiltinMemberCall { // [arr] sb.emitHelper(node, innerOptions, sb.helpers.unwrapArray); // [number] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [arr] sb.emitHelper( node, @@ -101,13 +101,8 @@ export class ObjectKeys extends BuiltinMemberCall { iterable: emptyArray, iterableIterator: emptyArray, transaction: emptyArray, - output: emptyArray, attribute: emptyArray, - input: emptyArray, - account: emptyArray, - asset: emptyArray, contract: emptyArray, - header: emptyArray, block: emptyArray, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/add.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/add.ts index 0f51d7b778..291f940877 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/add.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/add.ts @@ -37,7 +37,9 @@ export class SetAdd extends BuiltinInstanceMemberCall { sb.emitHelper(node, options, sb.helpers.unwrapMap); // [valVal, map] sb.visit(tsUtils.argumented.getArguments(node)[0], options); - // [value, keyVal, map] + // [key, map] + sb.emitSysCall(node, 'System.Binary.Serialize'); + // [value, key, map] sb.emitPushBoolean(node, true); // [] sb.emitOp(node, 'SETITEM'); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/forEach.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/forEach.ts index 881a47d34d..3a6357bd22 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/forEach.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/forEach.ts @@ -32,13 +32,13 @@ export class SetForEach extends BuiltinInstanceMemberCall { // [map] sb.emitHelper(node, options, sb.helpers.unwrapMap); // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [enumerator] - sb.emitSysCall(node, 'Neo.Iterator.Keys'); + sb.emitSysCall(node, 'System.Iterator.Keys'); // [objectVal, iterator] sb.visit(tsUtils.argumented.getArguments(node)[0], options); // [] - sb.emitHelper(node, sb.noPushValueOptions(options), sb.helpers.rawEnumeratorForEachFunc); + sb.emitHelper(node, sb.noPushValueOptions(options), sb.helpers.rawEnumeratorForEachFunc({ deserializeKey: true })); if (optionsIn.pushValue) { // [val] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/index.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/index.ts index 7efcaf8c7a..6aa2ce1f43 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/index.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/index.ts @@ -57,6 +57,8 @@ class SetValue extends BuiltinNew { sb.emitOp(node, 'TUCK'); // [val, map, map] sb.emitOp(node, 'SWAP'); + // [val, map, map] + sb.emitSysCall(node, 'System.Binary.Serialize'); // [boolean, val, map, map] sb.emitPushBoolean(node, true); // [map] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/iterator.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/iterator.ts index 4a01992f1e..24e65e8900 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/iterator.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/set/iterator.ts @@ -34,10 +34,10 @@ export class SetIterator extends BuiltinInstanceMemberCall { // [map] sb.emitHelper(node, options, sb.helpers.unwrapMap); // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [enumerator] - sb.emitSysCall(node, 'Neo.Iterator.Keys'); + sb.emitSysCall(node, 'System.Iterator.Keys'); // [val] - sb.emitHelper(node, options, sb.helpers.createEnumeratorIterableIterator({})); + sb.emitHelper(node, options, sb.helpers.createEnumeratorIterableIterator({ deserializeKey: true })); } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/compile.ts b/packages/neo-one-smart-contract-compiler/src/compile/compile.ts index 1886418b41..5d8eb73bd4 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/compile.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/compile.ts @@ -1,6 +1,9 @@ +import { common, crypto } from '@neo-one/client-common'; +import { tsUtils } from '@neo-one/ts-utils'; import { RawSourceMap } from 'source-map'; import ts from 'typescript'; import { Context } from '../Context'; +import { processMethods } from '../utils'; import { getSmartContractInfo } from './getSmartContractInfo'; import { createHelpers } from './helper'; import { @@ -31,9 +34,14 @@ export const compileForDiagnostics = ({ context, sourceFile }: DiagnosticCompile scriptBuilder.process(); }; -export const compile = ({ context, sourceFile, linked = {}, sourceMaps = {} }: CompileOptions): CompileResult => { +export const compile = async ({ + context, + sourceFile, + linked = {}, + sourceMaps = {}, +}: CompileOptions): Promise => { const helpers = createHelpers(); - const { contractInfo, abi, contract, debugInfo } = getSmartContractInfo(context, sourceFile); + const { name, contractInfo, manifest, debugInfo } = getSmartContractInfo(context, sourceFile); const helperScriptBuilder = new HelperCapturingScriptBuilder( context, @@ -66,14 +74,35 @@ export const compile = ({ context, sourceFile, linked = {}, sourceMaps = {} }: C emittingScriptBuilder.process(); const finalResult = emittingScriptBuilder.getFinalResult(sourceMaps); + const script = finalResult.code.toString('hex'); + const hash = common.uInt160ToString(crypto.toScriptHash(Buffer.from(script, 'hex'))); + + const methods = await processMethods({ + context, + manifest, + debugInfo, + finalResult, + filePath: tsUtils.file.getFilePath(sourceFile), + }); return { contract: { - script: finalResult.code.toString('hex'), - ...contract, - ...finalResult.features, + name, + script, + manifest: { + hash, + ...manifest, + features: { + ...manifest.features, + ...finalResult.features, + }, + abi: { + hash, + ...manifest.abi, + methods, + }, + }, }, - abi, context, debugInfo, sourceMap: finalResult.sourceMap, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/constants/Types.ts b/packages/neo-one-smart-contract-compiler/src/compile/constants/Types.ts index 1369d57dfd..b87c89aa89 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/constants/Types.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/constants/Types.ts @@ -18,16 +18,12 @@ export enum Types { MapStorage = 17, SetStorage = 18, Transaction = 19, - Output = 20, - Attribute = 21, - Input = 22, - Account = 23, - Asset = 24, - Contract = 25, - Header = 26, - Block = 27, + Attribute = 20, + Contract = 21, + Block = 22, + Notification = 23, // Fake type, never appears - Iterable = 28, + Iterable = 24, } export type WrappableType = @@ -48,14 +44,10 @@ export type WrappableType = | Types.MapStorage | Types.SetStorage | Types.Transaction - | Types.Output | Types.Attribute - | Types.Input - | Types.Account - | Types.Asset | Types.Contract - | Types.Header - | Types.Block; + | Types.Block + | Types.Notification; export type IterableTypes = | Types.Array diff --git a/packages/neo-one-smart-contract-compiler/src/compile/declaration/ClassDeclarationCompiler.ts b/packages/neo-one-smart-contract-compiler/src/compile/declaration/ClassDeclarationCompiler.ts index 6529a6aeb7..5d483022d7 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/declaration/ClassDeclarationCompiler.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/declaration/ClassDeclarationCompiler.ts @@ -89,13 +89,8 @@ export class ClassDeclarationCompiler extends NodeCompiler iterable: throwTypeError, iterableIterator: throwTypeError, transaction: throwTypeError, - output: throwTypeError, attribute: throwTypeError, - input: throwTypeError, - account: throwTypeError, - asset: throwTypeError, contract: throwTypeError, - header: throwTypeError, block: throwTypeError, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/expression/ElementAccessExpressionCompiler.ts b/packages/neo-one-smart-contract-compiler/src/compile/expression/ElementAccessExpressionCompiler.ts index 8e10d0fa81..d36eb03668 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/expression/ElementAccessExpressionCompiler.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/expression/ElementAccessExpressionCompiler.ts @@ -123,13 +123,8 @@ export class ElementAccessExpressionCompiler extends NodeCompiler iterable: pushObject, iterableIterator: pushObject, transaction: pushObject, - output: pushObject, attribute: pushObject, - input: pushObject, - account: pushObject, - asset: pushObject, contract: pushObject, - header: pushObject, block: pushObject, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/getSmartContractInfo.ts b/packages/neo-one-smart-contract-compiler/src/compile/getSmartContractInfo.ts index ee9b98068e..35b1cb7eb2 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/getSmartContractInfo.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/getSmartContractInfo.ts @@ -1,5 +1,11 @@ -import { ABI, ContractParameterType } from '@neo-one/client-common'; -import { ContractRegister } from '@neo-one/client-full-core'; +import { + ContractEventDescriptorClient, + ContractGroup, + ContractMethodDescriptorClient, + ContractPermission, + UInt160Hex, + WildcardContainer, +} from '@neo-one/client-common'; import { tsUtils } from '@neo-one/ts-utils'; import { OmitStrict, utils } from '@neo-one/utils'; import ts from 'typescript'; @@ -8,12 +14,12 @@ import { Context } from '../Context'; import { ContractInfo, DebugInfo, - getABI, getAllPropInfos, getContractInfo, getContractProperties, getDebugInfo, } from '../contract'; +import { getManifest } from '../contract/getManifest'; import { DiagnosticCode } from '../DiagnosticCode'; import { DiagnosticMessage } from '../DiagnosticMessage'; import { @@ -24,9 +30,6 @@ import { BuiltinInstanceMemberStructuredStorageProperty, } from './builtins'; -const PARAMETERS: ReadonlyArray = ['String', 'Array']; -const RETURN_TYPE: ContractParameterType = 'Buffer'; - const getSmartContract = (context: Context, sourceFile: ts.SourceFile) => { const classDecls = tsUtils.statement .getStatements(sourceFile) @@ -68,13 +71,7 @@ const addContractInfo = (context: Context, contractInfo: ContractInfo) => { const propertyNameToOverride = new Map(); getAllPropInfos(contractInfo).forEach((propInfo) => { const symbol = context.analysis.getSymbol(propInfo.classDecl); - if ( - symbol !== undefined && - propInfo.type !== 'deploy' && - propInfo.type !== 'refundAssets' && - propInfo.type !== 'upgrade' && - propInfo.type !== 'completeSend' - ) { + if (symbol !== undefined && propInfo.type !== 'deploy' && propInfo.type !== 'upgrade') { const memberSymbol = propInfo.symbol; switch (propInfo.type) { case 'function': @@ -125,11 +122,33 @@ const addContractInfo = (context: Context, contractInfo: ContractInfo) => { addOverrideSymbol(context, contractInfo); }; +export type SmartContractInfoMethodDescriptor = OmitStrict; + +export interface SmartContractInfoABI { + readonly methods: readonly SmartContractInfoMethodDescriptor[]; + readonly events: readonly ContractEventDescriptorClient[]; +} + +export interface SmartContractInfoManifest { + readonly groups: readonly ContractGroup[]; + readonly features: { + readonly storage: boolean; + readonly payable: boolean; + }; + readonly supportedStandards: readonly string[]; + readonly abi: SmartContractInfoABI; + readonly permissions: readonly ContractPermission[]; + readonly trusts: WildcardContainer; + readonly safeMethods: WildcardContainer; + readonly hasStorage: boolean; + readonly payable: boolean; +} + export interface SmartContractInfo { + readonly name: string; readonly contractInfo: ContractInfo | undefined; - readonly abi: ABI; readonly debugInfo: DebugInfo; - readonly contract: OmitStrict; + readonly manifest: SmartContractInfoManifest; } export const getSmartContractInfo = (context: Context, sourceFile: ts.SourceFile): SmartContractInfo => { @@ -137,33 +156,36 @@ export const getSmartContractInfo = (context: Context, sourceFile: ts.SourceFile const contractInfo = smartContract === undefined ? undefined : getContractInfo(context, smartContract); const properties = smartContract === undefined ? DEFAULT_CONTRACT_PROPERTIES : getContractProperties(context, smartContract); - const payable = - contractInfo === undefined - ? true - : contractInfo.propInfos.some((propInfo) => propInfo.type === 'function' && propInfo.receive); if (contractInfo !== undefined) { addContractInfo(context, contractInfo); return { + name: properties.name, contractInfo, - abi: getABI(context, contractInfo), + manifest: getManifest(context, contractInfo, properties), debugInfo: getDebugInfo(context, contractInfo), - contract: { - parameters: PARAMETERS, - returnType: RETURN_TYPE, - ...properties, - storage: true, - dynamicInvoke: true, - payable, - }, }; } return { + name: properties.name, contractInfo, - abi: { - functions: [], - events: [], + manifest: { + groups: [], + features: { + storage: true, + payable: true, + }, + supportedStandards: [], + abi: { + methods: [], + events: [], + }, + permissions: [], + trusts: '*', + safeMethods: '*', + hasStorage: true, + payable: true, }, debugInfo: { entrypoint: '', @@ -171,13 +193,5 @@ export const getSmartContractInfo = (context: Context, sourceFile: ts.SourceFile methods: [], events: [], }, - contract: { - parameters: PARAMETERS, - returnType: RETURN_TYPE, - ...properties, - storage: true, - dynamicInvoke: true, - payable, - }, }; }; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrConcatHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrConcatHelper.ts index 45a7337fa7..57c016c13c 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrConcatHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrConcatHelper.ts @@ -10,7 +10,7 @@ export class ArrConcatHelper extends Helper { const options = sb.pushValueOptions(optionsIn); // [enumerator, result] - sb.emitSysCall(node, 'Neo.Enumerator.Create'); + sb.emitSysCall(node, 'System.Enumerator.Create'); sb.emitHelper( node, options, @@ -19,7 +19,7 @@ export class ArrConcatHelper extends Helper { // [enumerator, result, enumerator] sb.emitOp(node, 'TUCK'); // [boolean, result, enumerator] - sb.emitSysCall(node, 'Neo.Enumerator.Next'); + sb.emitSysCall(node, 'System.Enumerator.Next'); }, each: () => { // [result, enumerator, result] @@ -27,7 +27,7 @@ export class ArrConcatHelper extends Helper { // [enumerator, result, enumerator, result] sb.emitOp(node, 'OVER'); // [value, result, enumerator, result] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [enumerator, result] sb.emitOp(node, 'APPEND'); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrEveryFuncHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrEveryFuncHelper.ts index 75cd7b6ff6..b05d3cc9f7 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrEveryFuncHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrEveryFuncHelper.ts @@ -14,7 +14,7 @@ export class ArrEveryFuncHelper extends Helper { // [arr, callable] sb.emitOp(node, 'SWAP'); // [enumerator, callable] - sb.emitSysCall(node, 'Neo.Enumerator.Create'); + sb.emitSysCall(node, 'System.Enumerator.Create'); // [idx, enumerator, callable] sb.emitPushInt(node, 0); // [result, idx, enumerator, callable] @@ -31,7 +31,7 @@ export class ArrEveryFuncHelper extends Helper { // [enumerator, result, enumerator, result, idx, callable] sb.emitOp(node, 'OVER'); // [boolean, result, enumerator, result, idx, callable] - sb.emitSysCall(node, 'Neo.Enumerator.Next'); + sb.emitSysCall(node, 'System.Enumerator.Next'); // [boolean, enumerator, result, idx, callable] sb.emitOp(node, 'BOOLAND'); }, @@ -41,7 +41,7 @@ export class ArrEveryFuncHelper extends Helper { // [enumerator, enumerator, idx, callable] sb.emitOp(node, 'DUP'); // [value, enumerator, idx, callable] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [2, value, enumerator, idx, callable] sb.emitPushInt(node, 2); // [idx, value, enumerator, idx, callable] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrEveryHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrEveryHelper.ts index 5211fae1d7..b73bb9ce28 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrEveryHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrEveryHelper.ts @@ -24,7 +24,7 @@ export class ArrEveryHelper extends Helper { public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { // [enumerator] - sb.emitSysCall(node, 'Neo.Enumerator.Create'); + sb.emitSysCall(node, 'System.Enumerator.Create'); // [val] sb.emitHelper( node, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrFilterHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrFilterHelper.ts index 26c64080f8..1f480dc33c 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrFilterHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrFilterHelper.ts @@ -49,7 +49,7 @@ export class ArrFilterHelper extends Helper { if (this.withIndex) { // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [0, iterator] sb.emitPushInt(node, 0); // [accum, iterator] @@ -77,7 +77,7 @@ export class ArrFilterHelper extends Helper { ); } else { // [enumerator] - sb.emitSysCall(node, 'Neo.Enumerator.Create'); + sb.emitSysCall(node, 'System.Enumerator.Create'); // [0, enumerator] sb.emitPushInt(node, 0); // [accum, enumerator] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrFindHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrFindHelper.ts index cfac2a808d..2ed4f3a370 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrFindHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrFindHelper.ts @@ -19,7 +19,7 @@ export class ArrFindHelper extends Helper { public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { // [enumerator] - sb.emitSysCall(node, 'Neo.Enumerator.Create'); + sb.emitSysCall(node, 'System.Enumerator.Create'); // [val] sb.emitHelper( node, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrForEachFuncHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrForEachFuncHelper.ts index 4f31bc0c42..c0cdf905e1 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrForEachFuncHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrForEachFuncHelper.ts @@ -16,7 +16,7 @@ export class ArrForEachFuncHelper extends Helper { // [arr, arr, callable] sb.emitOp(node, 'DUP'); // [size, arr, callable] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [idx, size, arr, callable] sb.emitPushInt(node, 0); sb.emitHelper( diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrForEachHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrForEachHelper.ts index eea98a5a5a..22cf57fcd0 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrForEachHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrForEachHelper.ts @@ -23,7 +23,7 @@ export class ArrForEachHelper extends Helper { public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { if (this.withIndex) { // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [] sb.emitHelper( node, @@ -39,7 +39,7 @@ export class ArrForEachHelper extends Helper { ); } else { // [enumerator] - sb.emitSysCall(node, 'Neo.Enumerator.Create'); + sb.emitSysCall(node, 'System.Enumerator.Create'); sb.emitHelper( node, options, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrLeftHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrLeftHelper.ts index edf55f0535..ed0cc83480 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrLeftHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrLeftHelper.ts @@ -19,7 +19,7 @@ export class ArrLeftHelper extends Helper { // [arr, start, arr] sb.emitOp(node, 'OVER'); // [size, start, arr] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [0, size, start, arr] sb.emitPushInt(node, 0); // [outputArr, size, start, arr] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrMapFuncHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrMapFuncHelper.ts index e7294bc15a..ed23996bb6 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrMapFuncHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrMapFuncHelper.ts @@ -28,7 +28,9 @@ export class ArrMapFuncHelper extends Helper { // [size, callable, ...arr] sb.emitOp(node, 'SWAP'); // [idx, size, callable, ...arr] - sb.emitPushInt(node, 0); + sb.emitOp(node, 'DUP'); + // [idx, size, callable, ...arr] + sb.emitOp(node, 'DEC'); // [size, idx, callable, ...arr] sb.emitOp(node, 'SWAP'); sb.emitHelper( @@ -36,12 +38,14 @@ export class ArrMapFuncHelper extends Helper { options, sb.helpers.forLoop({ condition: () => { - // [size, idx, size, callable, ...arr] - sb.emitOp(node, 'TUCK'); - // [idx, size, idx, size, callable, ...arr] - sb.emitOp(node, 'OVER'); - // [size > idx, idx, size, callable, ...arr] - sb.emitOp(node, 'GT'); + // [idx, size, callable, ...arr] + sb.emitOp(node, 'SWAP'); + // [idx, idx, size, callable, ...arr] + sb.emitOp(node, 'DUP'); + // [0, idx, idx, size, callable, ...arr] + sb.emitPushInt(node, 0); + // [idx >= 0, idx, size, callable, ...arr] + sb.emitOp(node, 'GE'); }, each: (innerOptions) => { // [callable, idx, size, ...arr] @@ -56,9 +60,15 @@ export class ArrMapFuncHelper extends Helper { sb.emitHelper(node, options, sb.helpers.wrapNumber); // [idx, idxVal, callable, idx, callable, size, ...arr] sb.emitOp(node, 'SWAP'); - // [5, idx, idxVal, callable, idx, callable, size, ...arr] - sb.emitPushInt(node, 5); - // [idx + 5, idxVal, callable, idx, callable, size, ...arr] + // [idxVal, callable, idx, callable, size, ...arr] + sb.emitOp(node, 'DROP'); + // [4, idxVal, callable, idx, callable, size, ...arr] + sb.emitPushInt(node, 4); + // [size, idxVal, callable, idx, callable, size, ...arr] + sb.emitOp(node, 'PICK'); + // [4, size, idxVal, callable, idx, callable, size, ...arr] + sb.emitPushInt(node, 4); + // [size + 4, idxVal, callable, idx, callable, size, ...arr] sb.emitOp(node, 'ADD'); // [val, idxVal, callable, idx, callable, size, ...arr] sb.emitOp(node, 'ROLL'); @@ -70,24 +80,18 @@ export class ArrMapFuncHelper extends Helper { sb.emitOp(node, 'SWAP'); // [val, idx, callable, size, ...arr] sb.emitHelper(node, innerOptions, sb.helpers.call); - // [idx, val, idx, callable, size, ...arr] - sb.emitOp(node, 'OVER'); - // [4, idx, val, idx, callable, size, ...arr] - sb.emitPushInt(node, 4); - // [idx + 4, val, idx, callable, size, ...arr] - sb.emitOp(node, 'ADD'); - // [val, idx, callable, size, ...arr] - sb.emitOp(node, 'XTUCK'); + // [size, callable, idx, ...arr] + sb.emitOp(node, 'REVERSE4'); // [idx, callable, size, ...arr] - sb.emitOp(node, 'DROP'); + sb.emitOp(node, 'REVERSE3'); // [idx, callable, size, ...arr] - sb.emitOp(node, 'INC'); + sb.emitOp(node, 'DEC'); // [size, idx, callable, ...arr] sb.emitOp(node, 'ROT'); }, cleanup: () => { // [size, callable, ...arr] - sb.emitOp(node, 'NIP'); + sb.emitOp(node, 'DROP'); // [size, ...arr] sb.emitOp(node, 'NIP'); // [arr] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrMapHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrMapHelper.ts index 1a1583acbf..148b441e53 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrMapHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrMapHelper.ts @@ -23,7 +23,7 @@ export class ArrMapHelper extends Helper { public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { if (this.withIndex) { // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [0, iterator] sb.emitPushInt(node, 0); // [accum, iterator] @@ -54,7 +54,7 @@ export class ArrMapHelper extends Helper { ); } else { // [enumerator] - sb.emitSysCall(node, 'Neo.Enumerator.Create'); + sb.emitSysCall(node, 'System.Enumerator.Create'); // [0, enumerator] sb.emitPushInt(node, 0); // [accum, enumerator] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrRangeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrRangeHelper.ts index 0a22820a27..8bbd4f2595 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrRangeHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrRangeHelper.ts @@ -28,7 +28,7 @@ export class ArrRangeHelper extends Helper { // [arr] sb.emitOp(node, 'NEWARRAY'); // [enumerator] - sb.emitSysCall(node, 'Neo.Enumerator.Create'); + sb.emitSysCall(node, 'System.Enumerator.Create'); // [number, enumerator] sb.emitPushInt(node, 0); // [arr, enumerator] @@ -45,7 +45,7 @@ export class ArrRangeHelper extends Helper { // [enumerator, number, enumerator, arr] sb.emitOp(node, 'OVER'); // [boolean, number, enumerator, arr] - sb.emitSysCall(node, 'Neo.Enumerator.Next'); + sb.emitSysCall(node, 'System.Enumerator.Next'); }, each: (innerOptions) => { // [2, number, enumerator, arr] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrReduceFuncHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrReduceFuncHelper.ts index 923a979021..3fcab1b148 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrReduceFuncHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrReduceFuncHelper.ts @@ -16,7 +16,7 @@ export class ArrReduceFuncHelper extends Helper { // [arr, arr, callable, accum] sb.emitOp(node, 'DUP'); // [size, arr, callable, accum] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [idx, size, arr, callable, accum] sb.emitPushInt(node, 0); sb.emitHelper( @@ -67,10 +67,10 @@ export class ArrReduceFuncHelper extends Helper { sb.emitHelper(node, sb.pushValueOptions(innerOptions), sb.helpers.call); // [5, accum, idx, size, arr, callable] sb.emitPushInt(node, 5); - // [accum, idx, size, arr, callable, accum] - sb.emitOp(node, 'XTUCK'); + // [callable, arr, size, idx, accum] + sb.emitOp(node, 'REVERSEN'); // [idx, size, arr, callable, accum] - sb.emitOp(node, 'DROP'); + sb.emitOp(node, 'REVERSE4'); }, incrementor: () => { // [idx, size, arr, callable, accum] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrReduceHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrReduceHelper.ts index 4aecb5f6f9..710dbd04ba 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrReduceHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrReduceHelper.ts @@ -25,7 +25,7 @@ export class ArrReduceHelper extends Helper { // [arr, accum] sb.emitOp(node, 'SWAP'); // [iterator, accum] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [accum, iterator] sb.emitOp(node, 'SWAP'); // [accum] @@ -47,7 +47,7 @@ export class ArrReduceHelper extends Helper { // [arr, accum] sb.emitOp(node, 'SWAP'); // [enumerator, accum] - sb.emitSysCall(node, 'Neo.Enumerator.Create'); + sb.emitSysCall(node, 'System.Enumerator.Create'); // [accum, enumerator] sb.emitOp(node, 'SWAP'); // [accum] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrSomeFuncHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrSomeFuncHelper.ts index 5c615a5e88..19e67bacfb 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrSomeFuncHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrSomeFuncHelper.ts @@ -14,7 +14,7 @@ export class ArrSomeFuncHelper extends Helper { // [arr, callable] sb.emitOp(node, 'SWAP'); // [enumerator, callable] - sb.emitSysCall(node, 'Neo.Enumerator.Create'); + sb.emitSysCall(node, 'System.Enumerator.Create'); // [idx, enumerator, callable] sb.emitPushInt(node, 0); // [result, idx, enumerator, callable] @@ -33,7 +33,7 @@ export class ArrSomeFuncHelper extends Helper { // [enumerator, !result, enumerator, result, idx, callable] sb.emitOp(node, 'OVER'); // [boolean, !result, enumerator, result, idx, callable] - sb.emitSysCall(node, 'Neo.Enumerator.Next'); + sb.emitSysCall(node, 'System.Enumerator.Next'); // [boolean, enumerator, result, idx, callable] sb.emitOp(node, 'BOOLAND'); }, @@ -43,7 +43,7 @@ export class ArrSomeFuncHelper extends Helper { // [enumerator, enumerator, idx, callable] sb.emitOp(node, 'DUP'); // [value, enumerator, idx, callable] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [2, value, enumerator, idx, callable] sb.emitPushInt(node, 2); // [idx, value, enumerator, idx, callable] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrSomeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrSomeHelper.ts index aa440799ea..ccfc7ab461 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrSomeHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ArrSomeHelper.ts @@ -24,7 +24,7 @@ export class ArrSomeHelper extends Helper { public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { // [enumerator] - sb.emitSysCall(node, 'Neo.Enumerator.Create'); + sb.emitSysCall(node, 'System.Enumerator.Create'); // [val] sb.emitHelper( node, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ExtendArrHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ExtendArrHelper.ts index 91ee3c3139..9a4bb903bc 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ExtendArrHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/arr/ExtendArrHelper.ts @@ -13,7 +13,7 @@ export class ExtendArrHelper extends Helper { // [arr, length, arr] sb.emitOp(node, 'OVER'); // [currentLength, length, arr] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); sb.emitHelper( node, options, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/bind/ArrayBindingHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/bind/ArrayBindingHelper.ts index bfdc5c120b..d15d31a66b 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/bind/ArrayBindingHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/bind/ArrayBindingHelper.ts @@ -136,23 +136,25 @@ export class ArrayBindingHelper extends TypedHelper { // [map] sb.emitHelper(node, innerOptions, sb.helpers.unwrapMap); // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); }, (element, innerOptions) => { // [iterator, iterator] sb.emitOp(element, 'DUP'); // [boolean, iterator] - sb.emitSysCall(element, 'Neo.Enumerator.Next'); + sb.emitSysCall(element, 'System.Enumerator.Next'); // [iterator] sb.emitOp(element, 'DROP'); // [iterator, iterator] sb.emitOp(element, 'DUP'); // [val, iterator] - sb.emitSysCall(element, 'Neo.Enumerator.Value'); + sb.emitSysCall(element, 'System.Enumerator.Value'); // [iterator, val] sb.emitOp(element, 'SWAP'); // [key, val] - sb.emitSysCall(element, 'Neo.Iterator.Key'); + sb.emitSysCall(element, 'System.Iterator.Key'); + // [key, val] + sb.emitSysCall(element, 'System.Binary.Deserialize'); // [2, key, val] sb.emitPushInt(element, 2); // [arr] @@ -170,6 +172,7 @@ export class ArrayBindingHelper extends TypedHelper { element, innerOptions, sb.helpers.rawIteratorReduce({ + deserializeKey: true, each: handleMapLike(element), }), ); @@ -194,17 +197,19 @@ export class ArrayBindingHelper extends TypedHelper { // [map] sb.emitHelper(node, innerOptions, sb.helpers.unwrapSet); // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); }, (element) => { // [iterator, iterator] sb.emitOp(element, 'DUP'); // [boolean, iterator] - sb.emitSysCall(element, 'Neo.Enumerator.Next'); + sb.emitSysCall(element, 'System.Enumerator.Next'); // [iterator] sb.emitOp(element, 'DROP'); // [val] - sb.emitSysCall(element, 'Neo.Iterator.Key'); + sb.emitSysCall(element, 'System.Iterator.Key'); + // [val] + sb.emitSysCall(element, 'System.Binary.Deserialize'); }, (element, innerOptions) => { // [0, iterator] @@ -216,6 +221,7 @@ export class ArrayBindingHelper extends TypedHelper { element, innerOptions, sb.helpers.rawIteratorReduce({ + deserializeKey: true, each: handleSetLike(element), }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/bind/ObjectBindingHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/bind/ObjectBindingHelper.ts index f0fed6a15e..f71c55d652 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/bind/ObjectBindingHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/bind/ObjectBindingHelper.ts @@ -260,13 +260,8 @@ export class ObjectBindingHelper extends TypedHelper { iterable: throwInnerTypeError, iterableIterator: throwInnerTypeError, transaction: throwInnerTypeError, - output: throwInnerTypeError, attribute: throwInnerTypeError, - input: throwInnerTypeError, - account: throwInnerTypeError, - asset: throwInnerTypeError, contract: throwInnerTypeError, - header: throwInnerTypeError, block: throwInnerTypeError, }), ); @@ -337,10 +332,12 @@ export class ObjectBindingHelper extends TypedHelper { sb.emitPushInt(node, 3); // [obj, propertyArr, symbolArr] sb.emitHelper(node, innerOptions, sb.helpers.packObject); - // [3, objectVal, propertyArr, symbolArr] - sb.emitPushInt(node, 3); + // [objectVal, objectVal, propertyArr, symbolArr] + sb.emitOp(node, 'DUP'); + // [symbolArr, propertyArr, objectVal, objectVal] + sb.emitOp(node, 'REVERSE4'); // [objectVal, propertyArr, symbolArr, objectVal] - sb.emitOp(node, 'XTUCK'); + sb.emitOp(node, 'REVERSE3'); // [symbolArr, objectVal, propertyArr, objectVal] sb.emitOp(restElement, 'ROT'); // [propertyArr, symbolArr, objectVal, objectVal] @@ -388,14 +385,9 @@ export class ObjectBindingHelper extends TypedHelper { iteratorResult: createProcessBuiltin('IteratorResult'), iterable: createProcessBuiltin('Iterable'), iterableIterator: createProcessBuiltin('IterableIterator'), - transaction: createProcessBuiltin('TransactionBase'), - output: createProcessBuiltin('Output'), + transaction: createProcessBuiltin('Transaction'), attribute: createProcessBuiltin('AttributeBase'), - input: createProcessBuiltin('Input'), - account: createProcessBuiltin('Account'), - asset: createProcessBuiltin('Asset'), contract: createProcessBuiltin('Contract'), - header: createProcessBuiltin('Header'), block: createProcessBuiltin('Block'), }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/buffer/BufferSliceHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/buffer/BufferSliceHelper.ts index 467053bd9c..c6bf72fc31 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/buffer/BufferSliceHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/buffer/BufferSliceHelper.ts @@ -93,7 +93,7 @@ export class BufferSliceHelper extends Helper { // [start, end, start, end, buffer] sb.emitOp(node, 'OVER'); // [end <= start, start, end, buffer] - sb.emitOp(node, 'LTE'); + sb.emitOp(node, 'LE'); }, whenTrue: () => { // [end, buffer] @@ -195,7 +195,7 @@ export class BufferSliceHelper extends Helper { // [0, right, buffer, right] sb.emitPushInt(node, 0); // [right < 0, buffer, right] - sb.emitOp(node, 'LTE'); + sb.emitOp(node, 'LE'); }, whenTrue: () => { // [right] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/cache/GetCachedValueHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/cache/GetCachedValueHelper.ts index 394bb3d3f6..7273228660 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/cache/GetCachedValueHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/cache/GetCachedValueHelper.ts @@ -46,10 +46,12 @@ export class GetCachedValueHelper extends Helper { whenFalse: () => { // [val, keyVal, map] this.create(options); - // [3, val, keyVal, map] - sb.emitPushInt(node, 3); + // [val, val, keyVal, map] + sb.emitOp(node, 'DUP'); + // [map, keyVal, val, val] + sb.emitOp(node, 'REVERSE4'); // [val, keyVal, map, val] - sb.emitOp(node, 'XTUCK'); + sb.emitOp(node, 'REVERSE3'); // [val] sb.emitOp(node, 'SETITEM'); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/common/ArrSliceHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/common/ArrSliceHelper.ts index d7b162d897..4e1955d03e 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/common/ArrSliceHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/common/ArrSliceHelper.ts @@ -35,7 +35,7 @@ export class ArrSliceHelper extends Helper { // [arr, start, arr] sb.emitOp(node, 'OVER'); // [end, start, arr] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [start, end, arr] sb.emitOp(node, 'SWAP'); } @@ -60,7 +60,7 @@ export class ArrSliceHelper extends Helper { // [arr, start, arr, end] sb.emitOp(node, 'TUCK'); // [size, start, arr, end] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [start, arr, end] sb.emitOp(node, 'ADD'); // [end, start, arr] @@ -87,7 +87,7 @@ export class ArrSliceHelper extends Helper { // [arr, end, arr, start] sb.emitOp(node, 'TUCK'); // [size, end, arr, start] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [end, arr, start] sb.emitOp(node, 'ADD'); // [start, end, arr] @@ -103,7 +103,7 @@ export class ArrSliceHelper extends Helper { // [arr, end, arr, start] sb.emitOp(node, 'TUCK'); // [size, end, arr, start] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [end, arr, start] sb.emitOp(node, 'MIN'); // [start, end, arr] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/common/ConsoleLogHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/common/ConsoleLogHelper.ts index 86a5d24175..e22b1f7e71 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/common/ConsoleLogHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/common/ConsoleLogHelper.ts @@ -13,7 +13,7 @@ export class ConsoleLogHelper extends Helper { // [value] sb.emitHelper(node, options, sb.helpers.genericLogSerialize); // [buffer] - sb.emitSysCall(node, 'Neo.Runtime.Serialize'); + sb.emitSysCall(node, 'System.Binary.Serialize'); // [line, buffer] sb.emitLine(node); // ['console.log', line, buffer] @@ -22,7 +22,9 @@ export class ConsoleLogHelper extends Helper { sb.emitPushInt(node, 3); // [arr] sb.emitOp(node, 'PACK'); + // ['console.log', arr] + sb.emitPushString(node, 'console.log'); // [] - sb.emitSysCall(node, 'Neo.Runtime.Notify'); + sb.emitSysCall(node, 'System.Runtime.Notify'); } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/common/GenericLogSerializeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/common/GenericLogSerializeHelper.ts index 941f4a3008..bcb36440d4 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/common/GenericLogSerializeHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/common/GenericLogSerializeHelper.ts @@ -50,6 +50,7 @@ export class GenericLogSerializeHelper extends Helper { node, innerOptions, sb.helpers.mapReduce({ + deserializeKey: true, each: (innerInnerOptions) => { // [val, arr, key] sb.emitOp(node, 'ROT'); @@ -87,6 +88,7 @@ export class GenericLogSerializeHelper extends Helper { node, innerOptions, sb.helpers.mapReduce({ + deserializeKey: true, each: (innerInnerOptions) => { // [val, arr, key] sb.emitOp(node, 'ROT'); @@ -185,13 +187,8 @@ export class GenericLogSerializeHelper extends Helper { iterable: throwTypeError, iterableIterator: throwTypeError, transaction: throwTypeError, - output: throwTypeError, attribute: throwTypeError, - input: throwTypeError, - account: throwTypeError, - asset: throwTypeError, contract: throwTypeError, - header: throwTypeError, block: throwTypeError, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/BreakHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/BreakHelper.ts index e0f8be6ad7..5dd0d5f874 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/BreakHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/BreakHelper.ts @@ -21,7 +21,7 @@ export class BreakHelper extends Helper { pc = options.finallyPC; sb.emitPushInt(node, constants.FINALLY_COMPLETION); } - sb.emitJmp(node, 'JMP', pc); + sb.emitJmp(node, 'JMP_L', pc); } } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ContinueHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ContinueHelper.ts index f6f8544aad..9f010658e2 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ContinueHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ContinueHelper.ts @@ -21,7 +21,7 @@ export class ContinueHelper extends Helper { pc = options.finallyPC; sb.emitPushInt(node, constants.FINALLY_COMPLETION); } - sb.emitJmp(node, 'JMP', pc); + sb.emitJmp(node, 'JMP_L', pc); } } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ReturnHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ReturnHelper.ts index d9ea2ae19d..867dca9341 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ReturnHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ReturnHelper.ts @@ -18,7 +18,7 @@ export class ReturnHelper extends Helper { sb.emitPushInt(node, constants.NORMAL_COMPLETION); // [finally, normal, val] sb.emitPushInt(node, constants.FINALLY_COMPLETION); - sb.emitJmp(node, 'JMP', finallyPC); + sb.emitJmp(node, 'JMP_L', finallyPC); } } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ThrowCompletionBaseHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ThrowCompletionBaseHelper.ts index b8806a7083..f0b2e9c51e 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ThrowCompletionBaseHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ThrowCompletionBaseHelper.ts @@ -28,13 +28,13 @@ export class ThrowCompletionBaseHelper extends Helper { if (catchPC !== undefined) { sb.emitPushInt(node, constants.THROW_COMPLETION); - sb.emitJmp(node, 'JMP', catchPC); + sb.emitJmp(node, 'JMP_L', catchPC); } else if (finallyPC !== undefined) { // [throw, val] sb.emitPushInt(node, constants.THROW_COMPLETION); // [finally, throw, val] sb.emitPushInt(node, constants.FINALLY_COMPLETION); - sb.emitJmp(node, 'JMP', finallyPC); + sb.emitJmp(node, 'JMP_L', finallyPC); } else if (ts.isSourceFile(node) || (parent !== undefined && ts.isSourceFile(parent))) { sb.emitOp(node, 'DROP'); sb.emitHelper( @@ -45,7 +45,7 @@ export class ThrowCompletionBaseHelper extends Helper { sb.emitHelper(node, options, sb.helpers.invocationIsCaller); }, whenTrue: () => { - sb.emitOp(node, 'THROW'); + sb.emitOp(node, 'ABORT'); }, whenFalse: () => { sb.emitPushBoolean(node, false); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ThrowCompletionHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ThrowCompletionHelper.ts index 38f839446d..42bc24f2a8 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ThrowCompletionHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ThrowCompletionHelper.ts @@ -17,8 +17,10 @@ export class ThrowCompletionHelper extends Helper { sb.emitPushInt(node, 2); // [array] sb.emitOp(node, 'PACK'); + // ['trace', array] + sb.emitPushString(node, 'trace'); // [] - sb.emitSysCall(node, 'Neo.Runtime.Notify'); + sb.emitSysCall(node, 'System.Runtime.Notify'); // [] sb.emitHelper(node, options, sb.helpers.throwCompletionBase); } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ThrowHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ThrowHelper.ts index d98018d408..ebeb86c202 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ThrowHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/completionRecord/ThrowHelper.ts @@ -44,8 +44,10 @@ export class ThrowHelper extends Helper { sb.emitPushInt(node, 3); // [array, errorVal] sb.emitOp(node, 'PACK'); + // ['error', array, errorVal] + sb.emitPushString(node, 'error'); // [errorVal] - sb.emitSysCall(node, 'Neo.Runtime.Notify'); + sb.emitSysCall(node, 'System.Runtime.Notify'); // [] sb.emitHelper(node, optionsIn, sb.helpers.throwCompletion); } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/ApplicationMatchesVerificationHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/ApplicationMatchesVerificationHelper.ts index d833307507..2688180658 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/ApplicationMatchesVerificationHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/ApplicationMatchesVerificationHelper.ts @@ -1,4 +1,4 @@ -import { Op } from '@neo-one/client-common'; +import { getSysCallHash, Op } from '@neo-one/client-common'; import ts from 'typescript'; import { ScriptBuilder } from '../../sb'; import { VisitOptions } from '../../types'; @@ -11,46 +11,50 @@ export class ApplicationMatchesVerificationHelper extends Helper { const options = sb.pushValueOptions(optionsIn); // [transaction] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); + sb.emitSysCall(node, 'System.Runtime.GetScriptContainer'); + // [7, transaction] + sb.emitPushInt(node, 7); // [buffer] - sb.emitSysCall(node, 'Neo.InvocationTransaction.GetScript'); + sb.emitOp(node, 'PICKITEM'); // [buffer, buffer] sb.emitOp(node, 'DUP'); - // [21, buffer, buffer] - sb.emitPushInt(node, 21); - // [21, buffer, 21, buffer] + // [25, buffer, buffer] + sb.emitPushInt(node, 25); + // [25, buffer, 25, buffer] sb.emitOp(node, 'TUCK'); - // [appCallHash, 21, buffer] + // [appCallHash, 25, buffer] sb.emitOp(node, 'RIGHT'); - // [appCall, appCallHash, 21, buffer] - sb.emitPushBuffer(node, Buffer.from([Op.APPCALL])); - // [hash, appCall, appCallHash, 21, buffer] - sb.emitSysCall(node, 'System.ExecutionEngine.GetExecutingScriptHash'); - // [appCallHash, appCallHash, 21, buffer] + // [appCall, appCallHash, 25, buffer] + sb.emitPushBuffer(node, Buffer.concat([Buffer.from([Op.SYSCALL]), getSysCallHash('System.Contract.Call')])); + // [hash, appCall, appCallHash, 25, buffer] + sb.emitSysCall(node, 'System.Runtime.GetExecutingScriptHash'); + // [appCallHash, appCallHash, 25, buffer] sb.emitOp(node, 'CAT'); sb.emitHelper( node, options, sb.helpers.if({ condition: () => { - // [boolean, 21, buffer] + // [boolean, 25, buffer] sb.emitOp(node, 'EQUAL'); }, whenTrue: () => { - // [buffer, 21, buffer] + // [buffer, 25, buffer] sb.emitOp(node, 'OVER'); - // [size, 21, buffer] + // [size, 25, buffer] sb.emitOp(node, 'SIZE'); - // [21, size, buffer] + // [25, size, buffer] sb.emitOp(node, 'SWAP'); - // [size - 21, buffer] + // [size - 25, buffer] sb.emitOp(node, 'SUB'); // [argsBuffer] sb.emitOp(node, 'LEFT'); // [argsHash] - sb.emitOp(node, 'HASH160'); + sb.emitSysCall(node, 'Neo.Crypto.SHA256'); + // [argsHash] + sb.emitSysCall(node, 'Neo.Crypto.RIPEMD160'); // [entryHash, argsHash] - sb.emitSysCall(node, 'System.ExecutionEngine.GetEntryScriptHash'); + sb.emitSysCall(node, 'System.Runtime.GetEntryScriptHash'); // [boolean] sb.emitOp(node, 'EQUAL'); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/CompleteSendHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/CompleteSendHelper.ts deleted file mode 100644 index fda8fda0d9..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/CompleteSendHelper.ts +++ /dev/null @@ -1,147 +0,0 @@ -import ts from 'typescript'; -import { ContractPropertyName } from '../../../constants'; -import { Types } from '../../constants'; -import { ScriptBuilder } from '../../sb'; -import { VisitOptions } from '../../types'; -import { Helper } from '../Helper'; - -// Input: [] -// Output: [boolean] -export class CompleteSendHelper extends Helper { - public emit(sb: ScriptBuilder, node: ts.Node, optionsIn: VisitOptions): void { - const options = sb.pushValueOptions(optionsIn); - - // [transaction] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [inputs] - sb.emitSysCall(node, 'Neo.Transaction.GetInputs'); - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [inputs, inputs] - sb.emitOp(node, 'DUP'); - // [size, inputs] - sb.emitOp(node, 'ARRAYSIZE'); - // [0, size, inputs] - sb.emitPushInt(node, 0); - // [size == 0, inputs] - sb.emitOp(node, 'NUMEQUAL'); - }, - whenTrue: () => { - // [] - sb.emitOp(node, 'DROP'); - // [boolean] - sb.emitPushBoolean(node, false); - }, - whenFalse: () => { - // [0, inputs] - sb.emitPushInt(node, 0); - // [input] - sb.emitOp(node, 'PICKITEM'); - // [input, input] - sb.emitOp(node, 'DUP'); - // [number, input] - sb.emitSysCall(node, 'Neo.Input.GetIndex'); - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [0, number, input] - sb.emitPushInt(node, 0); - // [number == 0, input] - sb.emitOp(node, 'NUMEQUAL'); - }, - whenTrue: () => { - // [hash] - sb.emitSysCall(node, 'Neo.Input.GetHash'); - // [val, hash] - sb.emitHelper( - node, - options, - sb.helpers.createStructuredStorage({ - prefix: ContractPropertyName.claimedTransactions, - type: Types.MapStorage, - }), - ); - // [hash, val] - sb.emitOp(node, 'SWAP'); - // [hashVal, val] - sb.emitHelper(node, options, sb.helpers.wrapBuffer); - // [val] - sb.emitHelper( - node, - options, - sb.helpers.getStructuredStorage({ - type: Types.MapStorage, - keyType: undefined, - knownKeyType: Types.Buffer, - }), - ); - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [val, val] - sb.emitOp(node, 'DUP'); - // [boolean, val] - sb.emitHelper(node, options, sb.helpers.isUndefined); - }, - whenTrue: () => { - // [] - sb.emitOp(node, 'DROP'); - // [boolean] - sb.emitPushBoolean(node, false); - }, - whenFalse: () => { - // [buffer] - sb.emitHelper(node, options, sb.helpers.unwrapBuffer); - // [boolean] - sb.emitHelper(node, options, sb.helpers.isCaller); - // [transaction, boolean] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [references, boolean] - sb.emitSysCall(node, 'Neo.Transaction.GetReferences'); - // [references, boolean] - sb.emitHelper( - node, - options, - sb.helpers.arrFilter({ - map: () => { - // [buffer] - sb.emitSysCall(node, 'Neo.Output.GetScriptHash'); - // [buffer, buffer] - sb.emitSysCall(node, 'System.ExecutionEngine.GetExecutingScriptHash'); - // [boolean] - sb.emitOp(node, 'EQUAL'); - }, - }), - ); - // [size, boolean] - sb.emitOp(node, 'ARRAYSIZE'); - // [1, size, boolean] - sb.emitPushInt(node, 1); - // [size == 1, boolean] - sb.emitOp(node, 'NUMEQUAL'); - // [boolean] - sb.emitOp(node, 'BOOLAND'); - }, - }), - ); - }, - whenFalse: () => { - // [] - sb.emitOp(node, 'DROP'); - // [boolean] - sb.emitPushBoolean(node, false); - }, - }), - ); - }, - }), - ); - } -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/DidReceiveAssetsHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/DidReceiveAssetsHelper.ts deleted file mode 100644 index 1b25fb7e64..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/DidReceiveAssetsHelper.ts +++ /dev/null @@ -1,37 +0,0 @@ -import ts from 'typescript'; -import { ScriptBuilder } from '../../sb'; -import { VisitOptions } from '../../types'; -import { Helper } from '../Helper'; - -// Input: [] -// Output: [boolean] -export class DidReceiveAssetsHelper extends Helper { - public emit(sb: ScriptBuilder, node: ts.Node, optionsIn: VisitOptions): void { - const options = sb.pushValueOptions(optionsIn); - - // [transaction] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [outputs] - sb.emitSysCall(node, 'Neo.Transaction.GetOutputs'); - // [boolean] - sb.emitHelper( - node, - options, - sb.helpers.arrSome({ - map: () => { - // [hash] - sb.emitSysCall(node, 'Neo.Output.GetScriptHash'); - // [hash, hash] - sb.emitSysCall(node, 'System.ExecutionEngine.GetExecutingScriptHash'); - // [boolean] - sb.emitOp(node, 'EQUAL'); - }, - }), - ); - - if (!optionsIn.pushValue) { - // [] - sb.emitOp(node, 'DROP'); - } - } -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/DidReceiveNonClaimAssetsHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/DidReceiveNonClaimAssetsHelper.ts deleted file mode 100644 index 12a273083e..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/DidReceiveNonClaimAssetsHelper.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { common } from '@neo-one/client-common'; -import ts from 'typescript'; -import { ScriptBuilder } from '../../sb'; -import { VisitOptions } from '../../types'; -import { Helper } from '../Helper'; - -// Input: [] -// Output: [boolean] -export class DidReceiveNonClaimAssetsHelper extends Helper { - public emit(sb: ScriptBuilder, node: ts.Node, optionsIn: VisitOptions): void { - const options = sb.pushValueOptions(optionsIn); - - // [transaction] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [outputs] - sb.emitSysCall(node, 'Neo.Transaction.GetOutputs'); - // [map] - sb.emitHelper(node, options, sb.helpers.getOutputAssetValueMap); - // [transaction, map] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [outputs, map] - sb.emitSysCall(node, 'Neo.Transaction.GetReferences'); - // [map] - sb.emitHelper(node, options, sb.helpers.mergeAssetValueMaps({ add: false })); - // [boolean] - sb.emitHelper( - node, - optionsIn, - sb.helpers.mapSome({ - each: () => { - // [buffer, key, value] - sb.emitPushBuffer(node, common.stringToUInt256(common.GAS_ASSET_HASH)); - // [isGAS, value] - sb.emitOp(node, 'EQUAL'); - // [!isGAS, value] - sb.emitOp(node, 'NOT'); - // [value, !isGAS] - sb.emitOp(node, 'SWAP'); - // [0, value, !isGAS] - sb.emitPushInt(node, 0); - // [value > 0, !isGAS] - sb.emitOp(node, 'GT'); - // [value > 0 && !isGAS] - sb.emitOp(node, 'BOOLAND'); - }, - }), - ); - - if (!optionsIn.pushValue) { - // [] - sb.emitOp(node, 'DROP'); - } - } -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/DidSendAssetsHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/DidSendAssetsHelper.ts deleted file mode 100644 index 79d470e371..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/DidSendAssetsHelper.ts +++ /dev/null @@ -1,37 +0,0 @@ -import ts from 'typescript'; -import { ScriptBuilder } from '../../sb'; -import { VisitOptions } from '../../types'; -import { Helper } from '../Helper'; - -// Input: [] -// Output: [boolean] -export class DidSendAssetsHelper extends Helper { - public emit(sb: ScriptBuilder, node: ts.Node, optionsIn: VisitOptions): void { - const options = sb.pushValueOptions(optionsIn); - - // [transaction] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [outputs] - sb.emitSysCall(node, 'Neo.Transaction.GetReferences'); - // [boolean] - sb.emitHelper( - node, - options, - sb.helpers.arrSome({ - map: () => { - // [hash] - sb.emitSysCall(node, 'Neo.Output.GetScriptHash'); - // [hash, hash] - sb.emitSysCall(node, 'System.ExecutionEngine.GetExecutingScriptHash'); - // [boolean] - sb.emitOp(node, 'EQUAL'); - }, - }), - ); - - if (!optionsIn.pushValue) { - // [] - sb.emitOp(node, 'DROP'); - } - } -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/GetOutputAssetValueMapHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/GetOutputAssetValueMapHelper.ts deleted file mode 100644 index 8591ba11cd..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/GetOutputAssetValueMapHelper.ts +++ /dev/null @@ -1,23 +0,0 @@ -import ts from 'typescript'; -import { ScriptBuilder } from '../../sb'; -import { VisitOptions } from '../../types'; -import { Helper } from '../Helper'; - -// Input: [outputs] -// Output: [map] -export class GetOutputAssetValueMapHelper extends Helper { - public emit(sb: ScriptBuilder, node: ts.Node, optionsIn: VisitOptions): void { - // [map, outputs] - sb.emitOp(node, 'NEWMAP'); - // [outputs, map] - sb.emitOp(node, 'SWAP'); - // [map] - sb.emitHelper( - node, - optionsIn, - sb.helpers.mergeAssetValueMaps({ - add: true, - }), - ); - } -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleNormalHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleNormalHelper.ts index b6a79610f2..513ddf713c 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleNormalHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleNormalHelper.ts @@ -47,14 +47,6 @@ export class HandleNormalHelper extends Helper { sb.emitPushInt(decl, 1); // [arg] sb.emitHelper(decl, options, sb.helpers.getArgument); - if (propInfo.claim) { - // [arg, arg] - sb.emitOp(decl, 'DUP'); - // [transaction, arg, arg] - sb.emitSysCall(decl, 'System.ExecutionEngine.GetScriptContainer'); - // [arg] - sb.emitOp(decl, 'APPEND'); - } sb.withScope(decl, options, (innerOptions) => { sb.emitHelper( decl, @@ -126,18 +118,6 @@ export class HandleNormalHelper extends Helper { return; } - if (propInfo.type === 'refundAssets') { - sb.emitHelper(node, options, sb.helpers.refundAssets); - - return; - } - - if (propInfo.type === 'completeSend') { - sb.emitHelper(node, options, sb.helpers.completeSend); - - return; - } - if (propInfo.type === 'deploy') { throw new Error('Something went wrong!'); } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleReceiveHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleReceiveHelper.ts deleted file mode 100644 index f4c138196e..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleReceiveHelper.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { HandleSendUnsafeReceiveHelperBase } from './HandleSendUnsafeReceiveHelperBase'; - -// Input: [] -// Output: [boolean] -export class HandleReceiveHelper extends HandleSendUnsafeReceiveHelperBase { - protected readonly lessThan = false; -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleSendHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleSendHelper.ts deleted file mode 100644 index 3db18d5f7a..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleSendHelper.ts +++ /dev/null @@ -1,344 +0,0 @@ -import { tsUtils } from '@neo-one/ts-utils'; -import ts from 'typescript'; -import { ContractPropertyName } from '../../../constants'; -import { Types } from '../../constants'; -import { ScriptBuilder } from '../../sb'; -import { VisitOptions } from '../../types'; -import { Helper } from '../Helper'; -import { createWrapParam } from './utils'; - -export interface HandleSendHelperOptions { - readonly method: ts.MethodDeclaration | ts.PropertyDeclaration; - readonly returnType: ts.Type | undefined; -} - -// Input: [] -// Output: [boolean] -export class HandleSendHelper extends Helper { - private readonly method: ts.MethodDeclaration | ts.PropertyDeclaration; - private readonly returnType: ts.Type | undefined; - - public constructor({ method, returnType }: HandleSendHelperOptions) { - super(); - this.method = method; - this.returnType = returnType; - } - - public emit(sb: ScriptBuilder, node: ts.Node, optionsIn: VisitOptions): void { - const options = sb.pushValueOptions(optionsIn); - const method = this.method; - if (ts.isPropertyDeclaration(method)) { - sb.context.reportUnsupported(method); - - return; - } - - // isProcessed(Blockchain.currentTransaction.hash) - // [transaction] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [hash] - sb.emitSysCall(node, 'Neo.Transaction.GetHash'); - // [boolean] - sb.emitHelper(node, options, sb.helpers.isProcessedTransaction); - - // !firstOutputToSelf() - // [transaction, boolean] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [outputs, boolean] - sb.emitSysCall(node, 'Neo.Transaction.GetOutputs'); - // [outputs, outputs, boolean] - sb.emitOp(node, 'DUP'); - // [outputs, outputs, outputs, boolean] - sb.emitOp(node, 'DUP'); - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [size, outputs, outputs, boolean] - sb.emitOp(node, 'ARRAYSIZE'); - // [0, size, outputs, outputs, boolean] - sb.emitPushInt(node, 0); - // [size <= 0, outputs, outputs, boolean] - sb.emitOp(node, 'LTE'); - }, - whenTrue: () => { - // [outputs, boolean] - sb.emitOp(node, 'DROP'); - // [boolean, outputs, boolean] - sb.emitPushBoolean(node, true); - }, - whenFalse: () => { - // [0, outputs, outputs, boolean] - sb.emitPushInt(node, 0); - // [output, outputs, boolean] - sb.emitOp(node, 'PICKITEM'); - // [buffer, outputs, boolean] - sb.emitSysCall(node, 'Neo.Output.GetScriptHash'); - // [buffer, buffer, outputs, boolean] - sb.emitSysCall(node, 'System.ExecutionEngine.GetExecutingScriptHash'); - // [firstOutputToSelf, outputs, boolean] - sb.emitOp(node, 'EQUAL'); - // [boolean, outputs, boolean] - sb.emitOp(node, 'NOT'); - }, - }), - ); - - // [boolean, boolean, outputs] - sb.emitOp(node, 'ROT'); - // [boolean, outputs] - sb.emitOp(node, 'BOOLOR'); - - // !allInputsAreProcessedAndUnclaimed() - // [transaction, boolean, outputs] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [inputs, boolean, outputs] - sb.emitSysCall(node, 'Neo.Transaction.GetInputs'); - sb.emitHelper( - node, - options, - sb.helpers.arrEvery({ - map: (innerOptions) => { - // [input, input] - sb.emitOp(node, 'DUP'); - // [buffer, input] - sb.emitSysCall(node, 'Neo.Input.GetHash'); - // [buffer, buffer, input] - sb.emitOp(node, 'DUP'); - // [boolean, buffer, input] - sb.emitHelper(node, innerOptions, sb.helpers.isProcessedTransaction); - // [buffer, boolean, input] - sb.emitOp(node, 'SWAP'); - // [boolean, boolean, input] - sb.emitHelper(node, innerOptions, sb.helpers.isClaimedTransaction); - // [boolean, boolean, input] - sb.emitOp(node, 'NOT'); - // [input, boolean, boolean] - sb.emitOp(node, 'ROT'); - // [number, boolean, boolean] - sb.emitSysCall(node, 'Neo.Input.GetIndex'); - // [0, number, boolean, boolean] - sb.emitPushInt(node, 0); - // [number === 0, boolean, boolean] - sb.emitOp(node, 'NUMEQUAL'); - // [number !== 0, boolean, boolean] - sb.emitOp(node, 'NOT'); - // [boolean, boolean] - sb.emitOp(node, 'BOOLOR'); - // [boolean] - sb.emitOp(node, 'BOOLAND'); - }, - }), - ); - // [boolean, boolean, outputs] - sb.emitOp(node, 'NOT'); - // [boolean, outputs] - sb.emitOp(node, 'BOOLOR'); - - // !netZero() - // [outputs, boolean, outputs] - sb.emitOp(node, 'OVER'); - // [map, boolean, outputs] - sb.emitHelper(node, options, sb.helpers.getOutputAssetValueMap); - // [transaction, map, boolean, outputs] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [references, map, boolean, outputs] - sb.emitSysCall(node, 'Neo.Transaction.GetReferences'); - // [map, boolean, outputs] - sb.emitHelper(node, options, sb.helpers.mergeAssetValueMaps({ add: false })); - // [boolean, boolean, outputs] - sb.emitHelper( - node, - optionsIn, - sb.helpers.mapEvery({ - each: () => { - // [value] - sb.emitOp(node, 'DROP'); - // [0, value] - sb.emitPushInt(node, 0); - // [boolean] - sb.emitOp(node, 'NUMEQUAL'); - }, - }), - ); - // [boolean, boolean, outputs] - sb.emitOp(node, 'NOT'); - - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [boolean, outputs] - sb.emitOp(node, 'BOOLOR'); - }, - whenTrue: () => { - // [] - sb.emitOp(node, 'DROP'); - // [boolean] - sb.emitPushBoolean(node, false); - }, - whenFalse: () => { - // [0, outputs] - sb.emitPushInt(node, 0); - // [output] - sb.emitOp(node, 'PICKITEM'); - // [number, output] - sb.emitPushInt(node, 1); - // [arg, output] - sb.emitHelper(node, options, sb.helpers.getArgument); - // [output, arg, output] - sb.emitOp(node, 'OVER'); - // [arg, output, arg, output] - sb.emitOp(node, 'OVER'); - // [arg, arg, output, arg, output] - sb.emitOp(node, 'DUP'); - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [size, arg, output, arg, output] - sb.emitOp(node, 'ARRAYSIZE'); - // [size, size, arg, output, arg, output] - sb.emitOp(node, 'DUP'); - // [0, size, size, arg, output, arg, output] - sb.emitPushInt(node, 0); - // [size == 0, size, arg, output, arg, output] - sb.emitOp(node, 'NUMEQUAL'); - }, - whenTrue: () => { - // [arg, output, arg, output] - sb.emitOp(node, 'DROP'); - // [output, arg, output] - sb.emitOp(node, 'DROP'); - // [arg, output] - sb.emitOp(node, 'DROP'); - // [output] - sb.emitOp(node, 'DROP'); - // [] - sb.emitOp(node, 'DROP'); - // [boolean] - sb.emitPushBoolean(node, false); - }, - whenFalse: () => { - // [size - 1, arg, output, arg, output] - sb.emitOp(node, 'DEC'); - // [arg, size - 1, arg, output, arg, output] - sb.emitOp(node, 'OVER'); - // [size - 1, arg, size - 1, arg, output, arg, output] - sb.emitOp(node, 'OVER'); - // [receiver, size - 1, arg, output, arg, output] - sb.emitOp(node, 'PICKITEM'); - // [arg, receiver, size - 1, output, arg, output] - sb.emitOp(node, 'ROT'); - // [size - 1, arg, receiver, output, arg, output] - sb.emitOp(node, 'ROT'); - // [receiver, output, arg, output] - sb.emitOp(node, 'REMOVE'); - // [transfer, receiver, output, arg, output] - sb.emitOp(node, 'NEWMAP'); - // [transfer, receiver, transfer, output, arg, output] - sb.emitOp(node, 'TUCK'); - // [receiver, transfer, receiver, transfer, output, arg, output] - sb.emitOp(node, 'OVER'); - // ['to', receiver, transfer, receiver, transfer, output, arg, output] - sb.emitPushString(node, 'to'); - // [receiver, 'to', transfer, receiver, transfer, output, arg, output] - sb.emitOp(node, 'SWAP'); - // [receiver, transfer, output, arg, output] - sb.emitOp(node, 'SETITEM'); - // [output, receiver, transfer, arg, output] - sb.emitOp(node, 'ROT'); - // [transfer, output, receiver, arg, output] - sb.emitOp(node, 'ROT'); - // [transfer, output, transfer, receiver, arg, output] - sb.emitOp(node, 'TUCK'); - // ['asset', transfer, output, transfer, receiver, arg, output] - sb.emitPushString(node, 'asset'); - // [output, 'asset', transfer, transfer, receiver, arg, output] - sb.emitOp(node, 'ROT'); - // [buffer, 'asset', transfer, transfer, receiver, arg, output] - sb.emitSysCall(node, 'Neo.Output.GetAssetId'); - // [transfer, receiver, arg, output] - sb.emitOp(node, 'SETITEM'); - // [arg, transfer, receiver, output] - sb.emitOp(node, 'ROT'); - // [arg, transfer, arg, receiver, output] - sb.emitOp(node, 'TUCK'); - // [transfer, arg, transfer, arg, receiver, output] - sb.emitOp(node, 'OVER'); - // [transfer, arg, receiver, output] - sb.emitOp(node, 'APPEND'); - // ['amount', transfer, arg, receiver, output] - sb.emitPushString(node, 'amount'); - // [4, 'amount', transfer, arg, receiver, output] - sb.emitPushInt(node, 4); - // [output, 'amount', transfer, arg, receiver] - sb.emitOp(node, 'ROLL'); - // [value, 'amount', transfer, arg, receiver] - sb.emitSysCall(node, 'Neo.Output.GetValue'); - // [arg, receiver] - sb.emitOp(node, 'SETITEM'); - sb.withScope(node, options, (innerOptions) => { - // [receiver] - sb.emitHelper( - node, - innerOptions, - sb.helpers.parameters({ - params: tsUtils.parametered.getParameters(method), - mapParam: createWrapParam(sb), - }), - ); - - // [val, receiver] - sb.emitHelper(node, innerOptions, sb.helpers.invokeSmartContractMethod({ method })); - // [value, receiver] - sb.emitHelper(node, innerOptions, sb.helpers.unwrapValRecursive({ type: this.returnType })); - // [receiver, value] - sb.emitOp(node, 'SWAP'); - // [transaction, receiver, value] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [hash, receiver, value] - sb.emitSysCall(node, 'Neo.Transaction.GetHash'); - // [bufferVal, receiver, value] - sb.emitHelper(node, innerOptions, sb.helpers.wrapBuffer); - // [receiver, bufferVal, value] - sb.emitOp(node, 'SWAP'); - // [val, receiver, bufferVal, value] - sb.emitHelper( - node, - innerOptions, - sb.helpers.createStructuredStorage({ - prefix: ContractPropertyName.claimedTransactions, - type: Types.MapStorage, - }), - ); - // [bufferVal, val, receiver, value] - sb.emitOp(node, 'ROT'); - // [receiver, bufferVal, val, value] - sb.emitOp(node, 'ROT'); - // [receiverVal, bufferVal, val, value] - sb.emitHelper(node, innerOptions, sb.helpers.wrapBuffer); - // [value] - sb.emitHelper( - node, - options, - sb.helpers.setStructuredStorage({ - type: Types.MapStorage, - keyType: undefined, - knownKeyType: Types.Buffer, - }), - ); - // [value] - sb.emitHelper(node, innerOptions, sb.helpers.setProcessedTransaction); - }); - }, - }), - ); - }, - }), - ); - } -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleSendUnsafeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleSendUnsafeHelper.ts deleted file mode 100644 index 7bdfa26d4f..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleSendUnsafeHelper.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { HandleSendUnsafeReceiveHelperBase } from './HandleSendUnsafeReceiveHelperBase'; - -// Input: [] -// Output: [boolean] -export class HandleSendUnsafeHelper extends HandleSendUnsafeReceiveHelperBase { - protected readonly lessThan = true; -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleSendUnsafeReceiveHelperBase.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleSendUnsafeReceiveHelperBase.ts deleted file mode 100644 index 0f14681283..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/HandleSendUnsafeReceiveHelperBase.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { tsUtils } from '@neo-one/ts-utils'; -import ts from 'typescript'; -import { ScriptBuilder } from '../../sb'; -import { VisitOptions } from '../../types'; -import { Helper } from '../Helper'; -import { createWrapParam } from './utils'; - -export interface HandleSendUnsafeReceiveHelperBaseOptions { - readonly method: ts.MethodDeclaration; - readonly returnType: ts.Type | undefined; - readonly opposite: boolean; -} - -// Input: [] -// Output: [boolean] -export abstract class HandleSendUnsafeReceiveHelperBase extends Helper { - protected abstract readonly lessThan: boolean; - private readonly method: ts.MethodDeclaration; - private readonly returnType: ts.Type | undefined; - private readonly opposite: boolean; - - public constructor({ method, returnType, opposite }: HandleSendUnsafeReceiveHelperBaseOptions) { - super(); - this.method = method; - this.returnType = returnType; - this.opposite = opposite; - } - - public emit(sb: ScriptBuilder, node: ts.Node, optionsIn: VisitOptions): void { - const options = sb.pushValueOptions(optionsIn); - - // isProcessed(Blockchain.currentTransaction.hash) - // [transaction] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [hash] - sb.emitSysCall(node, 'Neo.Transaction.GetHash'); - // [boolean] - sb.emitHelper(node, options, sb.helpers.isProcessedTransaction); - - // !isReceiveMethod() && !onlySentAssets() - if (!this.opposite) { - // [transaction, boolean] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [outputs, boolean] - sb.emitSysCall(node, 'Neo.Transaction.GetOutputs'); - // [map, boolean] - sb.emitHelper(node, options, sb.helpers.getOutputAssetValueMap); - // [transaction, map, boolean] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [outputs, map, boolean] - sb.emitSysCall(node, 'Neo.Transaction.GetReferences'); - // [map, boolean] - sb.emitHelper(node, options, sb.helpers.mergeAssetValueMaps({ add: false })); - // [boolean, boolean] - sb.emitHelper( - node, - optionsIn, - sb.helpers.mapEvery({ - each: () => { - // [value] - sb.emitOp(node, 'DROP'); - // [0, value] - sb.emitPushInt(node, 0); - // [value > 0] - sb.emitOp(node, this.lessThan ? 'LT' : 'GT'); - }, - }), - ); - // [boolean, boolean] - sb.emitOp(node, 'NOT'); - // [boolean] - sb.emitOp(node, 'BOOLOR'); - } - - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // do nothing - }, - whenTrue: () => { - // [boolean] - sb.emitPushBoolean(node, false); - }, - whenFalse: () => { - // [number] - sb.emitPushInt(node, 1); - // [arg] - sb.emitHelper(node, options, sb.helpers.getArgument); - sb.withScope(node, options, (innerOptions) => { - // [] - sb.emitHelper( - node, - innerOptions, - sb.helpers.parameters({ - params: tsUtils.parametered.getParameters(this.method), - mapParam: createWrapParam(sb), - }), - ); - - // [val] - sb.emitHelper(node, innerOptions, sb.helpers.invokeSmartContractMethod({ method: this.method })); - // [value] - sb.emitHelper(node, innerOptions, sb.helpers.unwrapValRecursive({ type: this.returnType })); - // [value] - sb.emitHelper(node, innerOptions, sb.helpers.setProcessedTransaction); - }); - }, - }), - ); - } -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/InvocationIsCallerHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/InvocationIsCallerHelper.ts index 4592223b2e..0a20f4002f 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/InvocationIsCallerHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/InvocationIsCallerHelper.ts @@ -16,11 +16,11 @@ export class InvocationIsCallerHelper extends Helper { // [buffer] sb.emitHelper(node, options, sb.helpers.getGlobalProperty({ property: GlobalProperty.CallingScriptHash })); // [buffer, buffer] - sb.emitSysCall(node, 'System.ExecutionEngine.GetEntryScriptHash'); + sb.emitSysCall(node, 'System.Runtime.GetEntryScriptHash'); // [boolean] sb.emitOp(node, 'EQUAL'); // [trigger, boolean] - sb.emitSysCall(node, 'Neo.Runtime.GetTrigger'); + sb.emitSysCall(node, 'System.Runtime.GetTrigger'); // [number, trigger, boolean] sb.emitPushInt(node, 0x00); // [boolean, boolean] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/InvokeSmartContractHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/InvokeSmartContractHelper.ts index b39d02a510..39afcc82a2 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/InvokeSmartContractHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/InvokeSmartContractHelper.ts @@ -1,17 +1,15 @@ // tslint:disable prefer-switch -import { TransactionTypeModel as TransactionType } from '@neo-one/client-common'; +import { TriggerType } from '@neo-one/client-common'; import { utils } from '@neo-one/utils'; import _ from 'lodash'; import ts from 'typescript'; import { ContractPropertyName } from '../../../constants'; import { AccessorPropInfo, - CompleteSendPropInfo, ContractInfo, DeployPropInfo, FunctionPropInfo, PropertyPropInfo, - RefundAssetsPropInfo, UpgradePropInfo, } from '../../../contract'; import { ScriptBuilder } from '../../sb'; @@ -136,11 +134,14 @@ export interface InvokeSmartContractHelperOptions { * const args = getArgument(1); * return contract.normalMethod(...args); * } - * + */ + +// TODO: args has changed. no longer array of properties, but a script and a serialized manifest +/** * const handleUpgrade = () => { * if (contract.approveUpgrade()) { * const args = getArgument(1); - * Neo.Contract.Migrate(...args); + * System.Contract.Update(...args); * return true; * } * return false; @@ -166,66 +167,18 @@ export interface InvokeSmartContractHelperOptions { * switch (method) { * case 'normalMethod': * return handleNormalMethod(); - * case 'sendMethod': - * return handleSend(); - * case 'sendUnsafeMethod': - * return handleSendUnsafe(); - * case 'receiveMethod': - * return handleReceive(); * case 'upgrade': * return handleUpgrade(); - * case 'refundAssets': - * return handleRefund(); - * case 'completeSend': - * return handleCompleteSend(); * case 'deploy': * return handleDeploy(); * default: * throw new Error('Unknown method'); * } else if (trigger === TriggerType.Verification) { - * const transaction = System.ExecutionEnginer.GetScriptContainer(); - * if (transaction.type === TransactionType.Invocation) { - * const method = getArgument(0); - * switch (method) { - * case 'sendMethod': - * if (!applicationScriptMatchesVerification()) { - * return false; - * } - * return handleSend(); - * case 'sendUnsafeMethod': - * if (!applicationScriptMatchesVerification()) { - * return false; - * } - * return handleSendUnsafe(); - * case 'receiveMethod': - * if (!applicationScriptMatchesVerification()) { - * return false; - * } - * return handleReceive(); - * case 'completeSend': - * return handleCompleteSend(); - * default: - * if (didSendAssets() || didReceiveAssets()) { - * throw new Error(); - * } - * return handleOther(); - * } - * } else if (transaction.type === TransactionType.Claim) { - * if (didSendAssets() || didReceiveNonClaimAssets()) { - * return false; - * } - * const method = getArgument(0); - * switch (method) { - * case 'claimMethod': - * return handleClaim(); - * default: - * throw new Error(); - * } else { - * throw new Error(); - * } - * } else { - * throw new Error(); - * } + * const method = getArgument(0); + * switch (method) { + * default: + * return handleOther(); + * } * } * */ @@ -267,24 +220,7 @@ export class InvokeSmartContractHelper extends Helper { return; } - - if (propInfo.send) { - sb.emitHelper(decl, options, sb.helpers.handleSend({ method: decl, returnType: propInfo.returnType })); - } else if (propInfo.receive) { - sb.emitHelper( - decl, - options, - sb.helpers.handleReceive({ opposite: propInfo.sendUnsafe, method: decl, returnType: propInfo.returnType }), - ); - } else if (propInfo.sendUnsafe) { - sb.emitHelper( - decl, - options, - sb.helpers.handleSendUnsafe({ opposite: propInfo.receive, method: decl, returnType: propInfo.returnType }), - ); - } else { - sb.emitHelper(decl, options, sb.helpers.handleNormal({ propInfo })); - } + sb.emitHelper(decl, options, sb.helpers.handleNormal({ propInfo })); }); const getDeployCase = (contractInfo: ContractInfo, propInfo: DeployPropInfo) => { @@ -327,16 +263,7 @@ export class InvokeSmartContractHelper extends Helper { return mutableCases; }; - const getRefundAssetsCase = (propInfo: RefundAssetsPropInfo) => - getCaseBase(node, ContractPropertyName.refundAssets, () => { - sb.emitHelper(node, options, sb.helpers.handleNormal({ propInfo })); - }); - - const getCompleteSendCase = (propInfo: CompleteSendPropInfo) => - getCaseBase(node, ContractPropertyName.completeSend, () => { - sb.emitHelper(node, options, sb.helpers.handleNormal({ propInfo })); - }); - + // TODO: change arguments from properties array to script and serialized new manifest const getUpgradeCase = (propInfo: UpgradePropInfo) => getCaseBase(node, ContractPropertyName.upgrade, () => { sb.emitHelper(node, options, sb.helpers.handleNormal({ propInfo })); @@ -350,34 +277,24 @@ export class InvokeSmartContractHelper extends Helper { return [ { propCase: getFunctionCase(propInfo), - claimVerify: propInfo.claim, - invokeVerify: propInfo.send || propInfo.sendUnsafe || propInfo.receive, + invokeVerify: false, }, ]; } - if (propInfo.type === 'refundAssets') { - return [{ propCase: getRefundAssetsCase(propInfo), claimVerify: false, invokeVerify: true }]; - } - - if (propInfo.type === 'completeSend') { - return [{ propCase: getCompleteSendCase(propInfo), claimVerify: false, invokeVerify: true }]; - } - if (propInfo.type === 'property') { - return [{ propCase: getPropertyCase(propInfo), claimVerify: false, invokeVerify: false }]; + return [{ propCase: getPropertyCase(propInfo), invokeVerify: false }]; } if (propInfo.type === 'accessor') { return getAccessorCase(propInfo).map((propCase) => ({ propCase, - claimVerify: false, invokeVerify: false, })); } if (propInfo.type === 'upgrade') { - return [{ propCase: getUpgradeCase(propInfo), claimVerify: false, invokeVerify: false }]; + return [{ propCase: getUpgradeCase(propInfo), invokeVerify: false }]; } if (propInfo.type === 'deploy') { @@ -390,18 +307,17 @@ export class InvokeSmartContractHelper extends Helper { throw new Error('For TS'); }), ); - let applicationCases = allCases.filter((propCase) => !propCase.claimVerify).map(({ propCase }) => propCase); + let applicationCases = allCases.map(({ propCase }) => propCase); const deploy = findDeployInfo(this.contractInfo); if (deploy !== undefined) { applicationCases = applicationCases.concat(getDeployCase(deploy[0], deploy[1])); } const invocationVerifyCases = allCases.filter((propCase) => propCase.invokeVerify).map(({ propCase }) => propCase); const nonVerifyCases = allCases.filter((propCase) => !propCase.invokeVerify).map(({ propCase }) => propCase); - const claimCases = allCases.filter((propCase) => propCase.claimVerify).map(({ propCase }) => propCase); const throwDefault = () => { sb.emitOp(node, 'DROP'); - sb.emitOp(node, 'THROW'); + sb.emitOp(node, 'ABORT'); }; const handleInvokeVerify = (func: () => void) => { @@ -425,46 +341,16 @@ export class InvokeSmartContractHelper extends Helper { ); }; - const handleClaimVerify = (func: () => void) => { - // [value] - func(); - // [] - sb.emitOp(node, 'DROP'); - // [boolean] - sb.emitPushBoolean(node, true); - }; - const handleDefaultInvokeVerify = () => { - // [] - sb.emitOp(node, 'DROP'); - // [boolean] - sb.emitHelper(node, options, sb.helpers.didReceiveAssets); - // [boolean, boolean] - sb.emitHelper(node, options, sb.helpers.didSendAssets); - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [boolean] - sb.emitOp(node, 'BOOLOR'); - }, - whenTrue: () => { - sb.emitOp(node, 'THROW'); - }, - whenFalse: () => { - // [number] - sb.emitPushInt(node, 0); - // [arg] - sb.emitHelper(node, options, sb.helpers.getArgument); - sb.emitHelper(node, options, sb.helpers.case(nonVerifyCases, throwDefault)); - }, - }), - ); + // [number] + sb.emitPushInt(node, 0); + // [arg] + sb.emitHelper(node, options, sb.helpers.getArgument); + sb.emitHelper(node, options, sb.helpers.case(nonVerifyCases, throwDefault)); }; // [number] - sb.emitSysCall(node, 'Neo.Runtime.GetTrigger'); + sb.emitSysCall(node, 'System.Runtime.GetTrigger'); sb.emitHelper( node, options, @@ -475,7 +361,7 @@ export class InvokeSmartContractHelper extends Helper { // [number, number] sb.emitOp(node, 'DUP'); // [number, number, number] - sb.emitPushInt(node, 0x10); + sb.emitPushInt(node, TriggerType.Application); // [boolean, number] sb.emitOp(node, 'NUMEQUAL'); }, @@ -495,106 +381,29 @@ export class InvokeSmartContractHelper extends Helper { // [number, number] sb.emitOp(node, 'DUP'); // [number, number, number] - sb.emitPushInt(node, 0x00); + sb.emitPushInt(node, TriggerType.Verification); // [boolean, number] sb.emitOp(node, 'NUMEQUAL'); }, whenTrue: () => { // [] sb.emitOp(node, 'DROP'); - // [transaction] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [type] - sb.emitSysCall(node, 'Neo.Transaction.GetType'); + // [number] + sb.emitPushInt(node, 0); + // [arg] + sb.emitHelper(node, options, sb.helpers.getArgument); + // [] sb.emitHelper( node, options, sb.helpers.case( - [ - { - condition: () => { - // [type, type] - sb.emitOp(node, 'DUP'); - // [number, type, type] - sb.emitPushInt(node, TransactionType.Invocation); - // [boolean, type] - sb.emitOp(node, 'NUMEQUAL'); - }, - whenTrue: () => { - // [] - sb.emitOp(node, 'DROP'); - // [number] - sb.emitPushInt(node, 0); - // [arg] - sb.emitHelper(node, options, sb.helpers.getArgument); - // [] - sb.emitHelper( - node, - options, - sb.helpers.case( - invocationVerifyCases.map((propCase) => ({ - ...propCase, - whenTrue: () => { - handleInvokeVerify(propCase.whenTrue); - }, - })), - handleDefaultInvokeVerify, - ), - ); - }, - }, - { - condition: () => { - // [type, type] - sb.emitOp(node, 'DUP'); - // [number, type, type] - sb.emitPushInt(node, TransactionType.Claim); - // [boolean, type] - sb.emitOp(node, 'NUMEQUAL'); - }, - whenTrue: () => { - // [] - sb.emitOp(node, 'DROP'); - // [boolean] - sb.emitHelper(node, options, sb.helpers.didReceiveNonClaimAssets); - // [boolean, boolean] - sb.emitHelper(node, options, sb.helpers.didSendAssets); - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [boolean] - sb.emitOp(node, 'BOOLOR'); - }, - whenTrue: () => { - sb.emitPushBoolean(node, false); - }, - whenFalse: () => { - // [number] - sb.emitPushInt(node, 0); - // [arg] - sb.emitHelper(node, options, sb.helpers.getArgument); - sb.emitHelper( - node, - options, - sb.helpers.case( - claimCases.map((propCase) => ({ - ...propCase, - whenTrue: () => { - handleClaimVerify(propCase.whenTrue); - }, - })), - throwDefault, - ), - ); - }, - }), - ); - }, + invocationVerifyCases.map((propCase) => ({ + ...propCase, + whenTrue: () => { + handleInvokeVerify(propCase.whenTrue); }, - ], - throwDefault, + })), + handleDefaultInvokeVerify, ), ); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/IsCallerHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/IsCallerHelper.ts index 4dff93c3d4..ccad88988a 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/IsCallerHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/IsCallerHelper.ts @@ -33,7 +33,7 @@ export class IsCallerHelper extends Helper { // [addressBuffer, addressBuffer] sb.emitOp(node, 'DUP'); // [maybeContract, addressBuffer] - sb.emitSysCall(node, 'Neo.Blockchain.GetContract'); + sb.emitSysCall(node, 'System.Blockchain.GetContract'); sb.emitHelper( node, options, @@ -49,7 +49,7 @@ export class IsCallerHelper extends Helper { // (this is the first contract called OR we are in verification BECAUSE verification already checks that this is the first contract called). whenTrue: () => { // [boolean] - sb.emitSysCall(node, 'Neo.Runtime.CheckWitness'); + sb.emitSysCall(node, 'System.Runtime.CheckWitness'); // [boolean, boolean] sb.emitHelper(node, options, sb.helpers.invocationIsCaller); // [boolean] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/MergeAssetValueMapsHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/MergeAssetValueMapsHelper.ts deleted file mode 100644 index 5f73b657a0..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/MergeAssetValueMapsHelper.ts +++ /dev/null @@ -1,123 +0,0 @@ -import ts from 'typescript'; -import { ScriptBuilder } from '../../sb'; -import { VisitOptions } from '../../types'; -import { Helper } from '../Helper'; - -export interface MergeAssetValueMapsHelperOptions { - readonly add: boolean; -} - -// Input: [outputs, map] -// Output: [map] -export class MergeAssetValueMapsHelper extends Helper { - private readonly add: boolean; - - public constructor({ add }: MergeAssetValueMapsHelperOptions) { - super(); - this.add = add; - } - - public emit(sb: ScriptBuilder, node: ts.Node, optionsIn: VisitOptions): void { - const options = sb.pushValueOptions(optionsIn); - - // [map, outputs] - sb.emitOp(node, 'SWAP'); - sb.emitHelper( - node, - options, - sb.helpers.arrReduce({ - each: () => { - // [map, output, map] - sb.emitOp(node, 'TUCK'); - // [map, output, map, map] - sb.emitOp(node, 'TUCK'); - // [output, map, output, map, map] - sb.emitOp(node, 'OVER'); - // [hash, map, output, map, map] - sb.emitSysCall(node, 'Neo.Output.GetScriptHash'); - // [hash, hash, map, output, map, map] - sb.emitSysCall(node, 'System.ExecutionEngine.GetExecutingScriptHash'); - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [boolean, map, output, map, map] - sb.emitOp(node, 'EQUAL'); - }, - whenTrue: () => { - // [output, map, output, map, map] - sb.emitOp(node, 'OVER'); - // [map, output, map, output, map, map] - sb.emitOp(node, 'OVER'); - // [output, map, map, output, map, map] - sb.emitOp(node, 'SWAP'); - // [hash, map, map, output, map, map] - sb.emitSysCall(node, 'Neo.Output.GetAssetId'); - // [hash, map, hash, map, output, map, map] - sb.emitOp(node, 'TUCK'); - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [hasKey, hash, map, output, map, map] - sb.emitOp(node, 'HASKEY'); - }, - whenTrue: () => { - // [hash, map, hash, output, map, map] - sb.emitOp(node, 'TUCK'); - // [value, hash, output, map, map] - sb.emitOp(node, 'PICKITEM'); - // [output, value, hash, map, map] - sb.emitOp(node, 'ROT'); - // [value, value, hash, map, map] - sb.emitSysCall(node, 'Neo.Output.GetValue'); - if (this.add) { - // [value, hash, map, map] - sb.emitOp(node, 'ADD'); - } else { - // [value, hash, map, map] - sb.emitOp(node, 'SUB'); - } - - // [map] - sb.emitOp(node, 'SETITEM'); - }, - whenFalse: () => { - // [output, hash, map, map, map] - sb.emitOp(node, 'ROT'); - // [value, hash, map, map, map] - sb.emitSysCall(node, 'Neo.Output.GetValue'); - if (!this.add) { - // [value, hash, map, map, map] - sb.emitOp(node, 'NEGATE'); - } - // [map, map] - sb.emitOp(node, 'SETITEM'); - // [map] - sb.emitOp(node, 'DROP'); - }, - }), - ); - }, - whenFalse: () => { - // [output, map, map] - sb.emitOp(node, 'DROP'); - // [map, map] - sb.emitOp(node, 'DROP'); - // [map] - sb.emitOp(node, 'DROP'); - }, - }), - ); - }, - }), - ); - - if (!optionsIn.pushValue) { - // [] - sb.emitOp(node, 'DROP'); - } - } -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/RefundAssetsHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/RefundAssetsHelper.ts deleted file mode 100644 index 225cb2ebfe..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/RefundAssetsHelper.ts +++ /dev/null @@ -1,163 +0,0 @@ -import ts from 'typescript'; -import { ScriptBuilder } from '../../sb'; -import { VisitOptions } from '../../types'; -import { Helper } from '../Helper'; - -// Input: [] -// Output: [] -export class RefundAssetsHelper extends Helper { - public emit(sb: ScriptBuilder, node: ts.Node, optionsIn: VisitOptions): void { - const options = sb.pushValueOptions(optionsIn); - const references = sb.scope.addUnique(); - - // [transaction] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [references] - sb.emitSysCall(node, 'Neo.Transaction.GetReferences'); - // [] - sb.scope.set(sb, node, options, references); - // [transaction] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [inputs] - sb.emitSysCall(node, 'Neo.Transaction.GetInputs'); - // [map, inputs] - sb.emitOp(node, 'NEWMAP'); - // [map] - sb.emitHelper( - node, - options, - sb.helpers.arrReduce({ - withIndex: true, - each: (innerOptions) => { - // [idx, map, input] - sb.emitOp(node, 'ROT'); - // [references, idx, map, input] - sb.scope.get(sb, node, innerOptions, references); - // [idx, references, map, input] - sb.emitOp(node, 'SWAP'); - // [reference, map, input] - sb.emitOp(node, 'PICKITEM'); - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [buffer, map, input] - sb.emitSysCall(node, 'Neo.Output.GetScriptHash'); - // [buffer, buffer, map, input] - sb.emitSysCall(node, 'System.ExecutionEngine.GetExecutingScriptHash'); - // [boolean, map, input] - sb.emitOp(node, 'EQUAL'); - }, - whenTrue: () => { - // [map, input, map] - sb.emitOp(node, 'TUCK'); - // [input, map, map] - sb.emitOp(node, 'SWAP'); - // [hash, map, map] - sb.emitSysCall(node, 'Neo.Input.GetHash'); - // [boolean, hash, map, map] - sb.emitPushBoolean(node, true); - // [map] - sb.emitOp(node, 'SETITEM'); - }, - whenFalse: () => { - // [map] - sb.emitOp(node, 'NIP'); - }, - }), - ); - }, - }), - ); - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [map, map] - sb.emitOp(node, 'DUP'); - // [size, map] - sb.emitOp(node, 'ARRAYSIZE'); - // [1, size, map] - sb.emitPushInt(node, 1); - // [size === 1, map] - sb.emitOp(node, 'NUMEQUAL'); - }, - whenTrue: () => { - // [arr] - sb.emitOp(node, 'KEYS'); - // [0, arr] - sb.emitPushInt(node, 0); - // [buffer] - sb.emitOp(node, 'PICKITEM'); - // [buffer, buffer] - sb.emitOp(node, 'DUP'); - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [isProcessedTransaction, buffer] - sb.emitHelper(node, options, sb.helpers.isProcessedTransaction); - }, - whenTrue: () => { - // [] - sb.emitOp(node, 'DROP'); - // [boolean] - sb.emitPushBoolean(node, false); - }, - whenFalse: () => { - // [transaction] - sb.emitSysCall(node, 'Neo.Blockchain.GetTransaction'); - // [references] - sb.emitSysCall(node, 'Neo.Transaction.GetReferences'); - // [boolean] - sb.emitHelper( - node, - options, - sb.helpers.arrEvery({ - map: () => { - // [buffer] - sb.emitSysCall(node, 'Neo.Output.GetScriptHash'); - // [isCaller] - sb.emitHelper(node, options, sb.helpers.isCaller); - }, - }), - ); - }, - }), - ); - }, - whenFalse: () => { - // [] - sb.emitOp(node, 'DROP'); - // [boolean] - sb.emitPushBoolean(node, false); - }, - }), - ); - - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // do nothing - }, - whenFalse: () => { - // ['InvalidRefundAssetsError'] - sb.emitPushString(node, 'InvalidRefundAssetsError'); - // [value] - sb.emitHelper(node, options, sb.helpers.wrapString); - // [] - sb.emitHelper(node, options, sb.helpers.throw); - }, - }), - ); - - if (optionsIn.pushValue) { - sb.emitHelper(node, options, sb.helpers.wrapUndefined); - } - } -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/SetProcessedTransactionHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/SetProcessedTransactionHelper.ts deleted file mode 100644 index 8b7c902401..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/SetProcessedTransactionHelper.ts +++ /dev/null @@ -1,44 +0,0 @@ -import ts from 'typescript'; -import { ContractPropertyName } from '../../../constants'; -import { Types } from '../../constants'; -import { ScriptBuilder } from '../../sb'; -import { VisitOptions } from '../../types'; -import { Helper } from '../Helper'; - -// Input: [] -// Output: [] -export class SetProcessedTransactionHelper extends Helper { - public emit(sb: ScriptBuilder, node: ts.Node, optionsIn: VisitOptions): void { - const options = sb.pushValueOptions(optionsIn); - - // [val] - sb.emitHelper( - node, - options, - sb.helpers.createStructuredStorage({ - prefix: ContractPropertyName.processedTransactions, - type: Types.SetStorage, - }), - ); - // [transaction, val] - sb.emitSysCall(node, 'System.ExecutionEngine.GetScriptContainer'); - // [hash, val] - sb.emitSysCall(node, 'Neo.Transaction.GetHash'); - // [hashVal, val] - sb.emitHelper(node, options, sb.helpers.wrapBuffer); - // [boolean, hashVal, val] - sb.emitPushBoolean(node, true); - // [val, hashVal, val] - sb.emitHelper(node, options, sb.helpers.wrapBoolean); - // [] - sb.emitHelper( - node, - options, - sb.helpers.setStructuredStorage({ - type: Types.SetStorage, - keyType: undefined, - knownKeyType: Types.Buffer, - }), - ); - } -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/UpgradeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/UpgradeHelper.ts index 1ac351b669..9fe0aa8803 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/UpgradeHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/UpgradeHelper.ts @@ -47,7 +47,7 @@ export class UpgradeHelper extends Helper { // [...args] sb.emitOp(node, 'DROP'); // [contract] - sb.emitSysCall(node, 'Neo.Contract.Migrate'); + sb.emitSysCall(node, 'System.Contract.Update'); // [] sb.emitOp(node, 'DROP'); // [boolean] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/index.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/index.ts index 4a77c6ccc8..c9847b049f 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/index.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/index.ts @@ -1,15 +1,7 @@ export * from './ApplicationMatchesVerificationHelper'; -export * from './CompleteSendHelper'; export * from './DeployHelper'; -export * from './DidReceiveAssetsHelper'; -export * from './DidReceiveNonClaimAssetsHelper'; -export * from './DidSendAssetsHelper'; -export * from './GetOutputAssetValueMapHelper'; export * from './GetSmartContractPropertyHelper'; export * from './HandleNormalHelper'; -export * from './HandleReceiveHelper'; -export * from './HandleSendHelper'; -export * from './HandleSendUnsafeHelper'; export * from './InvocationIsCallerHelper'; export * from './InvokeSmartContractHelper'; export * from './InvokeSmartContractMethodHelper'; @@ -17,8 +9,5 @@ export * from './IsCallerHelper'; export * from './IsClaimedTransactionHelper'; export * from './IsDeployedHelper'; export * from './IsProcessedTransactionHelper'; -export * from './MergeAssetValueMapsHelper'; -export * from './RefundAssetsHelper'; export * from './SetDeployedHelper'; -export * from './SetProcessedTransactionHelper'; export * from './UpgradeHelper'; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/createHelpers.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/createHelpers.ts index 7940ccc2db..16d89a791d 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/createHelpers.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/createHelpers.ts @@ -53,21 +53,12 @@ import { } from './completionRecord'; import { ApplicationMatchesVerificationHelper, - CompleteSendHelper, DeployHelper, DeployHelperOptions, - DidReceiveAssetsHelper, - DidReceiveNonClaimAssetsHelper, - DidSendAssetsHelper, - GetOutputAssetValueMapHelper, GetSmartContractPropertyHelper, GetSmartContractPropertyHelperOptions, HandleNormalHelper, HandleNormalHelperOptions, - HandleReceiveHelper, - HandleSendHelper, - HandleSendHelperOptions, - HandleSendUnsafeHelper, InvocationIsCallerHelper, InvokeSmartContractHelper, InvokeSmartContractHelperOptions, @@ -77,15 +68,10 @@ import { IsClaimedTransactionHelper, IsDeployedHelper, IsProcessedTransactionHelper, - MergeAssetValueMapsHelper, - MergeAssetValueMapsHelperOptions, - RefundAssetsHelper, SetDeployedHelper, - SetProcessedTransactionHelper, UpgradeHelper, UpgradeHelperOptions, } from './contract'; -import { HandleSendUnsafeReceiveHelperBaseOptions } from './contract/HandleSendUnsafeReceiveHelperBase'; import { ThrowTypeErrorHelper } from './error'; import { ArgumentsHelper, @@ -142,6 +128,7 @@ import { RawEnumeratorFindHelper, RawEnumeratorFindHelperOptions, RawEnumeratorForEachFuncHelper, + RawEnumeratorForEachFuncHelperOptions, RawEnumeratorForEachHelper, RawEnumeratorForEachHelperOptions, RawEnumeratorReduceHelper, @@ -158,6 +145,7 @@ import { RawIteratorForEachFuncBaseHelperOptions, RawIteratorForEachFuncHelper, RawIteratorForEachHelper, + RawIteratorForEachHelperFuncOptions, RawIteratorForEachHelperOptions, RawIteratorForEachKeyHelper, RawIteratorForEachKeyHelperOptions, @@ -205,6 +193,7 @@ import { LessThanHelper, LessThanHelperOptions, } from './relational'; +import { DupScopeHelper, PopScopeHelper, PushScopeHelper } from './scope'; import { Case, CaseHelper, @@ -314,7 +303,6 @@ import { IsBufferHelper, IsErrorHelper, IsForwardValueHelper, - IsInputHelper, IsIterableHelper, IsIterableIteratorHelper, IsIteratorResultHelper, @@ -324,7 +312,6 @@ import { IsNullOrUndefinedHelper, IsNumberHelper, IsObjectHelper, - IsOutputHelper, IsSetHelper, IsSetStorageHelper, IsStringHelper, @@ -363,14 +350,12 @@ import { UnwrapBufferHelper, UnwrapErrorHelper, UnwrapForwardValueHelper, - UnwrapInputHelper, UnwrapIterableIteratorHelper, UnwrapIteratorResultHelper, UnwrapMapHelper, UnwrapMapStorageHelper, UnwrapNumberHelper, UnwrapObjectHelper, - UnwrapOutputHelper, UnwrapSetHelper, UnwrapSetStorageHelper, UnwrapStringHelper, @@ -389,7 +374,6 @@ import { WrapBufferHelper, WrapErrorHelper, WrapForwardValueHelper, - WrapInputHelper, WrapIterableIteratorHelper, WrapIteratorResultHelper, WrapMapHelper, @@ -397,7 +381,6 @@ import { WrapNullHelper, WrapNumberHelper, WrapObjectHelper, - WrapOutputHelper, WrapSetHelper, WrapSetStorageHelper, WrapStringHelper, @@ -409,18 +392,11 @@ import { WrapValRecursiveHelper, WrapValRecursiveHelperOptions, } from './types'; -import { IsAccountHelper, UnwrapAccountHelper, WrapAccountHelper } from './types/account'; -import { IsAssetHelper, UnwrapAssetHelper, WrapAssetHelper } from './types/asset'; import { IsBlockHelper, UnwrapBlockHelper, WrapBlockHelper } from './types/block'; import { IsContractHelper, UnwrapContractHelper, WrapContractHelper } from './types/contract'; -import { IsHeaderHelper, UnwrapHeaderHelper, WrapHeaderHelper } from './types/header'; export interface Helpers { readonly mutableCache: { [K in string]?: Helper }; - // account - readonly isAccount: IsAccountHelper; - readonly wrapAccount: WrapAccountHelper; - readonly unwrapAccount: UnwrapAccountHelper; // arr readonly arrClone: ArrCloneHelper; @@ -443,11 +419,6 @@ export interface Helpers { readonly arrToString: (options: ArrToStringHelperOptions) => ArrToStringHelper; readonly extendArr: ExtendArrHelper; - // asset - readonly isAsset: IsAssetHelper; - readonly wrapAsset: WrapAssetHelper; - readonly unwrapAsset: UnwrapAssetHelper; - // bind readonly arrayBinding: (options: ArrayBindingHelperOptions) => ArrayBindingHelper; readonly objectBinding: (options: ObjectBindingHelperOptions) => ObjectBindingHelper; @@ -468,31 +439,20 @@ export interface Helpers { readonly createClass: (options: CreateClassHelperOptions) => CreateClassHelper; // contract - readonly didReceiveAssets: DidReceiveAssetsHelper; - readonly didReceiveNonClaimAssets: DidReceiveNonClaimAssetsHelper; - readonly didSendAssets: DidSendAssetsHelper; readonly invokeSmartContract: (options: InvokeSmartContractHelperOptions) => InvokeSmartContractHelper; readonly invokeSmartContractMethod: ( options: InvokeSmartContractMethodHelperOptions, ) => InvokeSmartContractMethodHelper; - readonly getOutputAssetValueMap: GetOutputAssetValueMapHelper; readonly invocationIsCaller: InvocationIsCallerHelper; readonly isCaller: IsCallerHelper; readonly isProcessedTransaction: IsProcessedTransactionHelper; - readonly refundAssets: RefundAssetsHelper; - readonly mergeAssetValueMaps: (options: MergeAssetValueMapsHelperOptions) => MergeAssetValueMapsHelper; readonly getSmartContractProperty: (options: GetSmartContractPropertyHelperOptions) => GetSmartContractPropertyHelper; readonly isDeployed: IsDeployedHelper; readonly setDeployed: SetDeployedHelper; readonly isClaimedTransaction: IsClaimedTransactionHelper; - readonly setProcessedTransaction: SetProcessedTransactionHelper; - readonly completeSend: CompleteSendHelper; readonly deploy: (options: DeployHelperOptions) => DeployHelper; readonly upgrade: (options: UpgradeHelperOptions) => UpgradeHelper; readonly handleNormal: (options: HandleNormalHelperOptions) => HandleNormalHelper; - readonly handleSend: (options: HandleSendHelperOptions) => HandleSendHelper; - readonly handleReceive: (options: HandleSendUnsafeReceiveHelperBaseOptions) => HandleReceiveHelper; - readonly handleSendUnsafe: (options: HandleSendUnsafeReceiveHelperBaseOptions) => HandleSendUnsafeHelper; readonly applicationMatchesVerification: ApplicationMatchesVerificationHelper; // types/contract @@ -514,6 +474,10 @@ export interface Helpers { readonly lessThan: (options: LessThanHelperOptions) => LessThanHelper; readonly processStatements: (options: ProcessStatementsHelperOptions) => ProcessStatementsHelper; + readonly dupScope: DupScopeHelper; + readonly popScope: PopScopeHelper; + readonly pushScope: PushScopeHelper; + readonly args: ArgumentsHelper; readonly bindFunctionThis: (options: BindFunctionThisHelperOptions) => BindFunctionThisHelper; readonly call: CallHelper; @@ -605,11 +569,6 @@ export interface Helpers { readonly findObjectProperty: (options: FindObjectPropertyHelperOptions) => FindObjectPropertyHelper; readonly findObjectPropertyBase: (options: FindObjectPropertyHelperBaseOptions) => FindObjectPropertyHelperBase; - // header - readonly isHeader: IsHeaderHelper; - readonly wrapHeader: WrapHeaderHelper; - readonly unwrapHeader: UnwrapHeaderHelper; - // iterableIterator readonly iterableIteratorForEach: (options: IterableIteratorForEachHelperOptions) => IterableIteratorForEachHelper; readonly iterableIteratorReduce: (options: IterableIteratorReduceHelperOptions) => IterableIteratorReduceHelper; @@ -631,11 +590,11 @@ export interface Helpers { readonly rawIteratorForEach: (options: RawIteratorForEachHelperOptions) => RawIteratorForEachHelper; readonly rawIteratorForEachKey: (options: RawIteratorForEachKeyHelperOptions) => RawIteratorForEachKeyHelper; readonly rawIteratorForEachBase: (options: RawIteratorForEachBaseHelperOptions) => RawIteratorForEachBaseHelper; - readonly rawIteratorForEachFunc: RawIteratorForEachFuncHelper; + readonly rawIteratorForEachFunc: (options: RawIteratorForEachHelperFuncOptions) => RawIteratorForEachFuncHelper; readonly rawIteratorForEachFuncBase: ( options: RawIteratorForEachFuncBaseHelperOptions, ) => RawIteratorForEachFuncBaseHelper; - readonly rawEnumeratorForEachFunc: RawEnumeratorForEachFuncHelper; + readonly rawEnumeratorForEachFunc: (options: RawEnumeratorForEachFuncHelperOptions) => RawEnumeratorForEachFuncHelper; readonly rawEnumeratorForEach: (options: RawEnumeratorForEachHelperOptions) => RawEnumeratorForEachHelper; readonly rawEnumeratorFilter: (options: RawEnumeratorFilterHelperOptions) => RawEnumeratorFilterHelper; readonly rawEnumeratorFind: (options: RawEnumeratorFindHelperOptions) => RawEnumeratorFindHelper; @@ -775,11 +734,6 @@ export interface Helpers { readonly unwrapForwardValue: UnwrapForwardValueHelper; readonly isForwardValue: IsForwardValueHelper; - // types/input - readonly wrapInput: WrapInputHelper; - readonly unwrapInput: UnwrapInputHelper; - readonly isInput: IsInputHelper; - // types/iterable readonly isIterable: IsIterableHelper; @@ -803,11 +757,6 @@ export interface Helpers { readonly unwrapMapStorage: UnwrapMapStorageHelper; readonly isMapStorage: IsMapStorageHelper; - // types/output - readonly wrapOutput: WrapOutputHelper; - readonly unwrapOutput: UnwrapOutputHelper; - readonly isOutput: IsOutputHelper; - // types/set readonly wrapSet: WrapSetHelper; readonly unwrapSet: UnwrapSetHelper; @@ -870,11 +819,6 @@ export const createHelpers = (prevHelpers?: Helpers): Helpers => { return { mutableCache, - // account - isAccount: new IsAccountHelper(), - wrapAccount: new WrapAccountHelper(), - unwrapAccount: new UnwrapAccountHelper(), - // arr arrClone: new ArrCloneHelper(), arrConcat: new ArrConcatHelper(), @@ -896,11 +840,6 @@ export const createHelpers = (prevHelpers?: Helpers): Helpers => { arrToString: (options) => new ArrToStringHelper(options), extendArr: new ExtendArrHelper(), - // asset - isAsset: new IsAssetHelper(), - wrapAsset: new WrapAssetHelper(), - unwrapAsset: new UnwrapAssetHelper(), - // bind arrayBinding: (options) => new ArrayBindingHelper(options), objectBinding: (options) => new ObjectBindingHelper(options), @@ -921,29 +860,18 @@ export const createHelpers = (prevHelpers?: Helpers): Helpers => { createClass: (options) => new CreateClassHelper(options), // contract - didReceiveAssets: new DidReceiveAssetsHelper(), - didReceiveNonClaimAssets: new DidReceiveNonClaimAssetsHelper(), - didSendAssets: new DidSendAssetsHelper(), invokeSmartContract: (options) => new InvokeSmartContractHelper(options), invokeSmartContractMethod: (options) => new InvokeSmartContractMethodHelper(options), - getOutputAssetValueMap: new GetOutputAssetValueMapHelper(), invocationIsCaller: new InvocationIsCallerHelper(), isCaller: new IsCallerHelper(), isProcessedTransaction: new IsProcessedTransactionHelper(), - refundAssets: new RefundAssetsHelper(), - mergeAssetValueMaps: (options) => new MergeAssetValueMapsHelper(options), getSmartContractProperty: (options) => new GetSmartContractPropertyHelper(options), isDeployed: new IsDeployedHelper(), setDeployed: new SetDeployedHelper(), isClaimedTransaction: new IsClaimedTransactionHelper(), - setProcessedTransaction: new SetProcessedTransactionHelper(), - completeSend: new CompleteSendHelper(), deploy: (options) => new DeployHelper(options), upgrade: (options) => new UpgradeHelper(options), handleNormal: memoizedUnique(HandleNormalHelper), - handleSend: (options) => new HandleSendHelper(options), - handleReceive: (options) => new HandleReceiveHelper(options), - handleSendUnsafe: (options) => new HandleSendUnsafeHelper(options), applicationMatchesVerification: new ApplicationMatchesVerificationHelper(), // types/contract @@ -965,6 +893,10 @@ export const createHelpers = (prevHelpers?: Helpers): Helpers => { lessThan: (options) => new LessThanHelper(options), processStatements: (options) => new ProcessStatementsHelper(options), + dupScope: new DupScopeHelper(), + popScope: new PopScopeHelper(), + pushScope: new PushScopeHelper(), + args: new ArgumentsHelper(), bindFunctionThis: (options) => new BindFunctionThisHelper(options), call: new CallHelper(), @@ -1052,11 +984,6 @@ export const createHelpers = (prevHelpers?: Helpers): Helpers => { findObjectProperty: (options) => new FindObjectPropertyHelper(options), findObjectPropertyBase: (options) => new FindObjectPropertyHelperBase(options), - // header - isHeader: new IsHeaderHelper(), - wrapHeader: new WrapHeaderHelper(), - unwrapHeader: new UnwrapHeaderHelper(), - // iterableIterator iterableIteratorForEach: (options) => new IterableIteratorForEachHelper(options), iterableIteratorReduce: (options) => new IterableIteratorReduceHelper(options), @@ -1072,9 +999,9 @@ export const createHelpers = (prevHelpers?: Helpers): Helpers => { rawIteratorForEach: (options) => new RawIteratorForEachHelper(options), rawIteratorForEachKey: (options) => new RawIteratorForEachKeyHelper(options), rawIteratorForEachBase: (options) => new RawIteratorForEachBaseHelper(options), - rawIteratorForEachFunc: new RawIteratorForEachFuncHelper(), + rawIteratorForEachFunc: (options) => new RawIteratorForEachFuncHelper(options), rawIteratorForEachFuncBase: (options) => new RawIteratorForEachFuncBaseHelper(options), - rawEnumeratorForEachFunc: new RawEnumeratorForEachFuncHelper(), + rawEnumeratorForEachFunc: (options) => new RawEnumeratorForEachFuncHelper(options), rawEnumeratorForEach: (options) => new RawEnumeratorForEachHelper(options), rawEnumeratorFilter: (options) => new RawEnumeratorFilterHelper(options), rawEnumeratorFind: (options) => new RawEnumeratorFindHelper(options), @@ -1191,11 +1118,6 @@ export const createHelpers = (prevHelpers?: Helpers): Helpers => { unwrapForwardValue: new UnwrapForwardValueHelper(), isForwardValue: new IsForwardValueHelper(), - // types/input - wrapInput: new WrapInputHelper(), - unwrapInput: new UnwrapInputHelper(), - isInput: new IsInputHelper(), - // types/iterable isIterable: new IsIterableHelper(), @@ -1219,11 +1141,6 @@ export const createHelpers = (prevHelpers?: Helpers): Helpers => { unwrapMapStorage: new UnwrapMapStorageHelper(), isMapStorage: new IsMapStorageHelper(), - // types/output - wrapOutput: new WrapOutputHelper(), - unwrapOutput: new UnwrapOutputHelper(), - isOutput: new IsOutputHelper(), - // types/set wrapSet: new WrapSetHelper(), unwrapSet: new UnwrapSetHelper(), diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/function/ArgumentsHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/function/ArgumentsHelper.ts index 3d18590017..16d668ce83 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/function/ArgumentsHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/function/ArgumentsHelper.ts @@ -113,6 +113,7 @@ export class ArgumentsHelper extends Helper { // [size, func, this, func] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [3, size, func, this, func] sb.emitPushInt(node, 3); // [hasThis, func, this, func] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/function/CallHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/function/CallHelper.ts index eb51170c49..392d9f0d97 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/function/CallHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/function/CallHelper.ts @@ -39,7 +39,7 @@ export class CallHelper extends Helper { sb.helpers.if({ condition: () => { // [size, [scopes, this], func] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [3, size, [scopes, this], func] sb.emitPushInt(node, 3); // [size === 3, [scopes, this], func] @@ -65,7 +65,7 @@ export class CallHelper extends Helper { ); // [func] - sb.emitOp(node, 'TOALTSTACK'); + sb.emitHelper(node, options, sb.helpers.pushScope); // Push the target on the stack // [0, func] @@ -77,7 +77,7 @@ export class CallHelper extends Helper { sb.emitCall(node); // Remove scope - sb.emitOp(node, 'FROMALTSTACK'); + sb.emitHelper(node, options, sb.helpers.popScope); sb.emitOp(node, 'DROP'); sb.emitHelper(node, optionsIn, sb.helpers.handleCompletion); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/function/CallLikeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/function/CallLikeHelper.ts index ef782e932e..fd6b037a2a 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/function/CallLikeHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/function/CallLikeHelper.ts @@ -347,14 +347,9 @@ export class CallLikeHelper extends Helper { // [default, argsarr] @@ -107,11 +107,11 @@ export class ParametersHelper extends Helper { // [argsarr, argsarr] sb.emitOp(param, 'DUP'); // [size, argsarr] - sb.emitOp(param, 'ARRAYSIZE'); + sb.emitOp(param, 'SIZE'); // [idx, size, argsarr] sb.emitPushInt(param, idx); // [size <= idx, argsarr] - sb.emitOp(param, 'LTE'); + sb.emitOp(param, 'LE'); }, whenTrue: () => { // [undefinedVal, argsarr] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/global/CreateGlobalObjectHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/global/CreateGlobalObjectHelper.ts index a7c4ec712a..653dedfd85 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/global/CreateGlobalObjectHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/global/CreateGlobalObjectHelper.ts @@ -37,7 +37,7 @@ export class CreateGlobalObjectHelper extends Helper { // [number, map, map] sb.emitPushInt(node, GlobalProperty.CallingScriptHash); // [buffer, number, map, map] - sb.emitSysCall(node, 'System.ExecutionEngine.GetCallingScriptHash'); + sb.emitSysCall(node, 'System.Runtime.GetCallingScriptHash'); // [map] sb.emitOp(node, 'SETITEM'); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/global/GetArgumentHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/global/GetArgumentHelper.ts index a3eede2b95..0114324789 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/global/GetArgumentHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/global/GetArgumentHelper.ts @@ -13,7 +13,7 @@ export class GetArgumentHelper extends Helper { return; } - // [argv] + // [argv, number] sb.emitHelper(node, options, sb.helpers.getGlobalProperty({ property: GlobalProperty.Arguments })); // [number, argv] sb.emitOp(node, 'SWAP'); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterableIterator/CreateEnumeratorIterableIteratorHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterableIterator/CreateEnumeratorIterableIteratorHelper.ts index 4426184bd2..17fba6b66d 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterableIterator/CreateEnumeratorIterableIteratorHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterableIterator/CreateEnumeratorIterableIteratorHelper.ts @@ -4,6 +4,7 @@ import { VisitOptions } from '../../types'; import { Helper } from '../Helper'; export interface CreateEnumeratorIterableIteratorHelperOptions { + readonly deserializeKey?: boolean; readonly mapValue?: (options: VisitOptions) => void; } @@ -14,11 +15,13 @@ const doNothing = () => { // Input: [enumerator] // Output: [val] export class CreateEnumeratorIterableIteratorHelper extends Helper { + private readonly deserializeKey: boolean; private readonly mapValue: (options: VisitOptions) => void; public constructor(options: CreateEnumeratorIterableIteratorHelperOptions) { super(); this.mapValue = options.mapValue === undefined ? doNothing : options.mapValue; + this.deserializeKey = options.deserializeKey ?? false; } public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { @@ -28,7 +31,11 @@ export class CreateEnumeratorIterableIteratorHelper extends Helper { sb.helpers.createIterableIteratorBase({ handleNext: (innerOptions) => { // [value] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); + if (this.deserializeKey) { + // [value] + sb.emitSysCall(node, 'System.Binary.Deserialize'); + } // [val] this.mapValue(innerOptions); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterableIterator/CreateIterableIteratorBaseHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterableIterator/CreateIterableIteratorBaseHelper.ts index b6beaab85b..3685d49138 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterableIterator/CreateIterableIteratorBaseHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterableIterator/CreateIterableIteratorBaseHelper.ts @@ -103,7 +103,7 @@ export class CreateIterableIteratorBaseHelper extends Helper { // [iterator, iterator] sb.emitOp(node, 'DUP'); // [boolean, iterator] - sb.emitSysCall(node, 'Neo.Enumerator.Next'); + sb.emitSysCall(node, 'System.Enumerator.Next'); }, whenTrue: () => { sb.emitHelper( @@ -167,7 +167,7 @@ export class CreateIterableIteratorBaseHelper extends Helper { // [iterator, iterator] sb.emitOp(node, 'DUP'); // [boolean, iterator] - sb.emitSysCall(node, 'Neo.Enumerator.Next'); + sb.emitSysCall(node, 'System.Enumerator.Next'); }, whenTrue: () => { // [valueVal] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterableIterator/CreateIteratorIterableIteratorHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterableIterator/CreateIteratorIterableIteratorHelper.ts index 8a2fce7c8f..a1ea67279f 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterableIterator/CreateIteratorIterableIteratorHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterableIterator/CreateIteratorIterableIteratorHelper.ts @@ -4,6 +4,7 @@ import { VisitOptions } from '../../types'; import { Helper } from '../Helper'; export interface CreateIteratorIterableIteratorHelperOptions { + readonly deserializeKey?: boolean; readonly mapKey?: (options: VisitOptions) => void; readonly mapValue?: (options: VisitOptions) => void; } @@ -15,11 +16,13 @@ const doNothing = () => { // Input: [iterator] // Output: [val] export class CreateIteratorIterableIteratorHelper extends Helper { + private readonly deserializeKey: boolean; private readonly mapKey: (options: VisitOptions) => void; private readonly mapValue: (options: VisitOptions) => void; public constructor(options: CreateIteratorIterableIteratorHelperOptions) { super(); + this.deserializeKey = options.deserializeKey ?? false; this.mapKey = options.mapKey === undefined ? doNothing : options.mapKey; this.mapValue = options.mapValue === undefined ? doNothing : options.mapValue; } @@ -33,13 +36,17 @@ export class CreateIteratorIterableIteratorHelper extends Helper { // [iterator, iterator] sb.emitOp(node, 'DUP'); // [value, iterator] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [valueVal, iterator] this.mapValue(innerOptions); // [iterator, valueVal] sb.emitOp(node, 'SWAP'); // [key, valueVal] - sb.emitSysCall(node, 'Neo.Iterator.Key'); + sb.emitSysCall(node, 'System.Iterator.Key'); + if (this.deserializeKey) { + // [key, valueVal] + sb.emitSysCall(node, 'System.Binary.Deserialize'); + } // [keyVal, valueVal] this.mapKey(innerOptions); // [number, keyVal, valueVal] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorEveryHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorEveryHelper.ts index d8e899313e..553b160042 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorEveryHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorEveryHelper.ts @@ -24,7 +24,7 @@ export class RawEnumeratorEveryHelper extends Helper { sb.helpers.rawIteratorEveryBase({ each: (innerOptions) => { // [value] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [result] this.each(innerOptions); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorFindHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorFindHelper.ts index 5e0219a4bf..4714dbe01a 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorFindHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorFindHelper.ts @@ -36,7 +36,7 @@ export class RawEnumeratorFindHelper extends Helper { sb.helpers.if({ condition: () => { // [size, arr] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [0, size, arr] sb.emitPushInt(node, 0); // [size == 0, arr] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorForEachFuncHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorForEachFuncHelper.ts index f195ec9ece..f238b4d1a3 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorForEachFuncHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorForEachFuncHelper.ts @@ -3,9 +3,20 @@ import { ScriptBuilder } from '../../sb'; import { VisitOptions } from '../../types'; import { Helper } from '../Helper'; +export interface RawEnumeratorForEachFuncHelperOptions { + readonly deserializeKey?: boolean; +} + // Input: [objectVal, enumerator] // Output: [] export class RawEnumeratorForEachFuncHelper extends Helper { + private readonly deserializeKey: boolean; + + public constructor(options: RawEnumeratorForEachFuncHelperOptions) { + super(); + this.deserializeKey = options.deserializeKey ?? false; + } + public emit(sb: ScriptBuilder, node: ts.Node, optionsIn: VisitOptions): void { const options = sb.pushValueOptions(optionsIn); @@ -21,13 +32,17 @@ export class RawEnumeratorForEachFuncHelper extends Helper { // [enumerator, enumerator, callable] sb.emitOp(node, 'DUP'); // [boolean, enumerator, callable] - sb.emitSysCall(node, 'Neo.Enumerator.Next'); + sb.emitSysCall(node, 'System.Enumerator.Next'); }, each: (innerOptions) => { // [enumerator, enumerator, callable] sb.emitOp(node, 'DUP'); // [key, enumerator, callable] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); + if (this.deserializeKey) { + // [key, enumerator, callable] + sb.emitSysCall(node, 'System.Binary.Deserialize'); + } // [1, value, enumerator, callable] sb.emitPushInt(node, 1); // [argsarr, enumerator, callable] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorForEachHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorForEachHelper.ts index b4756e3037..98a7ccc56b 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorForEachHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorForEachHelper.ts @@ -26,7 +26,7 @@ export class RawEnumeratorForEachHelper extends Helper { sb.helpers.rawIteratorForEachBase({ each: (innerOptions) => { // [val] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [] this.each(sb.noPushValueOptions(innerOptions)); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorReduceHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorReduceHelper.ts index a64174e9c0..4244b30148 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorReduceHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorReduceHelper.ts @@ -26,7 +26,7 @@ export class RawEnumeratorReduceHelper extends Helper { // [enumerator, accum] sb.emitOp(node, 'SWAP'); // [value, accum] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [accum, value] sb.emitOp(node, 'SWAP'); // [accum] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorSomeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorSomeHelper.ts index f537158c0e..930e7aa9c5 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorSomeHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawEnumeratorSomeHelper.ts @@ -24,7 +24,7 @@ export class RawEnumeratorSomeHelper extends Helper { sb.helpers.rawIteratorSomeBase({ each: (innerOptions) => { // [value] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [result] this.each(innerOptions); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorEveryBaseHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorEveryBaseHelper.ts index 731f4cdd56..7b8b8e5df9 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorEveryBaseHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorEveryBaseHelper.ts @@ -36,7 +36,7 @@ export class RawIteratorEveryBaseHelper extends Helper { // [iterator, result, result, iterator] sb.emitOp(node, 'SWAP'); // [boolean, result, result, iterator] - sb.emitSysCall(node, 'Neo.Enumerator.Next'); + sb.emitSysCall(node, 'System.Enumerator.Next'); // [boolean, result, iterator] sb.emitOp(node, 'BOOLAND'); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorEveryHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorEveryHelper.ts index a0aeb40a9b..b40a13bbba 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorEveryHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorEveryHelper.ts @@ -26,11 +26,11 @@ export class RawIteratorEveryHelper extends Helper { // [iterator, iterator] sb.emitOp(node, 'DUP'); // [value, iterator] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [iterator, value] sb.emitOp(node, 'SWAP'); // [key, value] - sb.emitSysCall(node, 'Neo.Iterator.Key'); + sb.emitSysCall(node, 'System.Iterator.Key'); // [result] this.each(innerOptions); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachBaseHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachBaseHelper.ts index 8334b4237b..19d07e3bdb 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachBaseHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachBaseHelper.ts @@ -28,7 +28,7 @@ export class RawIteratorForEachBaseHelper extends Helper { // [iterator, iterator] sb.emitOp(node, 'DUP'); // [boolean, iterator] - sb.emitSysCall(node, 'Neo.Enumerator.Next'); + sb.emitSysCall(node, 'System.Enumerator.Next'); }, each: (innerOptions) => { // [iterator, iterator] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachFuncBaseHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachFuncBaseHelper.ts index 2b5530d8ee..52236f42b9 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachFuncBaseHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachFuncBaseHelper.ts @@ -35,7 +35,7 @@ export class RawIteratorForEachFuncBaseHelper extends Helper { // [iterator, iterator, callable] sb.emitOp(node, 'DUP'); // [boolean, iterator, callable] - sb.emitSysCall(node, 'Neo.Enumerator.Next'); + sb.emitSysCall(node, 'System.Enumerator.Next'); }, each: (innerOptionsIn) => { const innerOptions = sb.pushValueOptions(innerOptionsIn); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachFuncHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachFuncHelper.ts index 631189d257..abfcde1a06 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachFuncHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachFuncHelper.ts @@ -3,9 +3,20 @@ import { ScriptBuilder } from '../../sb'; import { VisitOptions } from '../../types'; import { Helper } from '../Helper'; +export interface RawIteratorForEachHelperFuncOptions { + readonly deserializeKey?: boolean; +} + // Input: [objectVal, iterator] // Output: [] export class RawIteratorForEachFuncHelper extends Helper { + private readonly deserializeKey: boolean; + + public constructor(options: RawIteratorForEachHelperFuncOptions) { + super(); + this.deserializeKey = options.deserializeKey ?? false; + } + public emit(sb: ScriptBuilder, node: ts.Node, optionsIn: VisitOptions): void { const options = sb.pushValueOptions(optionsIn); @@ -15,11 +26,15 @@ export class RawIteratorForEachFuncHelper extends Helper { sb.helpers.rawIteratorForEachFuncBase({ handleNext: () => { // [key, iterator, callable] - sb.emitSysCall(node, 'Neo.Iterator.Key'); + sb.emitSysCall(node, 'System.Iterator.Key'); + if (this.deserializeKey) { + // [key, iterator, callable] + sb.emitSysCall(node, 'System.Binary.Deserialize'); + } // [iterator, key, iterator, callable] sb.emitOp(node, 'OVER'); // [value, key, iterator, callable] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [2, value, key, iterator, callable] sb.emitPushInt(node, 2); // [argsarr, iterator, callable] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachHelper.ts index 9b576f31c4..2518945b52 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachHelper.ts @@ -4,17 +4,20 @@ import { VisitOptions } from '../../types'; import { Helper } from '../Helper'; export interface RawIteratorForEachHelperOptions { + readonly deserializeKey?: boolean; readonly each: (options: VisitOptions) => void; } // Input: [iterator] // Output: [] export class RawIteratorForEachHelper extends Helper { + private readonly deserializeKey: boolean; private readonly each: (options: VisitOptions) => void; public constructor(options: RawIteratorForEachHelperOptions) { super(); this.each = options.each; + this.deserializeKey = options.deserializeKey ?? false; } public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { @@ -24,11 +27,15 @@ export class RawIteratorForEachHelper extends Helper { sb.helpers.rawIteratorForEachBase({ each: (innerOptions) => { // [val] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [iterator, val] sb.emitOp(node, 'OVER'); // [key, val] - sb.emitSysCall(node, 'Neo.Iterator.Key'); + sb.emitSysCall(node, 'System.Iterator.Key'); + if (this.deserializeKey) { + // [key, val] + sb.emitSysCall(node, 'System.Binary.Deserialize'); + } // [] this.each(innerOptions); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachKeyHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachKeyHelper.ts index 8a9ea2123e..bfe3a9cbdf 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachKeyHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorForEachKeyHelper.ts @@ -4,17 +4,20 @@ import { VisitOptions } from '../../types'; import { Helper } from '../Helper'; export interface RawIteratorForEachKeyHelperOptions { + readonly deserializeKey?: boolean; readonly each: (options: VisitOptions) => void; } // Input: [iterator] // Output: [] export class RawIteratorForEachKeyHelper extends Helper { + private readonly deserializeKey: boolean; private readonly each: (options: VisitOptions) => void; public constructor(options: RawIteratorForEachKeyHelperOptions) { super(); this.each = options.each; + this.deserializeKey = options.deserializeKey ?? false; } public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { @@ -24,7 +27,11 @@ export class RawIteratorForEachKeyHelper extends Helper { sb.helpers.rawIteratorForEachBase({ each: (innerOptions) => { // [key] - sb.emitSysCall(node, 'Neo.Iterator.Key'); + sb.emitSysCall(node, 'System.Iterator.Key'); + if (this.deserializeKey) { + // [key] + sb.emitSysCall(node, 'System.Binary.Deserialize'); + } // [] this.each(innerOptions); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorReduceBaseHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorReduceBaseHelper.ts index d862bddcb1..2aff489825 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorReduceBaseHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorReduceBaseHelper.ts @@ -28,7 +28,7 @@ export class RawIteratorReduceBaseHelper extends Helper { // [iterator, accum, iterator] sb.emitOp(node, 'OVER'); // [boolean, accum, iterator] - sb.emitSysCall(node, 'Neo.Enumerator.Next'); + sb.emitSysCall(node, 'System.Enumerator.Next'); }, each: (innerOptions) => { // [iterator, accum, iterator] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorReduceHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorReduceHelper.ts index 67c9802f7b..ec18e9c9ed 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorReduceHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorReduceHelper.ts @@ -4,17 +4,20 @@ import { VisitOptions } from '../../types'; import { Helper } from '../Helper'; export interface RawIteratorReduceHelperOptions { + readonly deserializeKey?: boolean; readonly each: (options: VisitOptions) => void; } // Input: [accum, iterator] // Output: [accum] export class RawIteratorReduceHelper extends Helper { + private readonly deserializeKey: boolean; private readonly each: (options: VisitOptions) => void; public constructor(options: RawIteratorReduceHelperOptions) { super(); this.each = options.each; + this.deserializeKey = options.deserializeKey ?? false; } public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { @@ -26,11 +29,15 @@ export class RawIteratorReduceHelper extends Helper { // [iterator, accum, iterator] sb.emitOp(node, 'OVER'); // [value, accum, iterator] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [iterator, value, accum] sb.emitOp(node, 'ROT'); // [key, value, accum] - sb.emitSysCall(node, 'Neo.Iterator.Key'); + sb.emitSysCall(node, 'System.Iterator.Key'); + if (this.deserializeKey) { + // [key, value, accum] + sb.emitSysCall(node, 'System.Binary.Deserialize'); + } // [accum, key, value] sb.emitOp(node, 'ROT'); // [accum] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorSomeBaseHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorSomeBaseHelper.ts index 4a477ecaa7..5412ce1e2a 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorSomeBaseHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorSomeBaseHelper.ts @@ -38,7 +38,7 @@ export class RawIteratorSomeBaseHelper extends Helper { // [iterator, !result, result, iterator] sb.emitOp(node, 'SWAP'); // [boolean, !result, result, iterator] - sb.emitSysCall(node, 'Neo.Enumerator.Next'); + sb.emitSysCall(node, 'System.Enumerator.Next'); // [boolean, result, iterator] sb.emitOp(node, 'BOOLAND'); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorSomeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorSomeHelper.ts index 6abb17771e..245cacdd92 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorSomeHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/iterator/RawIteratorSomeHelper.ts @@ -26,11 +26,11 @@ export class RawIteratorSomeHelper extends Helper { // [iterator, iterator] sb.emitOp(node, 'DUP'); // [value, iterator] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [iterator, value] sb.emitOp(node, 'SWAP'); // [key, value] - sb.emitSysCall(node, 'Neo.Iterator.Key'); + sb.emitSysCall(node, 'System.Iterator.Key'); // [result] this.each(innerOptions); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapEveryHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapEveryHelper.ts index 295d18f2f2..6c25f9f4b8 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapEveryHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapEveryHelper.ts @@ -19,7 +19,7 @@ export class MapEveryHelper extends Helper { public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [accum] sb.emitHelper( node, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapFilterHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapFilterHelper.ts index dc2ce7189b..893b53bb8f 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapFilterHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapFilterHelper.ts @@ -24,7 +24,7 @@ export class MapFilterHelper extends Helper { return; } // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [accum, iterator] sb.emitOp(node, 'NEWMAP'); // [accum] @@ -56,10 +56,12 @@ export class MapFilterHelper extends Helper { whenTrue: () => { // [accum, val, key] sb.emitOp(node, 'ROT'); - // [3, accum, val, key] - sb.emitPushInt(node, 3); + // [accum, accum, val, key] + sb.emitOp(node, 'DUP'); + // [key, val, accum, accum] + sb.emitOp(node, 'REVERSE4'); // [accum, val, key, accum] - sb.emitOp(node, 'XTUCK'); + sb.emitOp(node, 'REVERSE3'); // [key, accum, val, accum] sb.emitOp(node, 'ROT'); // [val, key, accum, accum] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapForEachHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapForEachHelper.ts index 74ea79a31a..2d4c0b95bc 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapForEachHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapForEachHelper.ts @@ -19,7 +19,7 @@ export class MapForEachHelper extends Helper { public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [] sb.emitHelper( node, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapMapHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapMapHelper.ts index 8bd6e51233..fdc6af8f98 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapMapHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapMapHelper.ts @@ -19,7 +19,7 @@ export class MapMapHelper extends Helper { public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [accum, iterator] sb.emitOp(node, 'NEWMAP'); // [accum] @@ -28,10 +28,12 @@ export class MapMapHelper extends Helper { options, sb.helpers.rawIteratorReduce({ each: (innerOptions) => { - // [3, accum, key, val] - sb.emitPushInt(node, 3); + // [accum, accum, key, val] + sb.emitOp(node, 'DUP'); + // [val, key, accum, accum] + sb.emitOp(node, 'REVERSE4'); // [accum, key, val, accum] - sb.emitOp(node, 'XTUCK'); + sb.emitOp(node, 'REVERSE3'); // [val, accum, key, accum] sb.emitOp(node, 'ROT'); // [key, val, accum, accum] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapReduceHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapReduceHelper.ts index 987d350e0c..ae24ad2744 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapReduceHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapReduceHelper.ts @@ -4,24 +4,27 @@ import { VisitOptions } from '../../types'; import { Helper } from '../Helper'; export interface MapReduceHelperOptions { + readonly deserializeKey?: boolean; readonly each: (options: VisitOptions) => void; } // Input: [accum, map] // Output: [accum] export class MapReduceHelper extends Helper { + private readonly deserializeKey: boolean; private readonly each: (options: VisitOptions) => void; public constructor(options: MapReduceHelperOptions) { super(); this.each = options.each; + this.deserializeKey = options.deserializeKey ?? false; } public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { // [map, accum] sb.emitOp(node, 'SWAP'); // [iterator, accum] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [accum, iterator] sb.emitOp(node, 'SWAP'); // [accum] @@ -29,6 +32,7 @@ export class MapReduceHelper extends Helper { node, options, sb.helpers.rawIteratorReduce({ + deserializeKey: this.deserializeKey, each: this.each, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapSomeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapSomeHelper.ts index 3e2ecf41db..3311984093 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapSomeHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/MapSomeHelper.ts @@ -19,7 +19,7 @@ export class MapSomeHelper extends Helper { public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [accum] sb.emitHelper( node, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapDeleteHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapDeleteHelper.ts new file mode 100644 index 0000000000..478efb54d4 --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapDeleteHelper.ts @@ -0,0 +1,72 @@ +import ts from 'typescript'; +import { ScriptBuilder } from '../../sb'; +import { VisitOptions } from '../../types'; +import { Helper } from '../Helper'; + +// Input: [keyVal, map] - Note that "map" here is actually a struct [typeMap, valueMap] +// Output: [boolVal] +export class UnusedMapDeleteHelper extends Helper { + public emit(sb: ScriptBuilder, node: ts.Node, optionsIn: VisitOptions): void { + const options = sb.pushValueOptions(optionsIn); + + // [map, keyVal] + sb.emitOp(node, 'SWAP'); + // [map, keyVal, map] + sb.emitOp(node, 'TUCK'); + // [keyVal, map, keyVal, map] + sb.emitOp(node, 'OVER'); + // [boolVal] + sb.emitHelper( + node, + options, + sb.helpers.if({ + condition: () => { + // [hasKey, keyVal, map] + sb.emitHelper(node, options, sb.helpers.mapHasKey); + }, + whenTrue: () => { + // [size, keyType, key, map] + sb.emitOp(node, 'UNPACK'); + // [keyType, key, map] + sb.emitOp(node, 'DROP'); + // [key, map] + sb.emitOp(node, 'DROP'); + // [key, key, map] + sb.emitOp(node, 'DUP'); + // [map, key, key] + sb.emitOp(node, 'ROT'); + // [size, typeMap, valueMap, key, key] + sb.emitOp(node, 'UNPACK'); + // [typeMap, valueMap, key, key] + sb.emitOp(node, 'DROP'); + // [key, typeMap, valueMap, key] + sb.emitOp(node, 'ROT'); + // [valueMap, key] + sb.emitOp(node, 'REMOVE'); + // [key, valueMap] + sb.emitOp(node, 'SWAP'); + // [] + sb.emitOp(node, 'REMOVE'); + if (optionsIn.pushValue) { + // [true] + sb.emitPushBoolean(node, true); + // [boolVal] + sb.emitHelper(node, options, sb.helpers.wrapBoolean); + } + }, + whenFalse: () => { + // [map] + sb.emitOp(node, 'DROP'); + // [] + sb.emitOp(node, 'DROP'); + if (optionsIn.pushValue) { + // [false] + sb.emitPushBoolean(node, false); + // [boolVal] + sb.emitHelper(node, options, sb.helpers.wrapBoolean); + } + }, + }), + ); + } +} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapGetHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapGetHelper.ts new file mode 100644 index 0000000000..95305c84ac --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapGetHelper.ts @@ -0,0 +1,30 @@ +import ts from 'typescript'; +import { ScriptBuilder } from '../../sb'; +import { VisitOptions } from '../../types'; +import { Helper } from '../Helper'; + +// Input: [keyVal, map] - Note that "map" here is actually a struct [typeMap, valueMap] +// Output: [val] +export class UnusedMapGetHelper extends Helper { + // TODO: add pushvalue option? + public emit(sb: ScriptBuilder, node: ts.Node, _options: VisitOptions): void { + // [size, keyType, key, map] + sb.emitOp(node, 'UNPACK'); + // [keyType, key, map] + sb.emitOp(node, 'DROP'); + // [key, map] + sb.emitOp(node, 'DROP'); + // [map, key] + sb.emitOp(node, 'SWAP'); + // [size, typeMap, valueMap, key] + sb.emitOp(node, 'UNPACK'); + // [typeMap, valueMap, key] + sb.emitOp(node, 'DROP'); + // [valueMap, key] + sb.emitOp(node, 'DROP'); + // [key, valueMap] + sb.emitOp(node, 'SWAP'); + // [val] + sb.emitOp(node, 'PICKITEM'); + } +} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapHasKeyHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapHasKeyHelper.ts new file mode 100644 index 0000000000..68ec18350d --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapHasKeyHelper.ts @@ -0,0 +1,105 @@ +import ts from 'typescript'; +import { ScriptBuilder } from '../../sb'; +import { VisitOptions } from '../../types'; +import { Helper } from '../Helper'; + +// Input: [keyVal, map] - Note that "map" here is actually a struct [typeMap, valueMap] +// Output: [hasKey] +export class UnusedMapHasKeyHelper extends Helper { + // TODO: need a push value DROP? + public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { + // [map, keyVal] + sb.emitOp(node, 'SWAP'); + // [map, map, keyVal] + sb.emitOp(node, 'DUP'); + // [0, map, map, keyVal] + sb.emitPushInt(node, 0); + // [typeMap, map, keyVal] + sb.emitOp(node, 'PICKITEM'); + // [map, typeMap, keyVal] + sb.emitOp(node, 'SWAP'); + // [1, map, typeMap, keyVal] + sb.emitPushInt(node, 1); + // [valueMap, typeMap, keyVal] + sb.emitOp(node, 'PICKITEM'); + // [keyVal, valueMap, typeMap] + sb.emitOp(node, 'ROT'); + // [size, keyType, key, valueMap, typeMap] + sb.emitOp(node, 'UNPACK'); + // [keyType, key, valueMap, typeMap] + sb.emitOp(node, 'DROP'); + // [key, keyType, valueMap, typeMap] + sb.emitOp(node, 'SWAP'); + // [key, key, keyType, valueMap, typeMap] + sb.emitOp(node, 'DUP'); + // [valueMap, keyType, key, key, typeMap] + sb.emitOp(node, 'REVERSE4'); + // [key, valueMap, keyType, key, typeMap] + sb.emitOp(node, 'ROT'); + // [hasKey] + sb.emitHelper( + node, + options, + sb.helpers.if({ + condition: () => { + // [valueMapHasKey, keyType, key, typeMap] + sb.emitOp(node, 'HASKEY'); + }, + whenTrue: () => { + // now check if types match + // [typeMap, keyType, key] + sb.emitOp(node, 'ROT'); + // [key, typeMap, keyType] + sb.emitOp(node, 'ROT'); + // [key, key, typeMap, keyType] + sb.emitOp(node, 'DUP'); + // [typeMap, key, key, keyType] + sb.emitOp(node, 'ROT'); + // [typeMap, typeMap, key, key, keyType] + sb.emitOp(node, 'DUP'); + // [key, typeMap, typeMap, key, keyType] + sb.emitOp(node, 'ROT'); + // [hasKey] + sb.emitHelper( + node, + options, + sb.helpers.if({ + condition: () => { + // [typeMapHasKey, typeMap, key, keyType] + sb.emitOp(node, 'HASKEY'); + }, + whenTrue: () => { + // [key, typeMap, keyType] + sb.emitOp(node, 'SWAP'); + // [keyType, keyType] + sb.emitOp(node, 'PICKITEM'); + // [keyTypesMatch] + sb.emitOp(node, 'NUMEQUAL'); + }, + whenFalse: () => { + // [key, keyType] + sb.emitOp(node, 'DROP'); + // [keyType] + sb.emitOp(node, 'DROP'); + // [] + sb.emitOp(node, 'DROP'); + // [false] + sb.emitPushBoolean(node, false); + }, + }), + ); + }, + whenFalse: () => { + // [key, typeMap] + sb.emitOp(node, 'DROP'); + // [typeMap] + sb.emitOp(node, 'DROP'); + // [] + sb.emitOp(node, 'DROP'); + // [false] + sb.emitPushBoolean(node, false); + }, + }), + ); + } +} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapSetHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapSetHelper.ts new file mode 100644 index 0000000000..56dbb10559 --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/map/UnusedMapSetHelper.ts @@ -0,0 +1,43 @@ +import ts from 'typescript'; +import { ScriptBuilder } from '../../sb'; +import { VisitOptions } from '../../types'; +import { Helper } from '../Helper'; + +// Input: [valVal, keyVal, map] - Note that "map" here is actually a struct [typeMap, valueMap] +// Output: [] +export class UnusedMapSetHelper extends Helper { + public emit(sb: ScriptBuilder, node: ts.Node, _options: VisitOptions): void { + // [map, valVal, keyVal] + sb.emitOp(node, 'ROT'); + // [size, typeMap, valueMap, valVal, keyVal] + sb.emitOp(node, 'UNPACK'); + // [typeMap, valueMap, valVal, keyVal] + sb.emitOp(node, 'DROP'); + // [keyVal, valVal, valueMap, typeMap] + sb.emitOp(node, 'REVERSE4'); + // [size, keyType, key, valVal, valueMap, typeMap] + sb.emitOp(node, 'UNPACK'); + // [keyType, key, valVal, valueMap, typeMap] + sb.emitOp(node, 'DROP'); + // [key, keyType, valVal, valueMap, typeMap] + sb.emitOp(node, 'SWAP'); + // [key, key, keyType, valVal, valueMap, typeMap] + sb.emitOp(node, 'DUP'); + // [keyType, key, key, valVal, valueMap, typeMap] + sb.emitOp(node, 'ROT'); + // [5, keyType, key, key, valVal, valueMap, typeMap] + sb.emitPushInt(node, 5); + // [typeMap, keyType, key, key, valVal, valueMap] + sb.emitOp(node, 'ROLL'); + // [key, typeMap, keyType, key, valVal, valueMap] + sb.emitOp(node, 'ROT'); + // [keyType, key, typeMap, key, valVal, valueMap] + sb.emitOp(node, 'ROT'); + // [key, valVal, valueMap] + sb.emitOp(node, 'SETITEM'); + // [valVal, key, valueMap] + sb.emitOp(node, 'SWAP'); + // [] + sb.emitOp(node, 'SETITEM'); + } +} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/relational/EqualsEqualsEqualsHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/relational/EqualsEqualsEqualsHelper.ts index d96f450459..d5bb62772a 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/relational/EqualsEqualsEqualsHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/relational/EqualsEqualsEqualsHelper.ts @@ -1,3 +1,4 @@ +import { StackItemType } from '@neo-one/client-common'; import ts from 'typescript'; import { Types, WrappableType } from '../../constants'; import { ScriptBuilder } from '../../sb'; @@ -58,7 +59,20 @@ export class EqualsEqualsEqualsHelper extends Helper { sb.emitHelper(node, innerOptions, sb.helpers.unwrapVal({ type })); sb.emitOp(node, 'SWAP'); sb.emitHelper(node, innerOptions, sb.helpers.unwrapVal({ type })); - sb.emitOp(node, 'EQUAL'); + if (type === Types.Boolean) { + sb.emitOp(node, 'NUMEQUAL'); + } else if (type === Types.String) { + // [bytestring, buffer] + sb.emitOp(node, 'CONVERT', Buffer.from([StackItemType.ByteString])); + // [buffer, bytestring] + sb.emitOp(node, 'SWAP'); + // [bytestring, bytestring] + sb.emitOp(node, 'CONVERT', Buffer.from([StackItemType.ByteString])); + // [boolean] + sb.emitOp(node, 'EQUAL'); + } else { + sb.emitOp(node, 'EQUAL'); + } }; const compareStorageValue = () => { @@ -72,8 +86,10 @@ export class EqualsEqualsEqualsHelper extends Helper { const compareNumber = (innerOptions: VisitOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.unwrapNumber); + sb.emitOp(node, 'CONVERT', Buffer.from([StackItemType.Integer])); sb.emitOp(node, 'SWAP'); sb.emitHelper(node, innerOptions, sb.helpers.unwrapNumber); + sb.emitOp(node, 'CONVERT', Buffer.from([StackItemType.Integer])); sb.emitOp(node, 'NUMEQUAL'); }; @@ -109,13 +125,8 @@ export class EqualsEqualsEqualsHelper extends Helper { iterable: pushFalse, iterableIterator: pushFalse, transaction: pushFalse, - output: pushFalse, attribute: pushFalse, - input: pushFalse, - account: pushFalse, - asset: pushFalse, contract: pushFalse, - header: pushFalse, block: pushFalse, [value]: compareValue, }), @@ -150,13 +161,8 @@ export class EqualsEqualsEqualsHelper extends Helper { iterable: pushFalse, iterableIterator: pushFalse, transaction: pushFalse, - output: pushFalse, attribute: pushFalse, - input: pushFalse, - account: pushFalse, - asset: pushFalse, contract: pushFalse, - header: pushFalse, block: pushFalse, [value]: compareStorageValue, }), @@ -191,13 +197,8 @@ export class EqualsEqualsEqualsHelper extends Helper { iterable: pushFalse, iterableIterator: pushFalse, transaction: pushFalse, - output: pushFalse, attribute: pushFalse, - input: pushFalse, - account: pushFalse, - asset: pushFalse, contract: pushFalse, - header: pushFalse, block: pushFalse, [value]: pushTrue, }), @@ -234,13 +235,8 @@ export class EqualsEqualsEqualsHelper extends Helper { iterable: createProcessIterable(), iterableIterator: createProcess('iterableIterator', Types.IterableIterator), transaction: createProcess('transaction', Types.Transaction), - output: createProcess('output', Types.Output), attribute: createProcess('attribute', Types.Attribute), - input: createProcess('input', Types.Input), - account: createProcess('account', Types.Account), - asset: createProcess('asset', Types.Asset), contract: createProcess('contract', Types.Contract), - header: createProcess('header', Types.Header), block: createProcess('block', Types.Block), }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/scope/DupScopeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/scope/DupScopeHelper.ts new file mode 100644 index 0000000000..00df2ca43c --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/scope/DupScopeHelper.ts @@ -0,0 +1,23 @@ +import ts from 'typescript'; +import { ScriptBuilder } from '../../sb'; +import { VisitOptions } from '../../types'; +import { Helper } from '../Helper'; + +// effectively replaces DUPFROMALTSTACK + +// Input: [] +// Output: [scope] +export class DupScopeHelper extends Helper { + public emit(sb: ScriptBuilder, node: ts.Node, _options: VisitOptions): void { + // [arr] + sb.emitOp(node, 'LDSFLD0'); + // [arr, arr] + sb.emitOp(node, 'DUP'); + // [size, arr] + sb.emitOp(node, 'SIZE'); + // [size - 1, arr] + sb.emitOp(node, 'DEC'); + // [scope] + sb.emitOp(node, 'PICKITEM'); + } +} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/scope/PopScopeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/scope/PopScopeHelper.ts new file mode 100644 index 0000000000..57fceb4143 --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/scope/PopScopeHelper.ts @@ -0,0 +1,17 @@ +import ts from 'typescript'; +import { ScriptBuilder } from '../../sb'; +import { VisitOptions } from '../../types'; +import { Helper } from '../Helper'; + +// effectively replaces FROMALTSTACK + +// Input: [] +// Output: [scope] +export class PopScopeHelper extends Helper { + public emit(sb: ScriptBuilder, node: ts.Node, _options: VisitOptions): void { + // [arr] + sb.emitOp(node, 'LDSFLD0'); + // [scope] + sb.emitOp(node, 'POPITEM'); + } +} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/scope/PushScopeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/scope/PushScopeHelper.ts new file mode 100644 index 0000000000..c7b5361090 --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/scope/PushScopeHelper.ts @@ -0,0 +1,19 @@ +import ts from 'typescript'; +import { ScriptBuilder } from '../../sb'; +import { VisitOptions } from '../../types'; +import { Helper } from '../Helper'; + +// effectively replaces TOALTSTACK + +// Input: [scope] +// Output: [] +export class PushScopeHelper extends Helper { + public emit(sb: ScriptBuilder, node: ts.Node, _options: VisitOptions): void { + // [arr, scope] + sb.emitOp(node, 'LDSFLD0'); + // [scope, arr] + sb.emitOp(node, 'SWAP'); + // [] + sb.emitOp(node, 'APPEND'); + } +} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/scope/index.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/scope/index.ts new file mode 100644 index 0000000000..ad03da404d --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/scope/index.ts @@ -0,0 +1,3 @@ +export * from './DupScopeHelper'; +export * from './PopScopeHelper'; +export * from './PushScopeHelper'; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/statement/ForLoopHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/statement/ForLoopHelper.ts index decce1d2a6..69e087e2a9 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/statement/ForLoopHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/statement/ForLoopHelper.ts @@ -36,7 +36,7 @@ export class ForLoopHelper extends Helper { } if (!loopPC.getFirst().equals(loopPC.getCurrent())) { - sb.emitJmp(node, 'JMPIFNOT', loopPC.getLast()); + sb.emitJmp(node, 'JMPIFNOT_L', loopPC.getLast()); } sb.withProgramCounter((finallyPC) => { @@ -54,7 +54,7 @@ export class ForLoopHelper extends Helper { this.incrementor(); } - sb.emitJmp(node, 'JMP', loopPC.getFirst()); + sb.emitJmp(node, 'JMP_L', loopPC.getFirst()); }); // Drop finally completion @@ -119,7 +119,7 @@ export class ForLoopHelper extends Helper { if (this.incrementor !== undefined) { this.incrementor(); } - sb.emitJmp(node, 'JMP', loopPC.getFirst()); + sb.emitJmp(node, 'JMP_L', loopPC.getFirst()); }, ), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/statement/IfHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/statement/IfHelper.ts index ed22332cb5..7cf092a957 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/statement/IfHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/statement/IfHelper.ts @@ -30,16 +30,16 @@ export class IfHelper extends Helper { throw new Error('If statement must have a true or false value'); } sb.withProgramCounter((endPC) => { - sb.emitJmp(node, 'JMPIF', endPC.getLast()); + sb.emitJmp(node, 'JMPIF_L', endPC.getLast()); whenFalse(); }); } else { sb.withProgramCounter((whenFalsePC) => { sb.withProgramCounter((whenTruePC) => { - sb.emitJmp(node, 'JMPIFNOT', whenTruePC.getLast()); + sb.emitJmp(node, 'JMPIFNOT_L', whenTruePC.getLast()); whenTrue(); if (this.whenFalse !== undefined) { - sb.emitJmp(node, 'JMP', whenFalsePC.getLast()); + sb.emitJmp(node, 'JMP_L', whenFalsePC.getLast()); } }); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/AtStructuredStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/AtStructuredStorageHelper.ts index 6f21aff44c..d2a05bff05 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/AtStructuredStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/AtStructuredStorageHelper.ts @@ -51,7 +51,7 @@ export class AtStructuredStorageHelper extends KeyStructuredStorageBaseHelper { // [valKeyArr, size, number, struct, struct] sb.emitOp(node, 'ROLL'); // [addSize, size, number, struct, struct] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [size, number, struct, struct] sb.emitOp(node, 'ADD'); // [struct] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/CacheStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/CacheStorageHelper.ts index 46d9593f9d..feab151e04 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/CacheStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/CacheStorageHelper.ts @@ -27,7 +27,7 @@ export class CacheStorageHelper extends Helper { // [map] sb.emitOp(node, 'PICKITEM'); // [number, map] - sb.emitSysCall(node, 'Neo.Runtime.GetTrigger'); + sb.emitSysCall(node, 'System.Runtime.GetTrigger'); // [number, number, map] sb.emitPushInt(node, 0x10); sb.emitHelper( @@ -46,9 +46,9 @@ export class CacheStorageHelper extends Helper { sb.helpers.mapForEach({ each: () => { // [context, keyBuffer, valBuffer] - sb.emitSysCall(node, 'Neo.Storage.GetContext'); + sb.emitSysCall(node, 'System.Storage.GetContext'); // [] - sb.emitSysCall(node, 'Neo.Storage.Put'); + sb.emitSysCall(node, 'System.Storage.Put'); }, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/CommonStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/CommonStorageHelper.ts index 661775ef44..63e43e74dc 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/CommonStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/CommonStorageHelper.ts @@ -32,24 +32,22 @@ export class CommonStorageHelper extends Helper { // [map, map, number, globalObject, number, globalObject] sb.emitOp(node, 'DUP'); // [buffer, map, number, globalObject, number, globalObject] - sb.emitSysCall(node, 'Neo.Runtime.Serialize'); + sb.emitSysCall(node, 'System.Binary.Serialize'); }, handleDefined: () => { // [buffer, buffer, number, globalObject, number, globalObject] sb.emitOp(node, 'DUP'); // [map, buffer, number, globalObject, number, globalObject] - sb.emitSysCall(node, 'Neo.Runtime.Deserialize'); + sb.emitSysCall(node, 'System.Binary.Deserialize'); // [buffer, map, number, globalObject, number, globalObject] sb.emitOp(node, 'SWAP'); }, }), ); - // [number, buffer, map, number, globalObject, number, globalObject] - sb.emitPushInt(node, 4); - // [buffer, map, number, globalObject, buffer, number, globalObject] - sb.emitOp(node, 'XTUCK'); + // [globalObject, number, map, buffer, number, globalObject] + sb.emitOp(node, 'REVERSE4'); // [map, number, globalObject, buffer, number, globalObject] - sb.emitOp(node, 'DROP'); + sb.emitOp(node, 'REVERSE3'); // [buffer, number, globalObject] sb.emitOp(node, 'SETITEM'); // [] @@ -72,7 +70,7 @@ export class CommonStorageHelper extends Helper { // [map, bufferOriginal] sb.emitOp(node, 'PICKITEM'); // [buffer, bufferOriginal] - sb.emitSysCall(node, 'Neo.Runtime.Serialize'); + sb.emitSysCall(node, 'System.Binary.Serialize'); // [buffer, bufferOriginal, buffer] sb.emitOp(node, 'TUCK'); sb.emitHelper( @@ -89,7 +87,7 @@ export class CommonStorageHelper extends Helper { }, whenFalse: () => { // [number, valueBuffer] - sb.emitSysCall(node, 'Neo.Runtime.GetTrigger'); + sb.emitSysCall(node, 'System.Runtime.GetTrigger'); // [number, number, valueBuffer] sb.emitPushInt(node, 0x10); sb.emitHelper( @@ -104,9 +102,9 @@ export class CommonStorageHelper extends Helper { // [keyBuffer, valueBuffer] sb.emitPushBuffer(node, Buffer.alloc(0, 0)); // [context, keyBuffer, valBuffer] - sb.emitSysCall(node, 'Neo.Storage.GetContext'); + sb.emitSysCall(node, 'System.Storage.GetContext'); // [] - sb.emitSysCall(node, 'Neo.Storage.Put'); + sb.emitSysCall(node, 'System.Storage.Put'); }, whenFalse: () => { sb.emitOp(node, 'DROP'); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/CreateStructuredStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/CreateStructuredStorageHelper.ts index 4da2519617..c43a97084a 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/CreateStructuredStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/CreateStructuredStorageHelper.ts @@ -36,9 +36,38 @@ export class CreateStructuredStorageHelper extends StructuredStorageBaseHelper { sb.emitPushString(node, this.prefix); // [3, prefix, size, arr] sb.emitPushInt(node, 3); - // [struct] - sb.emitOp(node, 'PACK'); + // [struct, prefix, size, arr] sb.emitOp(node, 'NEWSTRUCT'); + // [struct, prefix, struct, size, arr] + sb.emitOp(node, 'TUCK'); + // [prefix, struct, struct, size, arr] + sb.emitOp(node, 'SWAP'); + // [0, prefix, struct, struct, size, arr] + sb.emitPushInt(node, 0); + // [prefix, 0, struct, struct, size, arr] + sb.emitOp(node, 'SWAP'); + // [struct, size, arr] + sb.emitOp(node, 'SETITEM'); + // [struct, size, struct, arr] + sb.emitOp(node, 'TUCK'); + // [size, struct, struct, arr] + sb.emitOp(node, 'SWAP'); + // [1, size, struct, struct, arr] + sb.emitPushInt(node, 1); + // [size, 1, struct, struct, arr] + sb.emitOp(node, 'SWAP'); + // [struct, arr] + sb.emitOp(node, 'SETITEM'); + // [struct, arr, struct] + sb.emitOp(node, 'TUCK'); + // [arr, struct, struct] + sb.emitOp(node, 'SWAP'); + // [2, arr, struct, struct] + sb.emitPushInt(node, 2); + // [arr, 2, struct, struct] + sb.emitOp(node, 'SWAP'); + // [struct] + sb.emitOp(node, 'SETITEM'); // [val] sb.emitHelper(node, options, sb.helpers.wrapVal({ type: this.type })); } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/DeleteCacheStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/DeleteCacheStorageHelper.ts index c8c8cf71de..20e677cc4c 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/DeleteCacheStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/DeleteCacheStorageHelper.ts @@ -27,7 +27,7 @@ export class DeleteCacheStorageHelper extends Helper { // [map] sb.emitOp(node, 'PICKITEM'); // [number, map] - sb.emitSysCall(node, 'Neo.Runtime.GetTrigger'); + sb.emitSysCall(node, 'System.Runtime.GetTrigger'); // [number, number, map] sb.emitPushInt(node, 0x10); sb.emitHelper( @@ -46,9 +46,9 @@ export class DeleteCacheStorageHelper extends Helper { sb.helpers.mapForEach({ each: () => { // [context, keyBuffer, valBuffer] - sb.emitSysCall(node, 'Neo.Storage.GetContext'); + sb.emitSysCall(node, 'System.Storage.GetContext'); // [valBuffer] - sb.emitSysCall(node, 'Neo.Storage.Delete'); + sb.emitSysCall(node, 'System.Storage.Delete'); // [] sb.emitOp(node, 'DROP'); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/GetKeyStructuredStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/GetKeyStructuredStorageHelper.ts index 6fefe00e0e..079151633f 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/GetKeyStructuredStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/GetKeyStructuredStorageHelper.ts @@ -1,3 +1,4 @@ +import { StackItemType } from '@neo-one/client-common'; import ts from 'typescript'; import { StructuredStorageSlots } from '../../constants'; import { ScriptBuilder } from '../../sb'; @@ -36,11 +37,13 @@ export class GetKeyStructuredStorageHelper extends KeyStructuredStorageBaseHelpe // [val, prefix] sb.emitOp(node, 'SWAP'); // [buffer, prefix] - sb.emitSysCall(node, 'Neo.Runtime.Serialize'); + sb.emitSysCall(node, 'System.Binary.Serialize'); // [prefix] sb.emitOp(node, 'CAT'); }, }), ); + // [bytestring] + sb.emitOp(node, 'CONVERT', Buffer.from([StackItemType.ByteString])); } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/GetStorageBaseHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/GetStorageBaseHelper.ts index 87bff0711c..f322c8231d 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/GetStorageBaseHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/GetStorageBaseHelper.ts @@ -10,9 +10,9 @@ export class GetStorageBaseHelper extends Helper { const options = sb.pushValueOptions(optionsIn); // [context, keyBuffer] - sb.emitSysCall(node, 'Neo.Storage.GetReadOnlyContext'); + sb.emitSysCall(node, 'System.Storage.GetReadOnlyContext'); // [iterator] - sb.emitSysCall(node, 'Neo.Storage.Find'); + sb.emitSysCall(node, 'System.Storage.Find'); // [iterator, iterator] sb.emitOp(node, 'DUP'); sb.emitHelper( @@ -21,11 +21,11 @@ export class GetStorageBaseHelper extends Helper { sb.helpers.if({ condition: () => { // [boolean, iterator] - sb.emitSysCall(node, 'Neo.Enumerator.Next'); + sb.emitSysCall(node, 'System.Enumerator.Next'); }, whenTrue: () => { // [value] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); }, whenFalse: () => { // [] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/GetStructuredStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/GetStructuredStorageHelper.ts index 0a79d0c30f..e97b3a323a 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/GetStructuredStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/GetStructuredStorageHelper.ts @@ -26,7 +26,7 @@ export class GetStructuredStorageHelper extends KeyStructuredStorageBaseHelper { }, handleDefined: () => { // [arr] - sb.emitSysCall(node, 'Neo.Runtime.Deserialize'); + sb.emitSysCall(node, 'System.Binary.Deserialize'); // [1, arr] sb.emitPushInt(node, 1); // [val] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandlePrefixArrayStructuredStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandlePrefixArrayStructuredStorageHelper.ts index f9332e1b5b..f498e8e98d 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandlePrefixArrayStructuredStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandlePrefixArrayStructuredStorageHelper.ts @@ -21,7 +21,7 @@ export class HandlePrefixArrayStructuredStorageHelper extends Helper { // [val, prefix, val, struct] sb.emitOp(node, 'TUCK'); // [buffer, prefix, val, struct] - sb.emitSysCall(node, 'Neo.Runtime.Serialize'); + sb.emitSysCall(node, 'System.Binary.Serialize'); // [prefix, val, struct] sb.emitOp(node, 'CAT'); // [struct, prefix, val] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandlePrefixKeyStructuredStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandlePrefixKeyStructuredStorageHelper.ts index 5c3c80e087..247fa70f66 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandlePrefixKeyStructuredStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandlePrefixKeyStructuredStorageHelper.ts @@ -30,7 +30,7 @@ export class HandlePrefixKeyStructuredStorageHelper extends Helper { // [arr, arr] sb.emitOp(node, 'DUP'); // [size, arr] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [1, size, arr] sb.emitPushInt(node, 1); // [boolean, arr] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandleValValueStructuredStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandleValValueStructuredStorageHelper.ts index cefc424dea..c249c23572 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandleValValueStructuredStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandleValValueStructuredStorageHelper.ts @@ -16,7 +16,7 @@ export class HandleValValueStructuredStorageHelper extends Helper { // [iterator, iterator] sb.emitOp(node, 'DUP'); // [keyBuffer, iterator, size] - sb.emitSysCall(node, 'Neo.Iterator.Key'); + sb.emitSysCall(node, 'System.Iterator.Key'); sb.emitHelper( node, options, @@ -35,9 +35,9 @@ export class HandleValValueStructuredStorageHelper extends Helper { }, whenFalse: () => { // [value] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [arr] - sb.emitSysCall(node, 'Neo.Runtime.Deserialize'); + sb.emitSysCall(node, 'System.Binary.Deserialize'); // [1, arr] sb.emitPushInt(node, 1); // [val] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandleValueStructuredStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandleValueStructuredStorageHelper.ts index c9418013e7..a5e38bec89 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandleValueStructuredStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/HandleValueStructuredStorageHelper.ts @@ -19,7 +19,7 @@ export class HandleValueStructuredStorageHelper extends Helper { // [iterator, iterator, size] sb.emitOp(node, 'DUP'); // [keyBuffer, iterator, size] - sb.emitSysCall(node, 'Neo.Iterator.Key'); + sb.emitSysCall(node, 'System.Iterator.Key'); sb.emitHelper( node, options, @@ -38,9 +38,9 @@ export class HandleValueStructuredStorageHelper extends Helper { }, whenFalse: () => { // [value, size] - sb.emitSysCall(node, 'Neo.Enumerator.Value'); + sb.emitSysCall(node, 'System.Enumerator.Value'); // [arr, size] - sb.emitSysCall(node, 'Neo.Runtime.Deserialize'); + sb.emitSysCall(node, 'System.Binary.Deserialize'); // [2, keyVal, valVal, size] sb.emitOp(node, 'UNPACK'); // [keyVal, valVal, size] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/IterStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/IterStorageHelper.ts index 2dca7ec316..156cf3b2c8 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/IterStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/IterStorageHelper.ts @@ -12,9 +12,9 @@ export class IterStorageHelper extends Helper { // [keyBuffer, keyBuffer] sb.emitOp(node, 'DUP'); // [context, keyBuffer, keyBuffer] - sb.emitSysCall(node, 'Neo.Storage.GetReadOnlyContext'); + sb.emitSysCall(node, 'System.Storage.GetReadOnlyContext'); // [iterator, keyBuffer] - sb.emitSysCall(node, 'Neo.Storage.Find'); + sb.emitSysCall(node, 'System.Storage.Find'); // [keyBuffer, iterator] sb.emitOp(node, 'SWAP'); const key = sb.scope.addUnique(); @@ -44,8 +44,8 @@ export class IterStorageHelper extends Helper { }), ); // [iterator, iterator] - sb.emitSysCall(node, 'Neo.Iterator.Create'); + sb.emitSysCall(node, 'System.Iterator.Create'); // [iterator] - sb.emitSysCall(node, 'Neo.Iterator.Concat'); + sb.emitSysCall(node, 'System.Iterator.Concat'); } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/SetArrayStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/SetArrayStorageHelper.ts index abaf9e0ac4..1774c3f6fd 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/SetArrayStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/SetArrayStorageHelper.ts @@ -25,7 +25,7 @@ export class SetArrayStorageHelper extends Helper { sb.helpers.if({ condition: () => { // [length <= number, val, valueVal, number] - sb.emitOp(node, 'LTE'); + sb.emitOp(node, 'LE'); }, whenTrue: () => { // [val, val, valueVal, number] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/SetStructuredStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/SetStructuredStorageHelper.ts index 0f5d3094d9..494fa4cc2e 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/SetStructuredStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/SetStructuredStorageHelper.ts @@ -1,3 +1,4 @@ +import { StackItemType } from '@neo-one/client-common'; import ts from 'typescript'; import { StructuredStorageSlots } from '../../constants'; import { ScriptBuilder } from '../../sb'; @@ -42,6 +43,8 @@ export class SetStructuredStorageHelper extends KeyStructuredStorageBaseHelper { sb.emitPushInt(node, StructuredStorageSlots.prefix); // [keyBuffer, struct, valValue] sb.emitOp(node, 'PICKITEM'); + // [keyBuffer, struct, valValue] + sb.emitOp(node, 'CONVERT', Buffer.from([StackItemType.ByteString])); // [struct, keyBuffer, valValue] sb.emitOp(node, 'SWAP'); // [number, struct, keyBuffer, valValue] @@ -59,7 +62,7 @@ export class SetStructuredStorageHelper extends KeyStructuredStorageBaseHelper { // [arr, keyBuffer] sb.emitOp(node, 'PACK'); // [bufferValue, keyBuffer] - sb.emitSysCall(node, 'Neo.Runtime.Serialize'); + sb.emitSysCall(node, 'System.Binary.Serialize'); // [keyBuffer, bufferValue] sb.emitOp(node, 'SWAP'); // [] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/UnwrapKeyStructuredStorageHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/UnwrapKeyStructuredStorageHelper.ts index 6baeb151d9..65a3844e67 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/UnwrapKeyStructuredStorageHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/storage/UnwrapKeyStructuredStorageHelper.ts @@ -48,13 +48,8 @@ export class UnwrapKeyStructuredStorageHelper extends TypedHelper { iterable: wrapArray, iterableIterator: wrapArray, transaction: wrapArray, - output: wrapArray, attribute: wrapArray, - input: wrapArray, - account: wrapArray, - asset: wrapArray, contract: wrapArray, - header: wrapArray, block: wrapArray, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/ForBuiltinTypeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/ForBuiltinTypeHelper.ts index bd4e3439da..b2bae78ba4 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/ForBuiltinTypeHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/ForBuiltinTypeHelper.ts @@ -5,10 +5,8 @@ import { Types } from '../../constants'; import { ScriptBuilder } from '../../sb'; import { VisitOptions } from '../../types'; import { Helper } from '../Helper'; -import { hasAccount } from './account'; import { hasArray } from './array'; import { hasArrayStorage } from './arrayStorage'; -import { hasAsset } from './asset'; import { hasAttribute } from './attribute'; import { hasBlock } from './block'; import { hasBoolean } from './boolean'; @@ -16,8 +14,6 @@ import { hasBuffer } from './buffer'; import { hasContract } from './contract'; import { hasError } from './error'; import { hasForwardValue } from './forwardValue'; -import { hasHeader } from './header'; -import { hasInput } from './input'; import { hasIterable } from './iterable'; import { hasIterableIterator } from './iterableIterator'; import { hasIteratorResult } from './iteratorResult'; @@ -26,7 +22,6 @@ import { hasMapStorage } from './mapStorage'; import { hasNull } from './null'; import { hasNumber } from './number'; import { hasObject } from './object'; -import { hasOutput } from './output'; import { hasSet } from './set'; import { hasSetStorage } from './setStorage'; import { hasString } from './string'; @@ -62,13 +57,8 @@ export interface ForBuiltinTypeHelperOptions { readonly iterable: ProcessType; readonly iterableIterator: ProcessType; readonly transaction: ProcessType; - readonly output: ProcessType; readonly attribute: ProcessType; - readonly input: ProcessType; - readonly account: ProcessType; - readonly asset: ProcessType; readonly contract: ProcessType; - readonly header: ProcessType; readonly block: ProcessType; readonly forwardValue: ProcessType; } @@ -101,13 +91,8 @@ export class ForBuiltinTypeHelper extends Helper { private readonly iterable: ProcessType; private readonly iterableIterator: ProcessType; private readonly transaction: ProcessType; - private readonly output: ProcessType; private readonly attribute: ProcessType; - private readonly input: ProcessType; - private readonly account: ProcessType; - private readonly asset: ProcessType; private readonly contract: ProcessType; - private readonly header: ProcessType; private readonly block: ProcessType; private readonly forwardValue: ProcessType; @@ -137,13 +122,8 @@ export class ForBuiltinTypeHelper extends Helper { iterable, iterableIterator, transaction, - output, attribute, - input, - account, - asset, contract, - header, block, forwardValue, }: ForBuiltinTypeHelperOptions) { @@ -173,13 +153,8 @@ export class ForBuiltinTypeHelper extends Helper { this.iterable = iterable; this.iterableIterator = iterableIterator; this.transaction = transaction; - this.output = output; this.attribute = attribute; - this.input = input; - this.account = account; - this.asset = asset; this.contract = contract; - this.header = header; this.block = block; this.forwardValue = forwardValue; } @@ -332,13 +307,6 @@ export class ForBuiltinTypeHelper extends Helper { }, process: this.transaction, }, - { - hasType: (type) => hasOutput(sb.context, node, type), - isRuntimeType: (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.isOutput); - }, - process: this.output, - }, { hasType: (type) => hasAttribute(sb.context, node, type), isRuntimeType: (innerOptions) => { @@ -346,27 +314,6 @@ export class ForBuiltinTypeHelper extends Helper { }, process: this.attribute, }, - { - hasType: (type) => hasInput(sb.context, node, type), - isRuntimeType: (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.isInput); - }, - process: this.input, - }, - { - hasType: (type) => hasAccount(sb.context, node, type), - isRuntimeType: (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.isAccount); - }, - process: this.account, - }, - { - hasType: (type) => hasAsset(sb.context, node, type), - isRuntimeType: (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.isAsset); - }, - process: this.asset, - }, { hasType: (type) => hasContract(sb.context, node, type), isRuntimeType: (innerOptions) => { @@ -374,13 +321,6 @@ export class ForBuiltinTypeHelper extends Helper { }, process: this.contract, }, - { - hasType: (type) => hasHeader(sb.context, node, type), - isRuntimeType: (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.isHeader); - }, - process: this.header, - }, { hasType: (type) => hasBlock(sb.context, node, type), isRuntimeType: (innerOptions) => { @@ -470,27 +410,12 @@ export class ForBuiltinTypeHelper extends Helper { case Types.Transaction: this.transaction(options); break; - case Types.Output: - this.output(options); - break; case Types.Attribute: this.attribute(options); break; - case Types.Input: - this.input(options); - break; - case Types.Account: - this.account(options); - break; - case Types.Asset: - this.asset(options); - break; case Types.Contract: this.contract(options); break; - case Types.Header: - this.header(options); - break; case Types.Block: this.block(options); break; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/IsNullOrUndefinedHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/IsNullOrUndefinedHelper.ts index cc075710c6..f15424024d 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/IsNullOrUndefinedHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/IsNullOrUndefinedHelper.ts @@ -49,13 +49,8 @@ export class IsNullOrUndefinedHelper extends TypedHelper { iterable: pushFalse, iterableIterator: pushFalse, transaction: pushFalse, - output: pushFalse, attribute: pushFalse, - input: pushFalse, - account: pushFalse, - asset: pushFalse, contract: pushFalse, - header: pushFalse, block: pushFalse, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/ToPrimitiveHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/ToPrimitiveHelper.ts index 4d9d4e8523..f308ef8d4a 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/ToPrimitiveHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/ToPrimitiveHelper.ts @@ -122,13 +122,8 @@ export class ToPrimitiveHelper extends Helper { iterable: throwTypeError, iterableIterator: throwTypeError, transaction: throwTypeError, - output: throwTypeError, attribute: throwTypeError, - input: throwTypeError, - account: throwTypeError, - asset: throwTypeError, contract: throwTypeError, - header: throwTypeError, block: throwTypeError, }), ); @@ -169,13 +164,8 @@ export class ToPrimitiveHelper extends Helper { iterable: throwInnerTypeError, iterableIterator: throwInnerTypeError, transaction: throwInnerTypeError, - output: throwInnerTypeError, attribute: throwInnerTypeError, - input: throwInnerTypeError, - account: throwInnerTypeError, - asset: throwInnerTypeError, contract: throwInnerTypeError, - header: throwInnerTypeError, block: throwInnerTypeError, }), ); @@ -255,13 +245,8 @@ export class ToPrimitiveHelper extends Helper { iterable: toString(Types.Iterable), iterableIterator: toString(Types.IterableIterator), transaction: toString(Types.Transaction), - output: toString(Types.Output), attribute: toString(Types.Attribute), - input: toString(Types.Input), - account: toString(Types.Account), - asset: toString(Types.Asset), contract: toString(Types.Contract), - header: toString(Types.Header), block: toString(Types.Block), }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/UnwrapCopyStructHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/UnwrapCopyStructHelper.ts index edd95e8a65..148fa74d41 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/UnwrapCopyStructHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/UnwrapCopyStructHelper.ts @@ -19,7 +19,29 @@ export abstract class UnwrapCopyStructHelper extends UnwrapHelper { sb.emitOp(node, 'PICKITEM'); // [value] sb.emitOp(node, 'VALUES'); - // [value] + // [value, value] + sb.emitOp(node, 'DUP'); + // [size, value] + sb.emitOp(node, 'SIZE'); + // [struct, value] sb.emitOp(node, 'NEWSTRUCT'); + // [struct] + sb.emitHelper( + node, + options, + sb.helpers.arrReduce({ + withIndex: true, + each: () => { + // [accum, accum, val, idx] + sb.emitOp(node, 'DUP'); + // [idx, val, accum, accum] + sb.emitOp(node, 'REVERSE4'); + // [val, idx, accum, accum] + sb.emitOp(node, 'SWAP'); + // [accum] + sb.emitOp(node, 'SETITEM'); + }, + }), + ); } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/UnwrapValHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/UnwrapValHelper.ts index 0a09425c3e..c5cdd90ce6 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/UnwrapValHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/UnwrapValHelper.ts @@ -41,9 +41,6 @@ export class UnwrapValHelper extends Helper { case Types.ForwardValue: sb.emitHelper(node, options, sb.helpers.unwrapForwardValue); break; - case Types.Input: - sb.emitHelper(node, options, sb.helpers.unwrapInput); - break; case Types.IterableIterator: sb.emitHelper(node, options, sb.helpers.unwrapIterableIterator); break; @@ -62,9 +59,6 @@ export class UnwrapValHelper extends Helper { case Types.Object: sb.emitHelper(node, options, sb.helpers.unwrapObject); break; - case Types.Output: - sb.emitHelper(node, options, sb.helpers.unwrapOutput); - break; case Types.Set: sb.emitHelper(node, options, sb.helpers.unwrapSet); break; @@ -80,18 +74,9 @@ export class UnwrapValHelper extends Helper { case Types.Symbol: sb.emitHelper(node, options, sb.helpers.unwrapSymbol); break; - case Types.Account: - sb.emitHelper(node, options, sb.helpers.unwrapAccount); - break; - case Types.Asset: - sb.emitHelper(node, options, sb.helpers.unwrapAsset); - break; case Types.Contract: sb.emitHelper(node, options, sb.helpers.unwrapContract); break; - case Types.Header: - sb.emitHelper(node, options, sb.helpers.unwrapHeader); - break; case Types.Block: sb.emitHelper(node, options, sb.helpers.unwrapBlock); break; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/UnwrapValRecursiveHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/UnwrapValRecursiveHelper.ts index 99ced1b7eb..36149dbd92 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/UnwrapValRecursiveHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/UnwrapValRecursiveHelper.ts @@ -6,16 +6,19 @@ import { Helper } from '../Helper'; import { isOnlyMap } from './map'; export interface UnwrapValRecursiveHelperOptions { + readonly deserializeBeforeUnwrap?: boolean; readonly type: ts.Type | undefined; } // Input: [val] // Output: [value] export class UnwrapValRecursiveHelper extends Helper { + private readonly deserializeBeforeUnwrap: boolean; private readonly type: ts.Type | undefined; public constructor(options: UnwrapValRecursiveHelperOptions) { super(); this.type = options.type; + this.deserializeBeforeUnwrap = options.deserializeBeforeUnwrap ?? false; } public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { @@ -29,6 +32,9 @@ export class UnwrapValRecursiveHelper extends Helper { const type = tsUtils.type_.getNonNullableType(this.type); + if (this.deserializeBeforeUnwrap) { + sb.emitSysCall(node, 'System.Binary.Deserialize'); + } sb.emitHelper( node, options, @@ -122,7 +128,11 @@ export class UnwrapValRecursiveHelper extends Helper { localValueType === undefined ? undefined : sb.context.analysis.getNotAnyType(node, localValueType); } - sb.emitHelper(node, innerInnerOptions, sb.helpers.unwrapValRecursive({ type: keyType })); + sb.emitHelper( + node, + innerInnerOptions, + sb.helpers.unwrapValRecursive({ deserializeBeforeUnwrap: true, type: keyType }), + ); sb.emitOp(node, 'SWAP'); sb.emitHelper(node, innerInnerOptions, sb.helpers.unwrapValRecursive({ type: valueType })); sb.emitOp(node, 'SWAP'); @@ -164,27 +174,12 @@ export class UnwrapValRecursiveHelper extends Helper { transaction: (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.unwrapTransaction); }, - output: (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.unwrapOutput); - }, attribute: (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.unwrapAttribute); }, - input: (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.unwrapInput); - }, - account: (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.unwrapAccount); - }, - asset: (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.unwrapAsset); - }, contract: (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.unwrapContract); }, - header: (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.unwrapHeader); - }, block: (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.unwrapBlock); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/WrapHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/WrapHelper.ts index 434d06c6aa..9bfc18feaa 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/WrapHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/WrapHelper.ts @@ -4,7 +4,7 @@ import { ScriptBuilder } from '../../sb'; import { VisitOptions } from '../../types'; import { Helper } from '../Helper'; -// Input: [value] +// Input: [value] or [] // Output: [val] export abstract class WrapHelper extends Helper { protected readonly length: number = 2; @@ -19,10 +19,29 @@ export abstract class WrapHelper extends Helper { // [type, value] sb.emitPushInt(node, this.type); - // [2, type, value] + // [0, type, value] + sb.emitPushInt(node, 0); + // [2, 0, type, value] sb.emitPushInt(node, this.length); - // [[type, value]] - sb.emitOp(node, 'PACK'); + // [struct, 0, type, value] sb.emitOp(node, 'NEWSTRUCT'); + // [struct, struct, 0, type, value] + sb.emitOp(node, 'DUP'); + // [type, 0, struct, struct, value] + sb.emitOp(node, 'REVERSE4'); + // [[type, null], value] + sb.emitOp(node, 'SETITEM'); + if (this.length !== 1) { + // [[type, null], value, [type, null]] + sb.emitOp(node, 'TUCK'); + // [value, [type, null], [type, null]] + sb.emitOp(node, 'SWAP'); + // [1, value, [type, null], [type, null]] + sb.emitPushInt(node, 1); + // [value, 1, [type, null], [type, null]] + sb.emitOp(node, 'SWAP'); + // [[type, value]] + sb.emitOp(node, 'SETITEM'); + } } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/WrapValHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/WrapValHelper.ts index d02176e541..d31602b3d0 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/WrapValHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/WrapValHelper.ts @@ -41,9 +41,6 @@ export class WrapValHelper extends Helper { case Types.ForwardValue: sb.emitHelper(node, options, sb.helpers.wrapForwardValue); break; - case Types.Input: - sb.emitHelper(node, options, sb.helpers.wrapInput); - break; case Types.IteratorResult: sb.emitHelper(node, options, sb.helpers.wrapIteratorResult); break; @@ -62,9 +59,6 @@ export class WrapValHelper extends Helper { case Types.Object: sb.emitHelper(node, options, sb.helpers.wrapObject); break; - case Types.Output: - sb.emitHelper(node, options, sb.helpers.wrapOutput); - break; case Types.Set: sb.emitHelper(node, options, sb.helpers.wrapSet); break; @@ -80,18 +74,9 @@ export class WrapValHelper extends Helper { case Types.Symbol: sb.emitHelper(node, options, sb.helpers.wrapSymbol); break; - case Types.Account: - sb.emitHelper(node, options, sb.helpers.wrapAccount); - break; - case Types.Asset: - sb.emitHelper(node, options, sb.helpers.wrapAsset); - break; case Types.Contract: sb.emitHelper(node, options, sb.helpers.wrapContract); break; - case Types.Header: - sb.emitHelper(node, options, sb.helpers.wrapHeader); - break; case Types.Block: sb.emitHelper(node, options, sb.helpers.wrapBlock); break; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/WrapValRecursiveHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/WrapValRecursiveHelper.ts index 110c8e0361..0e080a23a4 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/WrapValRecursiveHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/WrapValRecursiveHelper.ts @@ -9,6 +9,7 @@ import { isAddress, isHash256, isPublicKey } from './buffer'; import { isOnlyMap } from './map'; export interface WrapValRecursiveHelperOptions { + readonly serializeFinalVal?: boolean; readonly checkValue?: boolean; readonly type: ts.Type | undefined; readonly optional?: boolean; @@ -17,6 +18,7 @@ export interface WrapValRecursiveHelperOptions { // Input: [val] // Output: [value] export class WrapValRecursiveHelper extends Helper { + private readonly serializeFinalVal: boolean; private readonly checkValue: boolean; private readonly type: ts.Type | undefined; private readonly optional?: boolean; @@ -26,6 +28,7 @@ export class WrapValRecursiveHelper extends Helper { this.checkValue = options.checkValue === undefined ? false : options.checkValue; this.type = options.type; this.optional = options.optional; + this.serializeFinalVal = options.serializeFinalVal ?? false; } public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { @@ -45,6 +48,9 @@ export class WrapValRecursiveHelper extends Helper { } body(innerOptions); + if (this.serializeFinalVal) { + sb.emitSysCall(node, 'System.Binary.Serialize'); + } }; const handleUndefined = createHandleValue(false, (innerOptions) => { @@ -243,6 +249,7 @@ export class WrapValRecursiveHelper extends Helper { node, innerInnerOptions, sb.helpers.wrapValRecursive({ + serializeFinalVal: true, checkValue: this.checkValue, type: keyType, }), @@ -289,27 +296,12 @@ export class WrapValRecursiveHelper extends Helper { transaction: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapTransaction); }), - output: createHandleValue(true, (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.wrapOutput); - }), attribute: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapAttribute); }), - input: createHandleValue(true, (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.wrapInput); - }), - account: createHandleValue(true, (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.wrapAccount); - }), - asset: createHandleValue(true, (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.wrapAsset); - }), contract: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapContract); }), - header: createHandleValue(true, (innerOptions) => { - sb.emitHelper(node, innerOptions, sb.helpers.wrapHeader); - }), block: createHandleValue(true, (innerOptions) => { sb.emitHelper(node, innerOptions, sb.helpers.wrapBlock); }), diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/account.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/account.ts deleted file mode 100644 index 3fa2c42bfe..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/account.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { tsUtils } from '@neo-one/ts-utils'; -import ts from 'typescript'; -import { Context } from '../../../Context'; -import { Types } from '../../constants'; -import { IsHelper } from './IsHelper'; -import { UnwrapHelper } from './UnwrapHelper'; -import { WrapHelper } from './WrapHelper'; - -export class UnwrapAccountHelper extends UnwrapHelper {} -export class WrapAccountHelper extends WrapHelper { - protected readonly type = Types.Account; -} -export class IsAccountHelper extends IsHelper { - protected readonly type = Types.Account; -} - -export const hasAccount = (context: Context, node: ts.Node, type: ts.Type): boolean => - tsUtils.type_.hasType(type, (tpe) => isAccount(context, node, tpe)); - -export const isOnlyAccount = (context: Context, node: ts.Node, type: ts.Type): boolean => - tsUtils.type_.isOnlyType(type, (tpe) => isAccount(context, node, tpe)); - -export const isAccount = (context: Context, node: ts.Node, type: ts.Type): boolean => - context.builtins.isInterface(node, type, 'Account'); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/array/ArrayLengthHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/array/ArrayLengthHelper.ts index 62287781a2..af5068e6e6 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/array/ArrayLengthHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/array/ArrayLengthHelper.ts @@ -16,6 +16,6 @@ export class ArrayLengthHelper extends Helper { // [arr] sb.emitHelper(node, options, sb.helpers.unwrapArray); // [length] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/array/GetArrayIndexHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/array/GetArrayIndexHelper.ts index 7c87baeea2..e62aa6b2fe 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/array/GetArrayIndexHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/array/GetArrayIndexHelper.ts @@ -21,7 +21,7 @@ export class GetArrayIndexHelper extends Helper { // [arr, indexNumber, arr] sb.emitOp(node, 'TUCK'); // [size, indexNumber, arr] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [indexNumber, size, indexNumber, arr] sb.emitOp(node, 'OVER'); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/array/SetArrayIndexHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/array/SetArrayIndexHelper.ts index e07b402408..062e3bec86 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/array/SetArrayIndexHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/array/SetArrayIndexHelper.ts @@ -12,10 +12,12 @@ export class SetArrayIndexHelper extends Helper { sb.emitOp(node, 'ROT'); // [arr, val, indexNumber] sb.emitHelper(node, options, sb.helpers.unwrapArray); - // [3, arr, val, indexNumber] - sb.emitPushInt(node, 3); + // [arr, arr, val, indexNumber] + sb.emitOp(node, 'DUP'); + // [indexNumber, val, arr, arr] + sb.emitOp(node, 'REVERSE4'); // [arr, val, indexNumber, arr] - sb.emitOp(node, 'XTUCK'); + sb.emitOp(node, 'REVERSE3'); // [2, arr, val, indexNumber, arr] sb.emitPushInt(node, 2); // [indexNumber, arr, val, indexNumber, arr] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/asset.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/asset.ts deleted file mode 100644 index 4fe01eb800..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/asset.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { tsUtils } from '@neo-one/ts-utils'; -import ts from 'typescript'; -import { Context } from '../../../Context'; -import { Types } from '../../constants'; -import { IsHelper } from './IsHelper'; -import { UnwrapHelper } from './UnwrapHelper'; -import { WrapHelper } from './WrapHelper'; - -export class UnwrapAssetHelper extends UnwrapHelper {} -export class WrapAssetHelper extends WrapHelper { - protected readonly type = Types.Asset; -} -export class IsAssetHelper extends IsHelper { - protected readonly type = Types.Asset; -} - -export const hasAsset = (context: Context, node: ts.Node, type: ts.Type): boolean => - tsUtils.type_.hasType(type, (tpe) => isAsset(context, node, tpe)); - -export const isOnlyAsset = (context: Context, node: ts.Node, type: ts.Type): boolean => - tsUtils.type_.isOnlyType(type, (tpe) => isAsset(context, node, tpe)); - -export const isAsset = (context: Context, node: ts.Node, type: ts.Type): boolean => - context.builtins.isInterface(node, type, 'Asset'); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/attribute/typeTests.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/attribute/typeTests.ts index c019791e32..be64bd55d6 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/attribute/typeTests.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/attribute/typeTests.ts @@ -10,8 +10,5 @@ export const isOnlyAttribute = (context: Context, node: ts.Node, type: ts.Type): export const isAttribute = (context: Context, node: ts.Node, type: ts.Type): boolean => context.builtins.isInterface(node, type, 'AttributeBase') || - context.builtins.isInterface(node, type, 'BufferAttribute') || - context.builtins.isInterface(node, type, 'PublicKeyAttribute') || - context.builtins.isInterface(node, type, 'AddressAttribute') || - context.builtins.isInterface(node, type, 'Hash256Attribute') || + context.builtins.isInterface(node, type, 'HighPriorityAttribute') || context.builtins.isType(node, type, 'Attribute'); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/boolean/ToBooleanHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/boolean/ToBooleanHelper.ts index b7075a56c3..f0fa11d813 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/boolean/ToBooleanHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/boolean/ToBooleanHelper.ts @@ -68,13 +68,8 @@ export class ToBooleanHelper extends TypedHelper { iterable: convertOther, iterableIterator: convertOther, transaction: convertOther, - output: convertOther, attribute: convertOther, - input: convertOther, - account: convertOther, - asset: convertOther, contract: convertOther, - header: convertOther, block: convertOther, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/boolean/ToNullishBooleanHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/boolean/ToNullishBooleanHelper.ts index 1defeb2d39..f32aefcc44 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/boolean/ToNullishBooleanHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/boolean/ToNullishBooleanHelper.ts @@ -51,13 +51,8 @@ export class ToNullishBooleanHelper extends TypedHelper { iterable: convertOther, iterableIterator: convertOther, transaction: convertOther, - output: convertOther, attribute: convertOther, - input: convertOther, - account: convertOther, - asset: convertOther, contract: convertOther, - header: convertOther, block: convertOther, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/getHasBuiltins.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/getHasBuiltins.ts index a8508cc64e..258a82d1ea 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/getHasBuiltins.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/getHasBuiltins.ts @@ -1,15 +1,10 @@ import ts from 'typescript'; import { Context } from '../../../Context'; -import { hasAccount } from './account'; import { hasArray } from './array'; -import { hasAsset } from './asset'; import { hasAttribute } from './attribute'; import { hasBlock } from './block'; import { hasBuffer } from './buffer'; import { hasContract } from './contract'; -import { hasHeader } from './header'; -import { hasInput } from './input'; -import { hasOutput } from './output'; import { hasTransaction } from './transaction'; type HasBuiltin = (context: Context, arg: ts.Node, argType: ts.Type) => boolean; @@ -18,14 +13,9 @@ const hasBuiltins: ReadonlyArray = [ hasArray, hasAttribute, hasBuffer, - hasInput, - hasOutput, hasTransaction, - hasAccount, - hasAsset, hasBlock, hasContract, - hasHeader, ]; export function getHasBuiltins(context: Context, node: ts.Node, type: ts.Type): ReadonlyArray { diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/header.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/header.ts deleted file mode 100644 index 1577de1515..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/header.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { tsUtils } from '@neo-one/ts-utils'; -import ts from 'typescript'; -import { Context } from '../../../Context'; -import { Types } from '../../constants'; -import { IsHelper } from './IsHelper'; -import { UnwrapHelper } from './UnwrapHelper'; -import { WrapHelper } from './WrapHelper'; - -export class UnwrapHeaderHelper extends UnwrapHelper {} -export class WrapHeaderHelper extends WrapHelper { - protected readonly type = Types.Header; -} -export class IsHeaderHelper extends IsHelper { - protected readonly type = Types.Header; -} - -export const hasHeader = (context: Context, node: ts.Node, type: ts.Type): boolean => - tsUtils.type_.hasType(type, (tpe) => isHeader(context, node, tpe)); - -export const isOnlyHeader = (context: Context, node: ts.Node, type: ts.Type): boolean => - tsUtils.type_.isOnlyType(type, (tpe) => isHeader(context, node, tpe)); - -export const isHeader = (context: Context, node: ts.Node, type: ts.Type): boolean => - context.builtins.isInterface(node, type, 'Header'); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/index.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/index.ts index 83af4b6953..f8bdc3e282 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/index.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/index.ts @@ -5,7 +5,6 @@ export * from './boolean'; export * from './buffer'; export * from './error'; export * from './forwardValue'; -export * from './input'; export * from './iterable'; export * from './iteratorResult'; export * from './iterableIterator'; @@ -16,7 +15,6 @@ export * from './setStorage'; export * from './null'; export * from './number'; export * from './object'; -export * from './output'; export * from './string'; export * from './symbol'; export * from './transaction'; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/IsInputHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/IsInputHelper.ts deleted file mode 100644 index 9cf94a31b1..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/IsInputHelper.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Types } from '../../../constants'; -import { IsHelper } from '../IsHelper'; - -// Input: [val] -// Output: [boolean] -export class IsInputHelper extends IsHelper { - protected readonly type = Types.Input; -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/UnwrapInputHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/UnwrapInputHelper.ts deleted file mode 100644 index 9f0adfa281..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/UnwrapInputHelper.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { UnwrapHelper } from '../UnwrapHelper'; - -// Input: [arrayVal] -// Output: [arr] -export class UnwrapInputHelper extends UnwrapHelper {} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/WrapInputHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/WrapInputHelper.ts deleted file mode 100644 index a7d4dba4d6..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/WrapInputHelper.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Types } from '../../../constants'; -import { WrapHelper } from '../WrapHelper'; - -// Input: [attr] -// Output: [attrVal] -export class WrapInputHelper extends WrapHelper { - protected readonly type = Types.Input; -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/index.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/index.ts deleted file mode 100644 index 217d73fba1..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './IsInputHelper'; -export * from './UnwrapInputHelper'; -export * from './WrapInputHelper'; - -export * from './typeTests'; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/typeTests.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/typeTests.ts deleted file mode 100644 index 8b72c5ce28..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/input/typeTests.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { tsUtils } from '@neo-one/ts-utils'; -import ts from 'typescript'; -import { Context } from '../../../../Context'; - -export const hasInput = (context: Context, node: ts.Node, type: ts.Type): boolean => - tsUtils.type_.hasType(type, (tpe) => isInput(context, node, tpe)); - -export const isOnlyInput = (context: Context, node: ts.Node, type: ts.Type): boolean => - tsUtils.type_.isOnlyType(type, (tpe) => isInput(context, node, tpe)); - -export const isInput = (context: Context, node: ts.Node, type: ts.Type): boolean => - context.builtins.isInterface(node, type, 'Input'); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/number/ToNumberHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/number/ToNumberHelper.ts index 73f080fe65..dc18351bcb 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/number/ToNumberHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/number/ToNumberHelper.ts @@ -1,3 +1,4 @@ +import { StackItemType } from '@neo-one/client-common'; import ts from 'typescript'; import { Types } from '../../../constants'; import { ScriptBuilder } from '../../../sb'; @@ -120,12 +121,16 @@ export class ToNumberHelper extends TypedHelper { sb.emitOp(node, 'DEC'); // [nextRemain, remain] sb.emitOp(node, 'LEFT'); + // [nextRemain, remain] + sb.emitOp(node, 'CONVERT', Buffer.from([StackItemType.ByteString])); // [remain] sb.scope.set(sb, node, innerOptions, remain); // [1, remain] sb.emitPushInt(node, 1); // [char] sb.emitOp(node, 'RIGHT'); + // [char] + sb.emitOp(node, 'CONVERT', Buffer.from([StackItemType.ByteString])); // [0x30, char] sb.emitPushInt(node, 0x30); // [char - 0x30] @@ -242,13 +247,8 @@ export class ToNumberHelper extends TypedHelper { iterable: throwTypeError, iterableIterator: throwTypeError, transaction: throwTypeError, - output: throwTypeError, attribute: throwTypeError, - input: throwTypeError, - account: throwTypeError, - asset: throwTypeError, contract: throwTypeError, - header: throwTypeError, block: throwTypeError, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/FindObjectPropertyHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/FindObjectPropertyHelper.ts index 7fb58d239f..d1d6695bce 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/FindObjectPropertyHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/FindObjectPropertyHelper.ts @@ -50,7 +50,7 @@ export class FindObjectPropertyHelper extends Helper { sb.helpers.if({ condition: () => { // [size, propVal] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [2, size, propVal] sb.emitPushInt(node, 2); // [size === 2, propVal] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/FindObjectPropertyHelperBase.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/FindObjectPropertyHelperBase.ts index 26a60016b1..0da199e744 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/FindObjectPropertyHelperBase.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/FindObjectPropertyHelperBase.ts @@ -1,3 +1,4 @@ +import { StackItemType } from '@neo-one/client-common'; import ts from 'typescript'; import { ScriptBuilder } from '../../../sb'; @@ -31,6 +32,8 @@ export class FindObjectPropertyHelperBase extends Helper { return; } + // [prop, objectVal] + sb.emitOp(node, 'CONVERT', Buffer.from([StackItemType.ByteString])); // [objectVal, prop] sb.emitOp(node, 'SWAP'); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/OmitObjectPropertiesHelperBase.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/OmitObjectPropertiesHelperBase.ts index c22bf191fd..99ca1e8a76 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/OmitObjectPropertiesHelperBase.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/OmitObjectPropertiesHelperBase.ts @@ -1,3 +1,4 @@ +import { StackItemType } from '@neo-one/client-common'; import ts from 'typescript'; import { ScriptBuilder } from '../../../sb'; @@ -25,6 +26,8 @@ export abstract class OmitObjectPropertiesHelperBase extends Helper { sb.emitHelper(node, options, this.getObject(sb)); // [string, obj] sb.emitOp(node, 'SWAP'); + // [string, obj] + sb.emitOp(node, 'CONVERT', Buffer.from([StackItemType.ByteString])); // [] sb.emitOp(node, 'REMOVE'); }, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/PickObjectPropertiesHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/PickObjectPropertiesHelper.ts index 67159a64fd..c32017c2ed 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/PickObjectPropertiesHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/PickObjectPropertiesHelper.ts @@ -22,10 +22,14 @@ export class PickObjectPropertiesHelper extends Helper { sb.emitHelper(node, options, sb.helpers.pickPropertyObjectProperties); // [outputObjectVal, outputObjectVal, symbolArr, objectVal] sb.emitOp(node, 'DUP'); - // [3, outputObjectVal, outputObjectVal, symbolArr, objectVal] + // [symbolArr, outputObjectVal, outputObjectVal, objectVal] + sb.emitOp(node, 'ROT'); + // [outputObjectVal, symbolArr, outputObjectVal, objectVal] + sb.emitOp(node, 'ROT'); + // [3, outputObjectVal, symbolArr, outputObjectVal, objectVal] sb.emitPushInt(node, 3); // [objectVal, outputObjectVal, symbolArr, outputObjectVal] - sb.emitOp(node, 'XSWAP'); + sb.emitOp(node, 'ROLL'); // [symbolArr, objectVal, outputObjectVal, outputObjectVal] sb.emitOp(node, 'ROT'); // [outputObjectVal] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/SetObjectDataPropertyHelperBase.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/SetObjectDataPropertyHelperBase.ts index 521e53c1e2..81fa76b652 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/SetObjectDataPropertyHelperBase.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/SetObjectDataPropertyHelperBase.ts @@ -1,3 +1,4 @@ +import { StackItemType } from '@neo-one/client-common'; import ts from 'typescript'; import { ScriptBuilder } from '../../../sb'; @@ -14,6 +15,8 @@ export abstract class SetObjectDataPropertyHelperBase extends Helper { sb.emitHelper(node, sb.pushValueOptions(options), this.getObject(sb)); // [stringProp, obj, val] sb.emitOp(node, 'ROT'); + // [stringProp, obj, val] + sb.emitOp(node, 'CONVERT', Buffer.from([StackItemType.ByteString])); // [val, stringProp, obj] sb.emitOp(node, 'ROT'); // [1, val, stringProp, obj] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/ToObjectHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/ToObjectHelper.ts index 2b6781949f..5c4be7ceb6 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/ToObjectHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/ToObjectHelper.ts @@ -54,13 +54,8 @@ export class ToObjectHelper extends TypedHelper { iterable: emptyObject, iterableIterator: emptyObject, transaction: emptyObject, - output: emptyObject, attribute: emptyObject, - input: emptyObject, - account: emptyObject, - asset: emptyObject, contract: emptyObject, - header: emptyObject, block: emptyObject, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/typeTests.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/typeTests.ts index c2891d648c..ad4130f90a 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/typeTests.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/object/typeTests.ts @@ -8,7 +8,6 @@ import { isBoolean } from '../boolean'; import { isBuffer } from '../buffer'; import { isError } from '../error'; import { isForwardValue } from '../forwardValue'; -import { isInput } from '../input'; import { isIterable } from '../iterable'; import { isIterableIterator } from '../iterableIterator'; import { isIteratorResult } from '../iteratorResult'; @@ -16,7 +15,6 @@ import { isMap } from '../map'; import { isMapStorage } from '../mapStorage'; import { isNull } from '../null'; import { isNumber } from '../number'; -import { isOutput } from '../output'; import { isSet } from '../set'; import { isSetStorage } from '../setStorage'; import { isString } from '../string'; @@ -52,6 +50,4 @@ export const isObject = (context: Context, node: ts.Node, type: ts.Type): boolea !isIterable(context, node, type) && !isIterableIterator(context, node, type) && !isTransaction(context, node, type) && - !isOutput(context, node, type) && - !isAttribute(context, node, type) && - !isInput(context, node, type); + !isAttribute(context, node, type); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/IsOutputHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/IsOutputHelper.ts deleted file mode 100644 index 9e9bd3cdc5..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/IsOutputHelper.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Types } from '../../../constants'; -import { IsHelper } from '../IsHelper'; - -// Input: [val] -// Output: [boolean] -export class IsOutputHelper extends IsHelper { - protected readonly type = Types.Output; -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/UnwrapOutputHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/UnwrapOutputHelper.ts deleted file mode 100644 index 7885eb697e..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/UnwrapOutputHelper.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { UnwrapHelper } from '../UnwrapHelper'; - -// Input: [arrayVal] -// Output: [arr] -export class UnwrapOutputHelper extends UnwrapHelper {} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/WrapOutputHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/WrapOutputHelper.ts deleted file mode 100644 index 0e620b7a2b..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/WrapOutputHelper.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Types } from '../../../constants'; -import { WrapHelper } from '../WrapHelper'; - -// Input: [attr] -// Output: [attrVal] -export class WrapOutputHelper extends WrapHelper { - protected readonly type = Types.Output; -} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/index.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/index.ts deleted file mode 100644 index 8fb1c192f6..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './IsOutputHelper'; -export * from './UnwrapOutputHelper'; -export * from './WrapOutputHelper'; - -export * from './typeTests'; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/typeTests.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/typeTests.ts deleted file mode 100644 index 89b33ed020..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/output/typeTests.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { tsUtils } from '@neo-one/ts-utils'; -import ts from 'typescript'; -import { Context } from '../../../../Context'; - -export const hasOutput = (context: Context, node: ts.Node, type: ts.Type): boolean => - tsUtils.type_.hasType(type, (tpe) => isOutput(context, node, tpe)); - -export const isOnlyOutput = (context: Context, node: ts.Node, type: ts.Type): boolean => - tsUtils.type_.isOnlyType(type, (tpe) => isOutput(context, node, tpe)); - -export const isOutput = (context: Context, node: ts.Node, type: ts.Type): boolean => - context.builtins.isInterface(node, type, 'Output'); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/string/ToStringHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/string/ToStringHelper.ts index 821da535bb..e61b154e7b 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/string/ToStringHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/string/ToStringHelper.ts @@ -197,13 +197,8 @@ export class ToStringHelper extends TypedHelper { iterable: convertEmptyString, iterableIterator: convertEmptyString, transaction: convertEmptyString, - output: convertEmptyString, attribute: convertEmptyString, - input: convertEmptyString, - account: convertEmptyString, - asset: convertEmptyString, contract: convertEmptyString, - header: convertEmptyString, block: convertEmptyString, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/transaction/typeTests.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/transaction/typeTests.ts index f93bc74a08..040fbf7334 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/types/transaction/typeTests.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/types/transaction/typeTests.ts @@ -9,14 +9,4 @@ export const isOnlyTransaction = (context: Context, node: ts.Node, type: ts.Type tsUtils.type_.isOnlyType(type, (tpe) => isTransaction(context, node, tpe)); export const isTransaction = (context: Context, node: ts.Node, type: ts.Type): boolean => - context.builtins.isInterface(node, type, 'TransactionBase') || - context.builtins.isInterface(node, type, 'MinerTransaction') || - context.builtins.isInterface(node, type, 'IssueTransaction') || - context.builtins.isInterface(node, type, 'ClaimTransaction') || - context.builtins.isInterface(node, type, 'EnrollmentTransaction') || - context.builtins.isInterface(node, type, 'RegisterTransaction') || - context.builtins.isInterface(node, type, 'ContractTransaction') || - context.builtins.isInterface(node, type, 'StateTransaction') || - context.builtins.isInterface(node, type, 'PublishTransaction') || - context.builtins.isInterface(node, type, 'InvocationTransaction') || - context.builtins.isType(node, type, 'Transaction'); + context.builtins.isInterface(node, type, 'Transaction'); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/pc/Call.ts b/packages/neo-one-smart-contract-compiler/src/compile/pc/Call.ts index 006949d6c6..ba0c7bcaff 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/pc/Call.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/pc/Call.ts @@ -3,7 +3,7 @@ import { ProgramCounter } from './ProgramCounter'; export class Call extends Jump { public constructor(pc: ProgramCounter) { - super('CALL', pc); + super('CALL_L', pc); } public plus(pc: number): Call { diff --git a/packages/neo-one-smart-contract-compiler/src/compile/pc/Jmp.ts b/packages/neo-one-smart-contract-compiler/src/compile/pc/Jmp.ts index 77b1559e78..303010fd77 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/pc/Jmp.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/pc/Jmp.ts @@ -1,7 +1,16 @@ import { Jump } from './Jump'; import { ProgramCounter } from './ProgramCounter'; -export type JmpOp = 'JMP' | 'JMPIF' | 'JMPIFNOT'; +export type JmpOp = + | 'JMP_L' + | 'JMPIF_L' + | 'JMPIFNOT_L' + | 'JMPEQ_L' + | 'JMPNE_L' + | 'JMPGT_L' + | 'JMPGE_L' + | 'JMPLT_L' + | 'JMPLE_L'; export class Jmp extends Jump { public constructor(op: JmpOp, pc: ProgramCounter) { diff --git a/packages/neo-one-smart-contract-compiler/src/compile/pc/Jump.ts b/packages/neo-one-smart-contract-compiler/src/compile/pc/Jump.ts index d0c9467c04..c058d23929 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/pc/Jump.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/pc/Jump.ts @@ -1,6 +1,7 @@ +import { JmpOp } from './Jmp'; import { ProgramCounter } from './ProgramCounter'; -export type JumpOp = 'CALL' | 'JMP' | 'JMPIF' | 'JMPIFNOT'; +export type JumpOp = 'CALL_L' | JmpOp; export abstract class Jump { public constructor(public readonly op: TOp, public readonly pc: ProgramCounter) {} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/sb/BaseScriptBuilder.ts b/packages/neo-one-smart-contract-compiler/src/compile/sb/BaseScriptBuilder.ts index 735a4cb442..80570ab313 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/sb/BaseScriptBuilder.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/sb/BaseScriptBuilder.ts @@ -1,15 +1,14 @@ import { assertSysCall, - BinaryWriter, ByteBuffer, ByteCode, common, crypto, + getSysCallHash, Op, OpCode, ScriptBuilder as ClientScriptBuilder, SysCallName, - toSysCallHash, UInt160, UnknownOpError, utils, @@ -28,10 +27,10 @@ import { expressions } from '../expression'; import { files } from '../file'; import { Helper, Helpers } from '../helper'; import { NodeCompiler } from '../NodeCompiler'; -import { Call, DeferredProgramCounter, Jmp, Jump, Line, ProgramCounter, ProgramCounterHelper } from '../pc'; +import { Call, DeferredProgramCounter, Jmp, JmpOp, Jump, Line, ProgramCounter, ProgramCounterHelper } from '../pc'; import { Name, Scope } from '../scope'; import { statements } from '../statement'; -import { Features, HandleSuperConstruct, LinkedContracts, ScriptBuilderResult, VisitOptions } from '../types'; +import { HandleSuperConstruct, LinkedContracts, ScriptBuilderResult, VisitOptions } from '../types'; import { JumpTable } from './JumpTable'; import { resolveJumps } from './resolveJumps'; import { Bytecode, CaptureResult, ScriptBuilder, SingleBytecode, SingleBytecodeValue, Tags } from './ScriptBuilder'; @@ -57,7 +56,6 @@ export abstract class BaseScriptBuilder implements ScriptB private readonly mutableExportMap: { [K in string]?: Set } = {}; private mutableNextModuleIndex = 0; private mutableCurrentModuleIndex = 0; - private mutableFeatures: Features = { dynamicInvoke: false }; public constructor( public readonly context: Context, @@ -160,7 +158,11 @@ export abstract class BaseScriptBuilder implements ScriptB public getFinalResult(sourceMaps: { readonly [filePath: string]: RawSourceMap }): ScriptBuilderResult { this.withProgramCounter((programCounter) => { - this.emitJmp(this.sourceFile, 'JMP', programCounter.getLast()); + // Initialize static fields for scope tracking + this.emitOp(this.sourceFile, 'INITSSLOT', Buffer.from([0xff])); // TODO: currently only using a single slot, not all + this.emitOp(this.sourceFile, 'NEWARRAY0'); + this.emitOp(this.sourceFile, 'STSFLD0'); + this.emitJmp(this.sourceFile, 'JMP_L', programCounter.getLast()); this.jumpTablePC.setPC(programCounter.getCurrent()); this.jumpTable.emitTable(this, this.sourceFile); }); @@ -177,19 +179,19 @@ export abstract class BaseScriptBuilder implements ScriptB const buffers = bytecode.map(([node, tags, value], idx) => { let finalValue: Buffer; if (value instanceof Jump) { - let jumpPCBuffer = Buffer.alloc(2, 0); + let jumpPCBuffer = Buffer.alloc(4, 0); const offsetPC = new BN(value.pc.getPC()).sub(new BN(pc)); - const jumpPC = offsetPC.toTwos(16); + const jumpPC = offsetPC.toTwos(32); try { - if (jumpPC.fromTwos(16).toNumber() !== value.pc.getPC() - pc) { + if (jumpPC.fromTwos(32).toNumber() !== value.pc.getPC() - pc) { /* istanbul ignore next */ throw new Error( `Something went wrong, expected 2's complement of ${value.pc.getPC() - pc}, found: ${jumpPC - .fromTwos(16) + .fromTwos(32) .toNumber()}`, ); } - jumpPCBuffer = jumpPC.toArrayLike(Buffer, 'le', 2); + jumpPCBuffer = jumpPC.toArrayLike(Buffer, 'le', 4); } catch { this.context.reportError( node, @@ -205,7 +207,7 @@ export abstract class BaseScriptBuilder implements ScriptB finalValue = Buffer.concat([byteCodeBuffer, jumpPCBuffer]); } else if (value instanceof Line) { const currentLine = new BN(idx + 1); - const byteCodeBuffer = ByteBuffer[Op.PUSHBYTES4]; + const byteCodeBuffer = ByteBuffer[Op.PUSHINT32]; finalValue = Buffer.concat([byteCodeBuffer, currentLine.toArrayLike(Buffer, 'le', 4)]); } else { finalValue = value; @@ -252,7 +254,6 @@ export abstract class BaseScriptBuilder implements ScriptB return { code: Buffer.concat(buffers), sourceMap, - features: this.mutableFeatures, }; } @@ -288,13 +289,6 @@ export abstract class BaseScriptBuilder implements ScriptB } public emitOp(node: ts.Node, code: OpCode, buffer?: Buffer | undefined): void { - if ( - ((code === 'APPCALL' || code === 'TAILCALL') && buffer !== undefined && buffer.equals(Buffer.alloc(20, 0))) || - code === 'CALL_ED' - ) { - this.mutableFeatures = { ...this.mutableFeatures, dynamicInvoke: true }; - } - const bytecode = Op[code] as Op | undefined; if (bytecode === undefined) { /* istanbul ignore next */ @@ -305,15 +299,43 @@ export abstract class BaseScriptBuilder implements ScriptB public emitPushInt(node: ts.Node, valueIn: number | BN): void { const value = new BN(valueIn); - if (value.eq(utils.NEGATIVE_ONE)) { - this.emitOp(node, 'PUSHM1'); - } else if (value.eq(utils.ZERO)) { - this.emitPush(node, utils.toSignedBuffer(value)); - } else if (value.gt(utils.ZERO) && value.lt(utils.SIXTEEN)) { - this.emitOpByte(node, Op.PUSH1 - 1 + value.toNumber()); - } else { - this.emitPush(node, utils.toSignedBuffer(value)); + if (value.gte(utils.NEGATIVE_ONE) && value.lte(utils.SIXTEEN)) { + this.emitOpByte(node, Op.PUSH0 + value.toNumber()); + + return; + } + const data = utils.toSignedBuffer(value); + if (data.length === 1) { + this.emitOp(node, 'PUSHINT8', data); + + return; + } + if (data.length === 2) { + this.emitOp(node, 'PUSHINT16', data); + + return; + } + if (data.length <= 4) { + this.emitOp(node, 'PUSHINT32', value.toArrayLike(Buffer, 'le', 4)); + + return; + } + if (data.length <= 8) { + this.emitOp(node, 'PUSHINT64', value.toArrayLike(Buffer, 'le', 8)); + + return; + } + if (data.length <= 16) { + this.emitOp(node, 'PUSHINT128', value.toArrayLike(Buffer, 'le', 16)); + + return; } + if (data.length <= 32) { + this.emitOp(node, 'PUSHINT256', value.toArrayLike(Buffer, 'le', 32)); + + return; + } + throw new Error('Invalid buffer length'); } public emitPushBoolean(node: ts.Node, value: boolean): void { @@ -328,7 +350,7 @@ export abstract class BaseScriptBuilder implements ScriptB this.emitPush(node, value); } - public emitJmp(node: ts.Node, code: 'JMP' | 'JMPIF' | 'JMPIFNOT', pc: ProgramCounter): void { + public emitJmp(node: ts.Node, code: JmpOp, pc: ProgramCounter): void { this.emitJump(node, new Jmp(code, pc)); } @@ -365,11 +387,15 @@ export abstract class BaseScriptBuilder implements ScriptB } public emitSysCall(node: ts.Node, name: SysCallName): void { - const sysCallBuffer = Buffer.allocUnsafe(4); - sysCallBuffer.writeUInt32LE(toSysCallHash(assertSysCall(name)), 0); - const writer = new BinaryWriter(); - writer.writeVarBytesLE(sysCallBuffer); - this.emitOp(node, 'SYSCALL', writer.toBuffer()); + // TODO: check. commented out was Dan's change + // const sysCallBuffer = Buffer.allocUnsafe(4); + // sysCallBuffer.writeUInt32LE(toSysCallHash(assertSysCall(name)), 0); + // const writer = new BinaryWriter(); + // writer.writeVarBytesLE(sysCallBuffer); + // this.emitOp(node, 'SYSCALL', writer.toBuffer()); + + const hash = getSysCallHash(assertSysCall(name)); + this.emitOp(node, 'SYSCALL', hash); } public emitLine(node: ts.Node): void { @@ -562,14 +588,12 @@ export abstract class BaseScriptBuilder implements ScriptB } private emitPush(node: ts.Node, value: Buffer): void { - if (value.length <= Op.PUSHBYTES75) { - this.emitOpByte(node, value.length, value); - } else if (value.length < 0x100) { - this.emitOp(node, 'PUSHDATA1', new ClientScriptBuilder().emitUInt8(value.length).emit(value).build()); + if (value.length < 0x100) { + this.emitOp(node, 'PUSHDATA1', new ClientScriptBuilder().emitUInt8(value.length).emitRaw(value).build()); } else if (value.length < 0x10000) { - this.emitOp(node, 'PUSHDATA2', new ClientScriptBuilder().emitUInt16LE(value.length).emit(value).build()); + this.emitOp(node, 'PUSHDATA2', new ClientScriptBuilder().emitUInt16LE(value.length).emitRaw(value).build()); } else if (value.length < 0x100000000) { - this.emitOp(node, 'PUSHDATA4', new ClientScriptBuilder().emitUInt32LE(value.length).emit(value).build()); + this.emitOp(node, 'PUSHDATA4', new ClientScriptBuilder().emitUInt32LE(value.length).emitRaw(value).build()); } else { throw new Error('Value too large.'); } @@ -591,7 +615,7 @@ export abstract class BaseScriptBuilder implements ScriptB private emitJump(node: ts.Node, jump: Jump, tags: Tags = this.mutableCurrentTags): void { this.push(node, tags, jump); - this.mutablePC += 3; + this.mutablePC += 5; } private emitLineRaw(node: ts.Node, line: Line, tags: Tags = this.mutableCurrentTags): void { diff --git a/packages/neo-one-smart-contract-compiler/src/compile/sb/JumpTable.ts b/packages/neo-one-smart-contract-compiler/src/compile/sb/JumpTable.ts index 2553ccebcf..6fe5b6fc41 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/sb/JumpTable.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/sb/JumpTable.ts @@ -42,6 +42,6 @@ export class JumpTable { ); }); - sb.emitOp(outerNode, 'THROW'); + sb.emitOp(outerNode, 'ABORT'); } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/sb/ScriptBuilder.ts b/packages/neo-one-smart-contract-compiler/src/compile/sb/ScriptBuilder.ts index 4100350575..0b9fda59d0 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/sb/ScriptBuilder.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/sb/ScriptBuilder.ts @@ -4,7 +4,7 @@ import { BN } from 'bn.js'; import ts from 'typescript'; import { Context } from '../../Context'; import { Helper, Helpers } from '../helper'; -import { Jump, Line, ProgramCounter, ProgramCounterHelper } from '../pc'; +import { JmpOp, Jump, Line, ProgramCounter, ProgramCounterHelper } from '../pc'; import { Name, Scope } from '../scope'; import { HandleSuperConstruct, VisitOptions } from '../types'; import { JumpTable } from './JumpTable'; @@ -34,7 +34,7 @@ export interface ScriptBuilder { readonly emitPushBoolean: (node: ts.Node, value: boolean) => void; readonly emitPushString: (node: ts.Node, value: string) => void; readonly emitPushBuffer: (node: ts.Node, value: Buffer) => void; - readonly emitJmp: (node: ts.Node, code: 'JMP' | 'JMPIF' | 'JMPIFNOT', pc: ProgramCounter) => void; + readonly emitJmp: (node: ts.Node, code: JmpOp, pc: ProgramCounter) => void; readonly emitHelper: (node: T, options: VisitOptions, helper: Helper) => void; readonly emitBytecode: (bytecode: Bytecode) => void; readonly emitCall: (node: ts.Node) => void; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/sb/resolveJumps.ts b/packages/neo-one-smart-contract-compiler/src/compile/sb/resolveJumps.ts index 6fdde6e452..92ea3e1765 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/sb/resolveJumps.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/sb/resolveJumps.ts @@ -1,10 +1,10 @@ import ts from 'typescript'; -import { Call, Jmp, Jump, Line } from '../pc'; +import { Call, Jmp, Jump, JumpOp, Line } from '../pc'; import { KnownProgramCounter } from '../pc/KnownProgramCounter'; import { Bytecode, SingleBytecode, Tags } from './ScriptBuilder'; -// const MAX_JUMP = 32767; -const MAX_JUMP = 32000; +// const MAX_JUMP = 2147483647; // (2^32) - 1 +const MAX_JUMP = 2147483000; abstract class CodePoint { public abstract readonly length: number; @@ -55,10 +55,10 @@ abstract class CodePoint { } class JumpCodePoint extends CodePoint { - public readonly length = 3; + public readonly length = 5; private mutableTarget: CodePoint | undefined; - public constructor(node: ts.Node, tags: Tags, public readonly type: 'JMP' | 'JMPIF' | 'JMPIFNOT' | 'CALL') { + public constructor(node: ts.Node, tags: Tags, public readonly type: JumpOp) { super(node, tags); } @@ -258,7 +258,7 @@ const getBytecode = (first: CodePoint): Bytecode => { while (current !== undefined) { if (current instanceof JumpCodePoint) { const pc = getTargetPC(current, current.target); - if (current.type === 'CALL') { + if (current.type === 'CALL_L') { mutableOut.push([current.node, current.tags, new Call(pc)]); } else { mutableOut.push([current.node, current.tags, new Jmp(current.type, pc)]); @@ -267,22 +267,22 @@ const getBytecode = (first: CodePoint): Bytecode => { mutableOut.push([current.node, current.tags, current.value]); } else if (current instanceof JumpStationCodePoint) { const target = current.target; - const reverseTarget = new Jmp('JMP', getTargetPC(current, current.reverseTarget)); + const reverseTarget = new Jmp('JMP_L', getTargetPC(current, current.reverseTarget)); if (target === undefined) { mutableOut.push([ current.node, current.tags, - new Jmp('JMP', new KnownProgramCounter(current.pc + current.length)), + new Jmp('JMP_L', new KnownProgramCounter(current.pc + current.length)), ]); mutableOut.push([current.node, current.tags, reverseTarget]); } else { mutableOut.push([ current.node, current.tags, - new Jmp('JMP', new KnownProgramCounter(current.pc + current.length)), + new Jmp('JMP_L', new KnownProgramCounter(current.pc + current.length)), ]); mutableOut.push([current.node, current.tags, reverseTarget]); - mutableOut.push([current.node, current.tags, new Jmp('JMP', getTargetPC(current, target))]); + mutableOut.push([current.node, current.tags, new Jmp('JMP_L', getTargetPC(current, target))]); } } else if (current instanceof LineCodePoint) { mutableOut.push([current.node, current.tags, new Line()]); @@ -297,7 +297,7 @@ const getBytecode = (first: CodePoint): Bytecode => { export const resolveJumps = (bytecode: Bytecode, maxOffset: number = MAX_JUMP): Bytecode => { const length = bytecode.reduce( - (acc, value) => (value instanceof Jump ? acc + 3 : value instanceof Line ? acc + 5 : acc + value.length), + (acc, value) => (value instanceof Jump ? acc + 5 : value instanceof Line ? acc + 5 : acc + value.length), 0, ); if (length < MAX_JUMP) { diff --git a/packages/neo-one-smart-contract-compiler/src/compile/scope/ResolvedScope.ts b/packages/neo-one-smart-contract-compiler/src/compile/scope/ResolvedScope.ts index 15112222d4..429afd69e3 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/scope/ResolvedScope.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/scope/ResolvedScope.ts @@ -78,7 +78,7 @@ export class ResolvedScope implements Scope { } } else { // [scope, val] - this.loadScope(sb, node, scopeLength, scopePosition); + this.loadScope(sb, node, options, scopeLength, scopePosition); // [position, scope, val] sb.emitPushInt(node, position); // [val, position, scope] @@ -103,7 +103,7 @@ export class ResolvedScope implements Scope { } } else { // [scope] - this.loadScope(sb, node, scopeLength, scopePosition); + this.loadScope(sb, node, options, scopeLength, scopePosition); // [position, scope] sb.emitPushInt(node, position); // [val] @@ -111,9 +111,9 @@ export class ResolvedScope implements Scope { } } - public getThis(sb: ScriptBuilder, node: ts.Node, _options: VisitOptions): void { + public getThis(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { // [[scopes, this]] - this.loadAll(sb, node); + this.loadAll(sb, node, options); // [1, [scopes, this]] sb.emitPushInt(node, 1); // [this] @@ -123,7 +123,7 @@ export class ResolvedScope implements Scope { public getGlobal(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { if (this.parent === undefined) { // [[scopes, this, global]] - this.loadAll(sb, node); + this.loadAll(sb, node, options); // [2, [scopes, this, global]] sb.emitPushInt(node, 2); // [this] @@ -136,7 +136,7 @@ export class ResolvedScope implements Scope { public setGlobal(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { if (this.parent === undefined) { // [[scopes, this, global], val] - this.loadAll(sb, node); + this.loadAll(sb, node, options); // [[scopes, this, global], val, [scopes, this, global]] sb.emitOp(node, 'TUCK'); // [val, [scopes, this, global], val, [scopes, this, global]] @@ -159,8 +159,8 @@ export class ResolvedScope implements Scope { } } - public pushAll(sb: ScriptBuilder, node: ts.Node, _options: VisitOptions): void { - sb.emitOp(node, 'DUPFROMALTSTACK'); + public pushAll(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { + sb.emitHelper(node, options, sb.helpers.dupScope); } public emit(sb: ScriptBuilder, node: ts.Node, options: VisitOptions, func: (options: VisitOptions) => void): void { @@ -193,10 +193,10 @@ export class ResolvedScope implements Scope { // [[scopes, this, global], [scopes, this, global]] sb.emitOp(node, 'DUP'); // [[scopes, this, global]] - sb.emitOp(node, 'TOALTSTACK'); + sb.emitHelper(node, options, sb.helpers.pushScope); } else { // [[scopes, this]] - sb.emitOp(node, 'DUPFROMALTSTACK'); + sb.emitHelper(node, options, sb.helpers.dupScope); } // [0, [scopes, this]] sb.emitPushInt(node, 0); @@ -236,12 +236,12 @@ export class ResolvedScope implements Scope { if (this.parent === undefined) { // [[scopes, undefined]] - sb.emitOp(node, 'FROMALTSTACK'); + sb.emitHelper(node, options, sb.helpers.popScope); // [] sb.emitOp(node, 'DROP'); } else { // [[scopes, undefined]] - sb.emitOp(node, 'DUPFROMALTSTACK'); + sb.emitHelper(node, options, sb.helpers.dupScope); // [0, [scopes, undefined]] sb.emitPushInt(node, 0); // [scopes] @@ -249,7 +249,7 @@ export class ResolvedScope implements Scope { // [scopes, scopes] sb.emitOp(node, 'DUP'); // [size, scopes] - sb.emitOp(node, 'ARRAYSIZE'); + sb.emitOp(node, 'SIZE'); // [size - 1, scopes] sb.emitOp(node, 'DEC'); // [] @@ -270,7 +270,7 @@ export class ResolvedScope implements Scope { sb.emitOp(node, 'DUP'); sb.emitPushInt(node, completion); sb.emitOp(node, 'NUMEQUAL'); - sb.emitJmp(node, 'JMPIF', pc); + sb.emitJmp(node, 'JMPIF_L', pc); } } @@ -286,9 +286,15 @@ export class ResolvedScope implements Scope { return this.uniqueVariables.get(name); } - private loadScope(sb: ScriptBuilder, node: ts.Node, scopeLength: number, scopePosition: number): void { - this.loadAll(sb, node); - // [0,[scopes, this]] + private loadScope( + sb: ScriptBuilder, + node: ts.Node, + options: VisitOptions, + scopeLength: number, + scopePosition: number, + ): void { + this.loadAll(sb, node, options); + // [0, [scopes, this]] sb.emitPushInt(node, 0); // [scopes] sb.emitOp(node, 'PICKITEM'); @@ -298,8 +304,8 @@ export class ResolvedScope implements Scope { sb.emitOp(node, 'PICKITEM'); } - private loadAll(sb: ScriptBuilder, node: ts.Node): void { + private loadAll(sb: ScriptBuilder, node: ts.Node, options: VisitOptions): void { // [[scopes, this]] - sb.emitOp(node, 'DUPFROMALTSTACK'); + sb.emitHelper(node, options, sb.helpers.dupScope); } } diff --git a/packages/neo-one-smart-contract-compiler/src/compile/statement/DoStatementCompiler.ts b/packages/neo-one-smart-contract-compiler/src/compile/statement/DoStatementCompiler.ts index b341548565..2dfa8ba52f 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/statement/DoStatementCompiler.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/statement/DoStatementCompiler.ts @@ -35,7 +35,7 @@ export class DoStatementCompiler extends NodeCompiler { ); }, whenTrue: () => { - sb.emitJmp(node, 'JMP', breakPC.getFirst()); + sb.emitJmp(node, 'JMP_L', breakPC.getFirst()); }, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/statement/ForOfStatementCompiler.ts b/packages/neo-one-smart-contract-compiler/src/compile/statement/ForOfStatementCompiler.ts index 349342cd47..d29a6c5d12 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/statement/ForOfStatementCompiler.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/statement/ForOfStatementCompiler.ts @@ -81,12 +81,13 @@ export class ForOfStatementCompiler extends NodeCompiler { // [map] sb.emitHelper(expression, innerOptions, sb.helpers.unwrapMap); // [iterator] - sb.emitSysCall(expression, 'Neo.Iterator.Create'); + sb.emitSysCall(expression, 'System.Iterator.Create'); // [] sb.emitHelper( node, innerOptions, sb.helpers.rawIteratorForEach({ + deserializeKey: true, each: (innerInnerOptionsIn) => { const innerInnerOptions = sb.pushValueOptions(innerInnerOptionsIn); // [2, key, val] @@ -127,9 +128,9 @@ export class ForOfStatementCompiler extends NodeCompiler { // [map] sb.emitHelper(expression, innerOptions, sb.helpers.unwrapSet); // [iterator] - sb.emitSysCall(expression, 'Neo.Iterator.Create'); + sb.emitSysCall(expression, 'System.Iterator.Create'); // [] - sb.emitHelper(node, innerOptions, sb.helpers.rawIteratorForEachKey({ each })); + sb.emitHelper(node, innerOptions, sb.helpers.rawIteratorForEachKey({ each, deserializeKey: true })); }; const handleSetStorage = (innerOptions: VisitOptions) => { @@ -227,13 +228,8 @@ export class ForOfStatementCompiler extends NodeCompiler { iterable: handleIterable, iterableIterator: handleIterableIterator, transaction: handleOther, - output: handleOther, attribute: handleOther, - input: handleOther, - account: handleOther, - asset: handleOther, contract: handleOther, - header: handleOther, block: handleOther, }), ); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/statement/TryStatementCompiler.ts b/packages/neo-one-smart-contract-compiler/src/compile/statement/TryStatementCompiler.ts index d0c91c598e..6137ac4ea9 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/statement/TryStatementCompiler.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/statement/TryStatementCompiler.ts @@ -31,7 +31,7 @@ export class TryStatementCompiler extends NodeCompiler { pcOptions = finallyBlock === undefined ? pcOptions : sb.finallyPCOptions(pcOptions, finallyPC.getLast()); sb.visit(tsUtils.statement.getTryBlock(node), pcOptions); pushFinally(); - sb.emitJmp(node, 'JMP', finallyPC.getLast()); + sb.emitJmp(node, 'JMP_L', finallyPC.getLast()); }); const finallyOptions = finallyBlock === undefined ? options : sb.finallyPCOptions(options, finallyPC.getLast()); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/types.ts b/packages/neo-one-smart-contract-compiler/src/compile/types.ts index 3bcf4f0c66..e49cd8bf6c 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/types.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/types.ts @@ -1,4 +1,3 @@ -import { ABI } from '@neo-one/client-common'; import { ContractRegister } from '@neo-one/client-full-core'; import { RawSourceMap } from 'source-map'; import ts from 'typescript'; @@ -32,17 +31,12 @@ export interface VisitOptions { readonly handleSuperConstruct?: HandleSuperConstruct; } -export interface Features { - // TODO: is dynamicInvoke even a thing now? - readonly dynamicInvoke: boolean; -} export interface ScriptBuilderResult { readonly code: Buffer; readonly sourceMap: Promise; } export interface CompileResult { readonly contract: ContractRegister; - readonly abi: ABI; readonly context: Context; readonly sourceMap: Promise; readonly debugInfo: DebugInfo; diff --git a/packages/neo-one-smart-contract-compiler/src/compileContract.ts b/packages/neo-one-smart-contract-compiler/src/compileContract.ts index 97cb19749f..73525da188 100644 --- a/packages/neo-one-smart-contract-compiler/src/compileContract.ts +++ b/packages/neo-one-smart-contract-compiler/src/compileContract.ts @@ -1,4 +1,3 @@ -import { ContractManifestClient } from '@neo-one/client-common'; import { ContractRegister } from '@neo-one/client-full-core'; import { tsUtils } from '@neo-one/ts-utils'; import { normalizePath } from '@neo-one/utils'; @@ -17,18 +16,17 @@ export interface CompileContractOptions extends WithLinked { } export interface CompileContractResult { - readonly manifest: ContractManifestClient; readonly diagnostics: ReadonlyArray; readonly contract: ContractRegister; readonly sourceMap: Promise; readonly debugInfo: DebugInfo; } -export const compileContract = ({ +export const compileContract = async ({ filePath: filePathIn, host, linked: linkedIn = {}, -}: CompileContractOptions): CompileContractResult => { +}: CompileContractOptions): Promise => { const filePath = normalizePath(filePathIn); const linked = _.fromPairs(Object.entries(linkedIn).map(([key, value]) => [normalizePath(key), value])); const transpileContext = createContextForPath(filePath, host); @@ -41,7 +39,7 @@ export const compileContract = ({ ? transpileContext : updateContext(transpileContext, { [filePath]: transpileResult.text }); - const { manifest, sourceMap: finalSourceMap, contract, debugInfo } = compile({ + const { sourceMap: finalSourceMap, contract, debugInfo } = await compile({ sourceFile: tsUtils.file.getSourceFileOrThrow(context.program, filePath), context, linked, @@ -51,7 +49,6 @@ export const compileContract = ({ return { diagnostics: context.diagnostics, sourceMap: finalSourceMap, - manifest, contract, debugInfo, }; diff --git a/packages/neo-one-smart-contract-compiler/src/constants.ts b/packages/neo-one-smart-contract-compiler/src/constants.ts index 705fd5b7ea..8f7d44ea26 100644 --- a/packages/neo-one-smart-contract-compiler/src/constants.ts +++ b/packages/neo-one-smart-contract-compiler/src/constants.ts @@ -1,3 +1,5 @@ +import { ContractGroup, ContractPermission, WildcardContainer } from '@neo-one/client-common'; + export const MAIN_FUNCTION = 'main'; export const DEPLOY_METHOD = 'deploy'; export const PROPERTIES_PROPERTY = 'properties'; @@ -9,26 +11,22 @@ export const FINALLY_COMPLETION = 4; export interface ContractProperties { readonly name: string; - readonly codeVersion: string; - readonly author: string; - readonly email: string; - readonly description: string; + readonly trusts: WildcardContainer; + readonly permissions: readonly ContractPermission[]; + readonly groups: readonly ContractGroup[]; } export const DEFAULT_CONTRACT_PROPERTIES = { name: '', - codeVersion: '1.0', - author: '', - email: '', - description: '', + groups: [], + permissions: [], + trusts: '*' as '*', }; export enum Decorator { constant = 'constant', - send = 'send', - sendUnsafe = 'sendUnsafe', receive = 'receive', - claim = 'claim', + safe = 'safe', } // tslint:disable-next-line no-any @@ -39,12 +37,8 @@ export const DECORATORS_ARRAY = Object.values(Decorator); export enum ContractPropertyName { deploy = 'deploy', - processedTransactions = 'processedTransactions', - claimedTransactions = 'claimedTransactions', - address = 'address', properties = 'properties', - refundAssets = 'refundAssets', - completeSend = 'completeSend', + address = 'address', deployed = 'deployed', approveUpgrade = 'approveUpgrade', upgrade = 'upgrade', @@ -52,16 +46,6 @@ export enum ContractPropertyName { } export const VIRTUAL_PROPERTIES: Set = new Set([ContractPropertyName.deploy]); -export const RESERVED_PROPERTIES: Set = new Set([ - ContractPropertyName.refundAssets, - ContractPropertyName.completeSend, - ContractPropertyName.upgrade, - ContractPropertyName.destroy, -]); -export const BUILTIN_PROPERTIES: Set = new Set([ - ContractPropertyName.processedTransactions, - ContractPropertyName.claimedTransactions, - ContractPropertyName.address, - ContractPropertyName.deployed, -]); +export const RESERVED_PROPERTIES: Set = new Set([ContractPropertyName.upgrade, ContractPropertyName.destroy]); +export const BUILTIN_PROPERTIES: Set = new Set([ContractPropertyName.address, ContractPropertyName.deployed]); export const IGNORED_PROPERTIES: Set = new Set([ContractPropertyName.properties]); diff --git a/packages/neo-one-smart-contract-compiler/src/contract/ContractInfoProcessor.ts b/packages/neo-one-smart-contract-compiler/src/contract/ContractInfoProcessor.ts index 7b514d796d..dbcaabdea7 100644 --- a/packages/neo-one-smart-contract-compiler/src/contract/ContractInfoProcessor.ts +++ b/packages/neo-one-smart-contract-compiler/src/contract/ContractInfoProcessor.ts @@ -3,7 +3,6 @@ import { utils } from '@neo-one/utils'; import _ from 'lodash'; import ts from 'typescript'; import { STRUCTURED_STORAGE_TYPES, StructuredStorageType } from '../compile/constants'; -import { hasForwardValue } from '../compile/helper/types'; import { BUILTIN_PROPERTIES, ContractPropertyName, @@ -31,20 +30,11 @@ export interface DeployPropInfo extends PropInfoBase { readonly callSignature?: ts.Signature; } -export interface RefundAssetsPropInfo extends PropInfoBase { - readonly type: 'refundAssets'; - readonly name: string; -} - -export interface CompleteSendPropInfo extends PropInfoBase { - readonly type: 'completeSend'; - readonly name: string; -} - export interface UpgradePropInfo extends PropInfoBase { readonly type: 'upgrade'; readonly name: string; readonly approveUpgrade: ts.PropertyDeclaration | ts.MethodDeclaration; + readonly isSafe: boolean; } export interface FunctionPropInfo extends PropInfoBase { @@ -53,12 +43,9 @@ export interface FunctionPropInfo extends PropInfoBase { readonly symbol: ts.Symbol; readonly decl: ts.PropertyDeclaration | ts.MethodDeclaration; readonly callSignature: ts.Signature | undefined; - readonly send: boolean; - readonly sendUnsafe: boolean; readonly receive: boolean; - readonly claim: boolean; readonly constant: boolean; - readonly acceptsClaim: boolean; + readonly isSafe: boolean; readonly returnType: ts.Type | undefined; readonly isAbstract: boolean; } @@ -71,6 +58,7 @@ export interface PropertyPropInfo extends PropInfoBase { readonly propertyType: ts.Type | undefined; readonly isReadonly: boolean; readonly isAbstract: boolean; + readonly isSafe: boolean; readonly structuredStorageType: StructuredStorageType | undefined; } @@ -82,22 +70,17 @@ export interface AccessorPropInfo extends PropInfoBase { readonly name: string; readonly decl: ts.GetAccessorDeclaration; readonly constant: boolean; + readonly isSafe: boolean; }; readonly setter?: { readonly name: string; readonly decl: ts.SetAccessorDeclaration; + readonly isSafe: boolean; }; readonly propertyType: ts.Type | undefined; } -export type PropInfo = - | PropertyPropInfo - | AccessorPropInfo - | FunctionPropInfo - | DeployPropInfo - | RefundAssetsPropInfo - | UpgradePropInfo - | CompleteSendPropInfo; +export type PropInfo = PropertyPropInfo | AccessorPropInfo | FunctionPropInfo | DeployPropInfo | UpgradePropInfo; export interface ContractInfo { readonly smartContract: ts.ClassDeclaration | ts.ClassExpression; @@ -117,27 +100,6 @@ export class ContractInfoProcessor { ); } const result = this.processClass(this.smartContract, this.context.analysis.getType(this.smartContract)); - - const hasReceive = result.propInfos.some((propInfo) => propInfo.type === 'function' && propInfo.receive); - const refundAssets: PropInfo | undefined = hasReceive - ? { - type: 'refundAssets', - name: ContractPropertyName.refundAssets, - classDecl: this.smartContract, - isPublic: true, - } - : undefined; - - const hasSend = result.propInfos.some((propInfo) => propInfo.type === 'function' && propInfo.send); - const completeSend: PropInfo | undefined = hasSend - ? { - type: 'completeSend', - name: ContractPropertyName.completeSend, - classDecl: this.smartContract, - isPublic: true, - } - : undefined; - const approveUpgrade = this.getApproveUpgradeDecl(result); const upgrade: PropInfo | undefined = approveUpgrade !== undefined @@ -147,10 +109,11 @@ export class ContractInfoProcessor { classDecl: this.smartContract, isPublic: true, approveUpgrade, + isSafe: true, // TODO: check } : undefined; - const finalPropInfos = result.propInfos.concat([refundAssets, completeSend, upgrade].filter(utils.notNull)); + const finalPropInfos = result.propInfos.concat([upgrade].filter(utils.notNull)); if (this.hasDeployInfo(result)) { return { @@ -424,6 +387,7 @@ export class ContractInfoProcessor { name: tsUtils.node.getName(getDecl), decl: getDecl, constant: this.hasConstant(getDecl), + isSafe: this.hasSafe(getDecl) || this.hasConstant(getDecl), }, setter: setDecl === undefined @@ -431,6 +395,7 @@ export class ContractInfoProcessor { : { name: getSetterName(tsUtils.node.getName(setDecl)), decl: setDecl, + isSafe: this.hasSafe(setDecl), }, isPublic, propertyType: type, @@ -469,66 +434,11 @@ export class ContractInfoProcessor { const callSignature = callSignatures[0]; - const send = this.hasSend(decl); - const sendUnsafe = this.hasSendUnsafe(decl); - const receive = this.hasReceive(decl); - const claim = this.hasClaim(decl); const constant = this.hasConstant(decl); - const isUTXO = send || sendUnsafe || receive || claim; - - if (isUTXO && constant) { - const decorator = tsUtils.decoratable - .getDecoratorsArray(decl) - .find((dec) => this.isDecorator(dec, Decorator.constant)); - this.context.reportError( - decorator === undefined ? decl : decorator, - DiagnosticCode.InvalidContractMethod, - DiagnosticMessage.InvalidContractMethodConstantNative, - ); - - return undefined; - } + const receive = this.hasReceive(decl); + const safe = this.hasSafe(decl); const returnType = callSignatures.length >= 1 ? tsUtils.signature.getReturnType(callSignature) : undefined; - if (claim && returnType !== undefined && !tsUtils.type_.isVoid(returnType)) { - const decorator = tsUtils.decoratable - .getDecoratorsArray(decl) - .find((dec) => this.isDecorator(dec, Decorator.claim)); - this.context.reportError( - decorator === undefined ? decl : decorator, - DiagnosticCode.InvalidContractMethod, - DiagnosticMessage.InvalidContractMethodNativeReturn, - ); - - return undefined; - } - - if (isUTXO && callSignatures.length >= 1) { - const signatureTypes = this.context.analysis.extractSignatureTypes(decl, callSignatures[0]); - if (signatureTypes !== undefined) { - const invalidParams = signatureTypes.paramDecls.filter((param) => { - const paramType = signatureTypes.paramTypes.get(param); - - return ( - paramType !== undefined && - (hasForwardValue(this.context, param, paramType) || - tsUtils.type_.hasType(paramType, (tpe) => this.context.builtins.isType(param, tpe, 'ForwardedValue'))) - ); - }); - - invalidParams.forEach((param) => { - this.context.reportError( - param, - DiagnosticCode.InvalidContractType, - DiagnosticMessage.InvalidContractTypeForwardNative, - ); - }); - - if (invalidParams.length > 0) { - return undefined; - } - } - } return { type: 'function', @@ -536,12 +446,9 @@ export class ContractInfoProcessor { classDecl, symbol: tsUtils.symbol.getTarget(symbol), decl, - send, - sendUnsafe, receive, - claim, - acceptsClaim: callSignatures.length >= 1 && this.isLastParamClaim(decl, callSignatures[0]), isPublic, + isSafe: safe || constant, callSignature, returnType, constant, @@ -586,6 +493,7 @@ export class ContractInfoProcessor { isReadonly, isAbstract, structuredStorageType, + isSafe: true, }; } @@ -593,20 +501,12 @@ export class ContractInfoProcessor { return this.hasDecorator(decl, Decorator.constant); } - private hasSend(decl: ClassInstanceMemberType | ts.ConstructorDeclaration): boolean { - return this.hasDecorator(decl, Decorator.send); - } - - private hasSendUnsafe(decl: ClassInstanceMemberType | ts.ConstructorDeclaration): boolean { - return this.hasDecorator(decl, Decorator.sendUnsafe); - } - private hasReceive(decl: ClassInstanceMemberType | ts.ConstructorDeclaration): boolean { return this.hasDecorator(decl, Decorator.receive); } - private hasClaim(decl: ClassInstanceMemberType | ts.ConstructorDeclaration): boolean { - return this.hasDecorator(decl, Decorator.claim); + private hasSafe(decl: ClassInstanceMemberType | ts.ConstructorDeclaration): boolean { + return this.hasDecorator(decl, Decorator.safe); } private hasDecorator(decl: ClassInstanceMemberType | ts.ConstructorDeclaration, name: Decorator): boolean { @@ -623,22 +523,6 @@ export class ContractInfoProcessor { return this.context.builtins.isValue(tsUtils.expression.getExpression(decorator), name); } - private isLastParamClaim(node: ts.Node, callSignature: ts.Signature): boolean { - const signatureTypes = this.context.analysis.extractSignatureTypes(node, callSignature); - if (signatureTypes === undefined) { - return false; - } - - if (signatureTypes.paramDecls.length === 0) { - return false; - } - - const param = signatureTypes.paramDecls[signatureTypes.paramDecls.length - 1]; - const paramType = signatureTypes.paramTypes.get(signatureTypes.paramDecls[signatureTypes.paramDecls.length - 1]); - - return paramType !== undefined && this.context.builtins.isInterface(param, paramType, 'ClaimTransaction'); - } - private hasDeployInfo(contractInfo: ContractInfo): boolean { if (contractInfo.propInfos.some((propInfo) => propInfo.type === 'deploy')) { return true; diff --git a/packages/neo-one-smart-contract-compiler/src/contract/DebugInfoProcessor.ts b/packages/neo-one-smart-contract-compiler/src/contract/DebugInfoProcessor.ts index 9a2ca217d5..e263a1a165 100644 --- a/packages/neo-one-smart-contract-compiler/src/contract/DebugInfoProcessor.ts +++ b/packages/neo-one-smart-contract-compiler/src/contract/DebugInfoProcessor.ts @@ -14,7 +14,7 @@ export interface DebugInfo { readonly documents: readonly string[]; } -interface DebugMethod { +export interface DebugMethod { readonly id: string; readonly name: string; readonly range: readonly [number, number]; @@ -47,15 +47,36 @@ export class DebugInfoProcessor { } private processMethods(): ReadonlyArray { - const propInfos = this.contractInfo.propInfos.filter(utils.notNull); + const propInfos = this.contractInfo.propInfos.filter((propInfo) => propInfo.isPublic).filter(utils.notNull); return _.flatten( propInfos.map( (propInfo): ReadonlyArray => { switch (propInfo.type) { + case 'deploy': + return [ + { + id: '', + name: propInfo.name, + params: propInfo.isMixinDeploy ? [] : this.getParameters({ callSignature: propInfo.callSignature }), + range: [0, 0], + returnType: 'Boolean', + }, + ]; + + case 'upgrade': + return [ + { + id: '', + name: propInfo.name, + params: ['script,Buffer', 'manifest,Buffer'], + range: [0, 0], + returnType: 'Void', + }, + ]; + case 'function': const funcRange = this.getSourceRange(propInfo.decl); - if (funcRange === undefined) { return []; } @@ -66,8 +87,6 @@ export class DebugInfoProcessor { name: propInfo.name, params: this.getParameters({ callSignature: propInfo.callSignature, - send: propInfo.send, - claim: propInfo.claim, }), range: funcRange, returnType: this.toDebugReturn(propInfo.decl, propInfo.returnType), @@ -76,7 +95,6 @@ export class DebugInfoProcessor { case 'property': const propRange = this.getSourceRange(propInfo.decl); - if (propRange === undefined) { return []; } @@ -95,7 +113,8 @@ export class DebugInfoProcessor { return [this.getGetterInfo(propInfo), this.getSetterInfo(propInfo)].filter(utils.notNull); default: - return []; + utils.assertNever(propInfo); + throw new Error('For TS'); } }, ), @@ -150,25 +169,14 @@ export class DebugInfoProcessor { private getParameters({ callSignature, - claim = false, - send = false, }: { readonly callSignature: ts.Signature | undefined; - readonly claim?: boolean; - readonly send?: boolean; }): ReadonlyArray { if (callSignature === undefined) { return []; } - let parameters = callSignature.getParameters(); - if (claim && this.checkLastParam(parameters, 'ClaimTransaction')) { - parameters = parameters.slice(0, -1); - } - - if (send && this.checkLastParam(parameters, 'Transfer')) { - parameters = parameters.slice(0, -1); - } + const parameters = callSignature.getParameters(); return parameters.map((parameter) => this.paramToABIParameter(parameter)).filter(utils.notNull); } @@ -194,24 +202,6 @@ export class DebugInfoProcessor { return this.context.analysis.getTypeOfSymbol(param, decl); } - private checkLastParam(parameters: ReadonlyArray, value: string): boolean { - return this.checkLastParamBase(parameters, (decl, type) => this.context.builtins.isInterface(decl, type, value)); - } - - private checkLastParamBase( - parameters: ReadonlyArray, - checkParamType: (decl: ts.Node, type: ts.Type) => boolean, - ): boolean { - if (parameters.length === 0) { - return false; - } - - const lastParam = parameters[parameters.length - 1]; - const lastParamType = this.getParamSymbolType(lastParam); - - return lastParamType !== undefined && checkParamType(tsUtils.symbol.getDeclarations(lastParam)[0], lastParamType); - } - private toDebugParameter( nameIn: string, node: ts.Node, diff --git a/packages/neo-one-smart-contract-compiler/src/contract/ABISmartContractProcessor.ts b/packages/neo-one-smart-contract-compiler/src/contract/ManifestSmartContractProcessor.ts similarity index 59% rename from packages/neo-one-smart-contract-compiler/src/contract/ABISmartContractProcessor.ts rename to packages/neo-one-smart-contract-compiler/src/contract/ManifestSmartContractProcessor.ts index 2d1cb5924e..eea1425847 100644 --- a/packages/neo-one-smart-contract-compiler/src/contract/ABISmartContractProcessor.ts +++ b/packages/neo-one-smart-contract-compiler/src/contract/ManifestSmartContractProcessor.ts @@ -1,37 +1,215 @@ -import { ABI, ABIEvent, ABIFunction, ABIParameter, ABIReturn, SenderAddressABIDefault } from '@neo-one/client-common'; +import { + ABIParameter, + ABIReturn, + ContractEventDescriptorClient, + ContractGroup, + ContractPermission, + SenderAddressABIDefault, + UInt160Hex, + WildcardContainer, +} from '@neo-one/client-common'; import { tsUtils } from '@neo-one/ts-utils'; import { utils } from '@neo-one/utils'; import _ from 'lodash'; import ts from 'typescript'; import { DEFAULT_DIAGNOSTIC_OPTIONS, DiagnosticOptions } from '../analysis'; +import { + SmartContractInfoABI, + SmartContractInfoManifest, + SmartContractInfoMethodDescriptor, +} from '../compile/getSmartContractInfo'; +import { ContractProperties } from '../constants'; import { Context } from '../Context'; import { DiagnosticCode } from '../DiagnosticCode'; import { DiagnosticMessage } from '../DiagnosticMessage'; import { getSetterName, toABIReturn } from '../utils'; -import { ContractInfo, DeployPropInfo } from './ContractInfoProcessor'; +import { + AccessorPropInfo, + ContractInfo, + DeployPropInfo, + FunctionPropInfo, + PropertyPropInfo, +} from './ContractInfoProcessor'; const BOOLEAN_RETURN: ABIReturn = { type: 'Boolean' }; const VOID_RETURN: ABIReturn = { type: 'Void' }; -export class ABISmartContractProcessor { - public constructor(private readonly context: Context, private readonly contractInfo: ContractInfo) {} +export class ManifestSmartContractProcessor { + public constructor( + private readonly context: Context, + private readonly contractInfo: ContractInfo, + private readonly properties: ContractProperties, + ) {} + + public process(): SmartContractInfoManifest { + // TODO: can remove this later + const storage = this.processStorage(); + const payable = this.processPayable(); - public process(): ABI { return { - functions: this.processFunctions(), + groups: this.processGroups(), + features: { + storage, + payable, + }, + supportedStandards: this.processSupportedStandards(), + abi: this.processABI(), + permissions: this.processPermissions(), + trusts: this.processTrusts(), + safeMethods: this.processSafeMethods(), + hasStorage: storage, + payable, + }; + } + + // TODO: document permissions, trusts, groups + // "contract.Manifest" is the manifest of contract to be called = "ManifestCalled" + // "currentManifest" is the manifest of the contract that is making the call = "CallingManifest" + // "method" is the method being called + // currentManifest.CanCall(contract.Manifest, method) + // If any Permission.isAllowed(manifest, method) returns true + // IsAllowed(manifest, method) + // Now "manifest" is the manifest of the contract to be called + // IsAllowed is for the Permission object in the manifest of the contract making the call + // Permission.Contract = the contract to be invoked (a contract hash or a "group" which is a public key) + // Permission.Methods = the methods to be called + + // If Permission.Contract is a hash, then check if Permission.Contract.Hash === ManifestCalled.Hash + // in this case CanCall() will return true as long as the + + private processGroups(): readonly ContractGroup[] { + return this.properties.groups; + } + + private processPermissions(): readonly ContractPermission[] { + return this.properties.permissions; + } + + private processTrusts(): WildcardContainer { + return this.properties.trusts; + } + + private processPayable(): boolean { + const propInfos = this.contractInfo.propInfos.filter((propInfo) => propInfo.isPublic && propInfo.type !== 'deploy'); + + return propInfos.some((info) => info.type === 'function' && info.receive); + } + + // TODO: make sure this matches up with docs and with @safe decorator + // These methods are automatically safe: + // Marked with @safe or @constant + // Properties that are readonly or @safe + // Getters marked with @constant or @safe + // Not the deploy method + private processSafeMethods(): WildcardContainer { + const propInfos = this.contractInfo.propInfos.filter((propInfo) => propInfo.isPublic && propInfo.type !== 'deploy'); + + const safeFuncs = propInfos + .filter((info) => info.type === 'function' && (info.constant || info.isSafe)) + .map((info) => info.name); + const safeProps = propInfos + .filter((info) => info.type === 'property' && (info.isReadonly || info.isSafe)) + .map((info) => info.name); + const safeGetters = propInfos + .filter((info): info is AccessorPropInfo => info.type === 'accessor') + .map((info) => info.getter) + .filter(utils.notNull) + .filter((getter) => getter.constant || getter.isSafe) + .map((getter) => getter.name); + const safeSetters = propInfos + .filter((info): info is AccessorPropInfo => info.type === 'accessor') + .map((info) => info.setter) + .filter(utils.notNull) + .filter((setter) => setter.isSafe) + .map((setter) => setter.name); + + return safeFuncs.concat(safeProps, safeGetters, safeSetters); + } + + private processSupportedStandards(): readonly string[] { + return [this.isNep5Contract() ? 'NEP-5' : undefined].filter(utils.notNull); + } + + // TODO: change to NEP17 + // Throw error if contract is marked at NEP17 but doesn't pass this test? + private isNep5Contract(): boolean { + const propInfos = this.contractInfo.propInfos.filter((propInfo) => propInfo.isPublic && propInfo.type !== 'deploy'); + const hasTransferEvent = this.processEvents().some((event) => event.name === 'transfer'); + const hasTotalSupply = propInfos.some( + (info) => info.type === 'function' && info.name === 'totalSupply' && info.constant, + ); + const hasBalanceOf = propInfos.some( + (info) => info.type === 'function' && info.name === 'balanceOf' && info.constant, + ); + const hasTransfer = propInfos.some( + (info) => info.type === 'function' && info.name === 'transfer' && !info.constant, + ); + const hasDecimals = propInfos.some( + (info) => info.type === 'property' && info.name === 'decimals' && info.isReadonly, + ); + const hasSymbol = propInfos.some((info) => info.type === 'property' && info.name === 'symbol' && info.isReadonly); + const hasName = propInfos.some((info) => info.type === 'property' && info.name === 'name' && info.isReadonly); + + return hasTotalSupply && hasBalanceOf && hasTransfer && hasDecimals && hasSymbol && hasName && hasTransferEvent; + } + + // TODO: can remove this later + private processStorage(): boolean { + const propInfos = this.contractInfo.propInfos.filter((propInfo) => propInfo.isPublic && propInfo.type !== 'deploy'); + + const funcProps = propInfos.filter((info): info is FunctionPropInfo => info.type === 'function'); + const hasNonConstant = funcProps.some((info) => !info.constant); + const propProps = propInfos.filter((info): info is PropertyPropInfo => info.type === 'property'); + const hasNonReadonly = propProps.some((info) => !info.isReadonly); + const accessorProps = propInfos.filter((info): info is AccessorPropInfo => info.type === 'accessor'); + const hasSetter = accessorProps.some((info) => info.setter !== undefined); + + return hasSetter || hasNonConstant || hasNonReadonly; + } + + private processABI(): SmartContractInfoABI { + return { + // TODO: fix this later when changing how smart contracts are called + methods: this.modifyProcessedFunctions(this.processFunctions()), events: this.processEvents(), }; } - private processFunctions(): ReadonlyArray { + // TODO: remove this later when changing how smart contracts are called + private modifyProcessedFunctions( + methods: ReadonlyArray, + ): ReadonlyArray { + return methods.map((method) => + method.parameters === undefined + ? method + : { ...method, parameters: this.addDefaultEntryParams(method.parameters) }, + ); + } + + // TODO: remove this later when changing how smart contracts are called + private addDefaultEntryParams(_params: readonly ABIParameter[]): readonly ABIParameter[] { + return [ + { + type: 'String', + name: 'method', + }, + { + type: 'Array', + name: 'args', + value: { type: 'Any' }, + }, + ]; + } + + private processFunctions(): ReadonlyArray { const deployInfo = this.findDeployInfo(); const propInfos = this.contractInfo.propInfos .filter((propInfo) => propInfo.isPublic && propInfo.type !== 'deploy') .concat([deployInfo].filter(utils.notNull)); - return _.flatten( + return _.flatten( propInfos.map( - (propInfo): ReadonlyArray => { + (propInfo): ReadonlyArray => { switch (propInfo.type) { case 'deploy': return [ @@ -43,38 +221,13 @@ export class ABISmartContractProcessor { returnType: BOOLEAN_RETURN, }, ]; - case 'refundAssets': - return [ - { - name: propInfo.name, - sendUnsafe: true, - parameters: [], - returnType: VOID_RETURN, - }, - ]; - case 'completeSend': - return [ - { - name: propInfo.name, - completeSend: true, - parameters: [], - returnType: VOID_RETURN, - }, - ]; case 'upgrade': return [ { name: propInfo.name, parameters: [ { name: 'script', type: 'Buffer' }, - { name: 'parameterList', type: 'Buffer' }, - { name: 'returnType', type: 'Integer', decimals: 0 }, - { name: 'properties', type: 'Integer', decimals: 0 }, - { name: 'contractName', type: 'String' }, - { name: 'codeVersion', type: 'String' }, - { name: 'author', type: 'String' }, - { name: 'email', type: 'String' }, - { name: 'description', type: 'String' }, + { name: 'manifest', type: 'Buffer' }, ], returnType: VOID_RETURN, }, @@ -85,15 +238,9 @@ export class ABISmartContractProcessor { name: propInfo.name, parameters: this.getParameters({ callSignature: propInfo.callSignature, - send: propInfo.send, - claim: propInfo.claim, }), returnType: this.toABIReturn(propInfo.decl, propInfo.returnType), constant: propInfo.constant, - send: propInfo.send, - sendUnsafe: propInfo.sendUnsafe, - receive: propInfo.receive, - claim: propInfo.claim, }, ]; case 'property': @@ -171,30 +318,20 @@ export class ABISmartContractProcessor { private getParameters({ callSignature, - claim = false, - send = false, }: { readonly callSignature: ts.Signature | undefined; - readonly claim?: boolean; readonly send?: boolean; }): ReadonlyArray { if (callSignature === undefined) { return []; } - let parameters = callSignature.getParameters(); - if (claim && this.checkLastParam(parameters, 'ClaimTransaction')) { - parameters = parameters.slice(0, -1); - } - - if (send && this.checkLastParam(parameters, 'Transfer')) { - parameters = parameters.slice(0, -1); - } + const parameters = callSignature.getParameters(); return parameters.map((parameter) => this.paramToABIParameter(parameter)).filter(utils.notNull); } - private processEvents(): ReadonlyArray { + private processEvents(): ReadonlyArray { const createEventNotifierDecl = tsUtils.symbol.getDeclarations( this.context.builtins.getValueSymbol('createEventNotifier'), )[0]; @@ -215,14 +352,17 @@ export class ABISmartContractProcessor { }) .filter(utils.notNull); - return calls.reduce>((events, call) => { - const event = this.toABIEvent(call, events); + return calls.reduce>((events, call) => { + const event = this.toContractEventDescriptorClient(call, events); return event === undefined ? events : [...events, event]; }, []); } - private toABIEvent(call: ts.CallExpression, events: ReadonlyArray): ABIEvent | undefined { + private toContractEventDescriptorClient( + call: ts.CallExpression, + events: ReadonlyArray, + ): ContractEventDescriptorClient | undefined { const callArguments = tsUtils.argumented.getArguments(call); const parent = tsUtils.node.getParent(call); diff --git a/packages/neo-one-smart-contract-compiler/src/contract/getABI.ts b/packages/neo-one-smart-contract-compiler/src/contract/getABI.ts deleted file mode 100644 index bcd953c2ed..0000000000 --- a/packages/neo-one-smart-contract-compiler/src/contract/getABI.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Context } from '../Context'; -import { ABISmartContractProcessor } from './ABISmartContractProcessor'; -import { ContractInfo } from './ContractInfoProcessor'; - -export const getABI = (context: Context, contractInfo: ContractInfo) => - new ABISmartContractProcessor(context, contractInfo).process(); diff --git a/packages/neo-one-smart-contract-compiler/src/contract/getContractProperties.ts b/packages/neo-one-smart-contract-compiler/src/contract/getContractProperties.ts index ad1f7bdc8e..7fd2f5272f 100644 --- a/packages/neo-one-smart-contract-compiler/src/contract/getContractProperties.ts +++ b/packages/neo-one-smart-contract-compiler/src/contract/getContractProperties.ts @@ -1,3 +1,4 @@ +import { common, ContractGroup, ContractPermission, WildcardContainer } from '@neo-one/client-common'; import { tsUtils } from '@neo-one/ts-utils'; import ts from 'typescript'; import { ContractProperties, ContractPropertyName, DEFAULT_CONTRACT_PROPERTIES } from '../constants'; @@ -22,6 +23,12 @@ export const getContractProperties = (context: Context, smartContract: ts.ClassD .find((symbol) => tsUtils.symbol.getName(symbol) === ContractPropertyName.properties); if (properties === undefined) { + context.reportWarning( + smartContract, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertiesWarning, + ); + return defaultContractProperties; } @@ -56,7 +63,11 @@ export const getContractProperties = (context: Context, smartContract: ts.ClassD return defaultContractProperties; } - const contract: { [key: string]: string } = {}; + const contract: { + trusts?: WildcardContainer; + permissions?: readonly ContractPermission[]; + groups?: readonly ContractGroup[]; + } = {}; // tslint:disable-next-line no-loop-statement for (const property of tsUtils.object_.getProperties(initializer)) { if (!ts.isPropertyAssignment(property)) { @@ -71,18 +82,355 @@ export const getContractProperties = (context: Context, smartContract: ts.ClassD const key = tsUtils.node.getName(property); const value = tsUtils.initializer.getInitializer(property); - if (!ts.isLiteralExpression(value)) { - context.reportError( - value, - DiagnosticCode.InvalidContractProperties, - DiagnosticMessage.InvalidContractPropertiesInitializer, - ); - return defaultContractProperties; + if (key === 'groups') { + const groupsArray = tsUtils.initializer.getInitializerOrThrow(value.parent); + if (!ts.isArrayLiteralExpression(groupsArray)) { + context.reportError( + groupsArray, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyGroups, + ); + + continue; + } + + const elements = tsUtils.expression.getElements(groupsArray); + const finalGroupsArray: ContractGroup[] = []; + + elements.forEach((elem) => { + if (!ts.isObjectLiteralExpression(elem)) { + context.reportError( + elem, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyGroups, + ); + + return; + } + + const newObjToPush: { [key: string]: string } = {}; + // tslint:disable-next-line: no-loop-statement + for (const innerProperty of tsUtils.object_.getProperties(elem)) { + if (!ts.isPropertyAssignment(innerProperty)) { + context.reportError( + innerProperty, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyGroups, + ); + + continue; + } + + const innerKey = tsUtils.node.getName(innerProperty); + const innerValue = tsUtils.initializer.getInitializer(innerProperty); + if (!ts.isLiteralExpression(innerValue)) { + context.reportError( + innerValue, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyGroups, + ); + + continue; + } + + const stringValue = tsUtils.literal.getLiteralValue(innerValue); + + if (innerKey === 'publicKey') { + try { + common.stringToECPoint(stringValue); + } catch { + context.reportError( + innerValue, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyGroups, + ); + + continue; + } + } + + // tslint:disable-next-line: no-object-mutation + newObjToPush[innerKey] = stringValue; + } + + // tslint:disable-next-line: no-array-mutation + finalGroupsArray.push((newObjToPush as unknown) as ContractGroup); + }); + + // tslint:disable-next-line: no-object-mutation + contract.groups = finalGroupsArray; } - // tslint:disable-next-line no-object-mutation - contract[key] = tsUtils.literal.getLiteralValue(value); + if (key === 'permissions') { + const permissionsArray = tsUtils.initializer.getInitializerOrThrow(value.parent); + if (!ts.isArrayLiteralExpression(permissionsArray)) { + context.reportError( + permissionsArray, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyPermissions, + ); + + continue; + } + + const elements = tsUtils.expression.getElements(permissionsArray); + const finalPermissionsArray: ContractPermission[] = []; + + elements.forEach((elem) => { + if (!ts.isObjectLiteralExpression(elem)) { + context.reportError( + elem, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyPermissions, + ); + + return; + } + + const permissionObject: { + contract?: { hash?: string; group?: string }; + methods?: WildcardContainer; + } = { + contract: undefined, + methods: undefined, + }; + // tslint:disable-next-line: no-loop-statement + for (const innerProperty of tsUtils.object_.getProperties(elem)) { + if (!ts.isPropertyAssignment(innerProperty)) { + context.reportError( + innerProperty, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyPermissions, + ); + + continue; + } + + const innerKey = tsUtils.node.getName(innerProperty); + const innerValue = tsUtils.initializer.getInitializer(innerProperty); + + if ( + !ts.isLiteralExpression(innerValue) && + !ts.isObjectLiteralExpression(innerValue) && + !ts.isArrayLiteralExpression(innerValue) + ) { + context.reportError( + innerValue, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyPermissions, + ); + + continue; + } + + const innerMethodsArray: string[] = []; + + if (innerKey === 'methods') { + if (!ts.isLiteralExpression(innerValue) && !ts.isArrayLiteralExpression(innerValue)) { + context.reportError( + innerValue, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyPermissions, + ); + + return; + } + + if (ts.isLiteralExpression(innerValue)) { + const stringValue = tsUtils.literal.getLiteralValue(innerValue); + if (stringValue !== '*') { + context.reportError( + innerValue, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyPermissions, + ); + + return; + } + + // tslint:disable-next-line: no-object-mutation + permissionObject.methods = stringValue; + + continue; + } + + if (ts.isArrayLiteralExpression(innerValue)) { + const arrayElements = tsUtils.expression.getElements(innerValue); + + arrayElements.forEach((methodElem) => { + if (!ts.isLiteralExpression(methodElem)) { + context.reportError( + methodElem, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyPermissions, + ); + + return; + } + + const literalString = tsUtils.literal.getLiteralValue(methodElem); + + // tslint:disable-next-line: no-array-mutation + innerMethodsArray.push(literalString); + }); + + // tslint:disable-next-line: no-object-mutation + permissionObject.methods = innerMethodsArray; + } + } + + const innerContractObject: { hash?: string; group?: string } = { hash: undefined, group: undefined }; + + if (innerKey === 'contract') { + if (!ts.isObjectLiteralExpression(innerValue)) { + context.reportError( + innerValue, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyPermissions, + ); + + return; + } + + // tslint:disable-next-line: no-loop-statement + for (const innerInnerProp of tsUtils.object_.getProperties(innerValue)) { + if (!ts.isPropertyAssignment(innerInnerProp)) { + context.reportError( + innerInnerProp, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyPermissions, + ); + + continue; + } + + const contractKey = tsUtils.node.getName(innerInnerProp); + const contractValue = tsUtils.initializer.getInitializer(innerInnerProp); + if (!ts.isLiteralExpression(contractValue)) { + context.reportError( + contractValue, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyPermissions, + ); + + return; + } + + const contractValueString = tsUtils.literal.getLiteralValue(contractValue); + + if (contractKey === 'hash') { + try { + common.stringToUInt160(contractValueString); + } catch { + context.reportError( + contractValue, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyPermissions, + ); + + return; + } + + // tslint:disable-next-line: no-object-mutation + innerContractObject.hash = contractValueString; + } + + if (contractKey === 'group') { + try { + common.stringToECPoint(contractValueString); + } catch { + context.reportError( + contractValue, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyPermissions, + ); + + return; + } + + // tslint:disable-next-line: no-object-mutation + innerContractObject.group = contractValueString; + } + } + + // tslint:disable-next-line: no-object-mutation + permissionObject.contract = innerContractObject; + } + } + + // tslint:disable-next-line: no-array-mutation + finalPermissionsArray.push((permissionObject as unknown) as ContractPermission); + }); + + // tslint:disable-next-line: no-object-mutation + contract.permissions = finalPermissionsArray; + } + + if (key === 'trusts') { + const trustsArray = tsUtils.initializer.getInitializerOrThrow(value.parent); + if (ts.isLiteralExpression(trustsArray)) { + const trustsString = tsUtils.literal.getLiteralValue(trustsArray); + if (trustsString !== '*') { + context.reportError( + trustsArray, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyTrusts, + ); + + continue; + } + + // tslint:disable-next-line: no-object-mutation + contract.trusts = trustsString; + + continue; + } + + if (!ts.isArrayLiteralExpression(trustsArray)) { + context.reportError( + trustsArray, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyTrusts, + ); + + continue; + } + + const elements = tsUtils.expression.getElements(trustsArray); + const finalTrustsArray: string[] = []; + + elements.forEach((elem) => { + if (!ts.isLiteralExpression(elem)) { + context.reportError( + elem, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyTrusts, + ); + + return; + } + + const literalString = tsUtils.literal.getLiteralValue(elem); + + try { + common.stringToUInt160(literalString); + // tslint:disable-next-line: no-array-mutation + finalTrustsArray.push(literalString); + } catch { + context.reportError( + elem, + DiagnosticCode.InvalidContractProperties, + DiagnosticMessage.InvalidContractPropertyTrusts, + ); + + return; + } + }); + + // tslint:disable-next-line: no-object-mutation + contract.trusts = finalTrustsArray; + } } return { diff --git a/packages/neo-one-smart-contract-compiler/src/contract/getManifest.ts b/packages/neo-one-smart-contract-compiler/src/contract/getManifest.ts new file mode 100644 index 0000000000..24d6b2dd05 --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/contract/getManifest.ts @@ -0,0 +1,7 @@ +import { ContractProperties } from '../constants'; +import { Context } from '../Context'; +import { ContractInfo } from './ContractInfoProcessor'; +import { ManifestSmartContractProcessor } from './ManifestSmartContractProcessor'; + +export const getManifest = (context: Context, contractInfo: ContractInfo, properties: ContractProperties) => + new ManifestSmartContractProcessor(context, contractInfo, properties).process(); diff --git a/packages/neo-one-smart-contract-compiler/src/contract/index.ts b/packages/neo-one-smart-contract-compiler/src/contract/index.ts index 576bd5206e..5ca4ff36e6 100644 --- a/packages/neo-one-smart-contract-compiler/src/contract/index.ts +++ b/packages/neo-one-smart-contract-compiler/src/contract/index.ts @@ -1,4 +1,4 @@ -export * from './getABI'; +export * from './getManifest'; export * from './getAllPropInfos'; export * from './getContractInfo'; export * from './getDebugInfo'; diff --git a/packages/neo-one-smart-contract-compiler/src/utils/BinaryReader.ts b/packages/neo-one-smart-contract-compiler/src/utils/BinaryReader.ts new file mode 100644 index 0000000000..f68f034b94 --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/utils/BinaryReader.ts @@ -0,0 +1,205 @@ +import { common, ECPoint, InvalidFormatError, UInt160, UInt256 } from '@neo-one/client-common'; +import { BN } from 'bn.js'; +import _ from 'lodash'; + +export class BinaryReader { + public readonly buffer: Buffer; + private mutableIndex: number; + + public constructor(buffer: Buffer, index = 0) { + this.buffer = buffer; + this.mutableIndex = index; + } + + public get index(): number { + return this.mutableIndex; + } + + public get remaining(): number { + return this.buffer.length - this.mutableIndex; + } + + public get remainingBuffer(): Buffer { + return this.buffer.slice(this.mutableIndex); + } + + public hasMore(): boolean { + return this.mutableIndex < this.buffer.byteLength; + } + + public clone(): BinaryReader { + return new BinaryReader(this.buffer, this.mutableIndex); + } + + public readBytes(numBytes: number): Buffer { + this.checkRead(numBytes); + const result = this.buffer.slice(this.mutableIndex, this.mutableIndex + numBytes); + this.mutableIndex += numBytes; + + return result; + } + + public readInt8(): number { + this.checkRead(1); + const result = this.buffer.readInt8(this.mutableIndex); + this.mutableIndex += 1; + + return result; + } + + public readUInt8(): number { + this.checkRead(1); + const result = this.buffer.readUInt8(this.mutableIndex); + this.mutableIndex += 1; + + return result; + } + + public readBoolean(): boolean { + return this.readBytes(1)[0] !== 0; + } + + public readInt16LE(): number { + this.checkRead(2); + const result = this.buffer.readInt16LE(this.mutableIndex); + this.mutableIndex += 2; + + return result; + } + + public readUInt16LE(): number { + this.checkRead(2); + const result = this.buffer.readUInt16LE(this.mutableIndex); + this.mutableIndex += 2; + + return result; + } + + public readUInt16BE(): number { + this.checkRead(2); + const result = this.buffer.readUInt16BE(this.mutableIndex); + this.mutableIndex += 2; + + return result; + } + + public readInt32LE(): number { + this.checkRead(4); + const result = this.buffer.readInt32LE(this.mutableIndex); + this.mutableIndex += 4; + + return result; + } + + public readUInt32LE(): number { + this.checkRead(4); + const result = this.buffer.readUInt32LE(this.mutableIndex); + this.mutableIndex += 4; + + return result; + } + + public readUInt64LE(): BN { + return new BN(this.readBytes(8), 'le'); + } + + public readInt64LE(): BN { + const buffer = this.readBytes(8); + + return new BN(buffer, 'le').fromTwos(buffer.length * 8); + } + + // NEO specific + public readUInt160(): UInt160 { + return common.bufferToUInt160(this.readBytes(common.UINT160_BUFFER_BYTES)); + } + + public readUInt256(): UInt256 { + return common.bufferToUInt256(this.readBytes(common.UINT256_BUFFER_BYTES)); + } + + public readFixed8(): BN { + return this.readInt64LE(); + } + + public readFixedString(length: number): string { + const values = _.takeWhile([...this.readBytes(length)], (value) => value !== 0); + + return Buffer.from(values).toString('utf8'); + } + + public readArray(read: () => T, max: BN | number = 0x1000000): readonly T[] { + const count = this.readVarUIntLE(new BN(max)).toNumber(); + + return _.range(count).map(read); + } + + public readObject( + read: () => { readonly key: number; readonly value: V }, + max?: number, + ): { readonly [key: number]: V }; + public readObject( + read: () => { readonly key: string; readonly value: V }, + max?: number, + ): { readonly [key: string]: V }; + public readObject( + read: () => { readonly key: string | number; readonly value: V }, + max = 0x1000000, + ): { readonly [key: string]: V } { + const count = this.readVarUIntLE(new BN(max)).toNumber(); + + return _.range(count).reduce<{ readonly [key: string]: V }>((acc) => { + const { key, value } = read(); + + return { ...acc, [key]: value }; + }, {}); + } + + public readVarBytesLE(max = 0x1000000): Buffer { + return this.readBytes(this.readVarUIntLE(new BN(max)).toNumber()); + } + + public readVarUIntLE(maxIn: BN | number = new BN('18446744073709551615', 10)): BN { + const max = typeof maxIn === 'number' ? new BN(maxIn) : maxIn; + const fb = this.readUInt8(); + let value: BN; + switch (fb) { + case 0xfd: + value = new BN(this.readUInt16LE()); + break; + case 0xfe: + value = new BN(this.readUInt32LE()); + break; + case 0xff: + value = this.readUInt64LE(); + break; + default: + value = new BN(fb); + } + + if (value.gt(max)) { + throw new InvalidFormatError(`Integer too large: ${value.toString(10)} > ${max.toString(10)}`); + } + + return value; + } + + public readVarString(max = 0x1000000): string { + return this.readVarBytesLE(max).toString('utf8'); + } + + public readECPoint(): ECPoint { + const firstByte = this.readBytes(1); + if (firstByte[0] === common.ECPOINT_INFINITY_BYTE) { + return common.ECPOINT_INFINITY; + } + + return common.bufferToECPoint(Buffer.concat([firstByte, this.readBytes(common.ECPOINT_BUFFER_BYTES - 1)])); + } + + private checkRead(numBytes: number): void { + if (this.remaining < numBytes) { + throw new InvalidFormatError(`Insufficient bytes remaining (${this.remaining}): ${numBytes}`); + } + } +} diff --git a/packages/neo-one-smart-contract-compiler/src/utils/disassembleByteCode.ts b/packages/neo-one-smart-contract-compiler/src/utils/disassembleByteCode.ts new file mode 100644 index 0000000000..67a2c5cccc --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/utils/disassembleByteCode.ts @@ -0,0 +1,142 @@ +// tslint:disable prefer-switch +import { Byte, isByteCode, Op, OpCode, toStackItemTypeJSON, toSysCallName, utils } from '@neo-one/client-common'; +import { BinaryReader } from './BinaryReader'; + +export const createHexString = (bytes: Buffer): string => { + let mutableResult = ''; + bytes.forEach((byte) => { + mutableResult += `${byte.toString(16).padStart(2, '0')}`; + }); + + return `0x${mutableResult}`; +}; + +interface Line { + readonly pc: number; + readonly value: string; +} + +export const disassembleByteCode = (bytes: Buffer): readonly Line[] => { + const reader = new BinaryReader(bytes); + + const signedBufferToString = (bytesLength: number) => + utils.fromSignedBuffer(reader.readBytes(bytesLength)).toString(10); + + const mutableResult: Array = []; + // tslint:disable-next-line no-loop-statement + while (reader.hasMore()) { + const pc = reader.index; + const byte = reader.readUInt8(); + if (!isByteCode(byte)) { + mutableResult.push([pc, 'UNKNOWN', undefined]); + continue; + } + + const pushData1 = byte === Op.PUSHDATA1; + const pushData2 = byte === Op.PUSHDATA2; + const pushData4 = byte === Op.PUSHDATA4; + + const opCode = Byte[byte]; + + if (pushData1 || pushData2 || pushData4) { + let numBytes; + if (pushData1) { + numBytes = reader.readUInt8(); + } else if (pushData2) { + numBytes = reader.readUInt16LE(); + } else { + numBytes = reader.readInt32LE(); + } + mutableResult.push([pc, opCode, createHexString(reader.readBytes(numBytes))]); + } else if (byte === Op.PUSHINT8) { + mutableResult.push([pc, opCode, signedBufferToString(1)]); + } else if (byte === Op.PUSHINT16) { + mutableResult.push([pc, opCode, signedBufferToString(2)]); + } else if (byte === Op.PUSHINT32) { + mutableResult.push([pc, opCode, signedBufferToString(4)]); + } else if (byte === Op.PUSHINT64) { + mutableResult.push([pc, opCode, signedBufferToString(8)]); + } else if (byte === Op.PUSHINT128) { + mutableResult.push([pc, opCode, signedBufferToString(16)]); + } else if (byte === Op.PUSHINT256) { + mutableResult.push([pc, opCode, signedBufferToString(32)]); + } else if ( + byte === Op.JMP || + byte === Op.JMPIF || + byte === Op.JMPIFNOT || + byte === Op.JMPEQ || + byte === Op.JMPNE || + byte === Op.JMPGT || + byte === Op.JMPLT || + byte === Op.JMPGE || + byte === Op.JMPLE || + byte === Op.CALL || + byte === Op.ENDTRY + ) { + mutableResult.push([pc, opCode, `${reader.readInt8()}`]); + } else if ( + byte === Op.JMP_L || + byte === Op.JMPIF_L || + byte === Op.JMPIFNOT_L || + byte === Op.JMPEQ_L || + byte === Op.JMPNE_L || + byte === Op.JMPGT_L || + byte === Op.JMPLT_L || + byte === Op.JMPGE_L || + byte === Op.JMPLE_L || + byte === Op.CALL_L || + byte === Op.ENDTRY_L + ) { + mutableResult.push([pc, opCode, `${reader.readInt32LE()}`]); + } else if (byte === Op.PUSHA) { + mutableResult.push([pc, opCode, `${createHexString(reader.readBytes(4))}`]); + } else if ( + byte === Op.LDSFLD || + byte === Op.STSFLD || + byte === Op.LDLOC || + byte === Op.STLOC || + byte === Op.LDARG || + byte === Op.STARG || + byte === Op.INITSSLOT + ) { + mutableResult.push([pc, opCode, `${reader.readUInt8()}`]); + } else if (byte === Op.TRY) { + const catchOffset = reader.readInt8(); + const finallyOffset = reader.readInt8(); + mutableResult.push([pc, opCode, `${catchOffset} ${finallyOffset}`]); + } else if (byte === Op.TRY_L) { + const catchOffset = reader.readInt32LE(); + const finallyOffset = reader.readInt32LE(); + mutableResult.push([pc, opCode, `${catchOffset} ${finallyOffset}`]); + } else if (byte === Op.INITSLOT) { + const localVarSlot = reader.readUInt8(); + const parametersCount = reader.readUInt8(); + mutableResult.push([pc, opCode, `${localVarSlot} ${parametersCount}`]); + } else if (byte === Op.NEWARRAY_T || byte === Op.ISTYPE || byte === Op.CONVERT) { + const type = reader.readUInt8(); + let typeString = `${type}`; + try { + typeString = toStackItemTypeJSON(type); + } catch { + // do nothing + } + mutableResult.push([pc, opCode, typeString]); + } else if (byte === Op.SYSCALL) { + const bytesOut = reader.readBytes(4); + let result = createHexString(bytesOut); + try { + result = toSysCallName(bytesOut.readUInt32BE()); + } catch { + // do nothing + } + mutableResult.push([pc, opCode, result]); + } else { + mutableResult.push([pc, opCode, undefined]); + } + } + + return mutableResult.map(([index, opCode, val]) => ({ + pc: index, + value: `${index.toString().padStart(4, '0')}:${opCode}${val === undefined ? '' : ` ${val}`}`, + })); +}; diff --git a/packages/neo-one-smart-contract-compiler/src/utils/index.ts b/packages/neo-one-smart-contract-compiler/src/utils/index.ts index 144c92cf8f..f9e9e78948 100644 --- a/packages/neo-one-smart-contract-compiler/src/utils/index.ts +++ b/packages/neo-one-smart-contract-compiler/src/utils/index.ts @@ -8,3 +8,4 @@ export * from './nodeKey'; export * from './throwOnDiagnosticErrorOrWarning'; export * from './toABIReturn'; export * from './typeKey'; +export * from './processMethods'; diff --git a/packages/neo-one-smart-contract-compiler/src/utils/processMethods.ts b/packages/neo-one-smart-contract-compiler/src/utils/processMethods.ts new file mode 100644 index 0000000000..63ba0b15da --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/utils/processMethods.ts @@ -0,0 +1,115 @@ +import { ContractMethodDescriptorClient } from '@neo-one/client-common'; +import { utils } from '@neo-one/utils'; +import _ from 'lodash'; +import { SourceMapConsumer } from 'source-map'; +import { SmartContractInfoManifest, SmartContractInfoMethodDescriptor } from '../compile/getSmartContractInfo'; +import { ScriptBuilderResult } from '../compile/types'; +import { Context } from '../Context'; +import { DebugInfo, DebugMethod } from '../contract'; +import { disassembleByteCode } from './disassembleByteCode'; + +export const getJumpLength = (value: string): number => { + const [, unknownOp] = value.split(':'); + const [op, arg] = unknownOp.split(' '); + if (op !== 'JMP' && op !== 'JMP_L') { + throw new Error(`${unknownOp} is not a JMP call`); + } + + return Number(arg); +}; + +export const processMethods = async ({ + // tslint:disable-next-line: no-unused + context, + manifest, + debugInfo, + finalResult, + filePath, +}: { + readonly context: Context; + readonly manifest: SmartContractInfoManifest; + readonly debugInfo: DebugInfo; + readonly finalResult: ScriptBuilderResult; + readonly filePath: string; +}): Promise => { + const methodsIn = manifest.abi.methods; + + if (methodsIn.length !== debugInfo.methods.length) { + throw new Error( + `Expected Manifest methods length ${methodsIn.length} to equal DebugInfo methods length ${debugInfo.methods.length}. Please report.`, + ); + } + + if (methodsIn.length === 0) { + return []; + } + + // TODO: include upgrade and deploy or no? In debug info + const newDebugInfoMethods = _.zipWith( + methodsIn, + debugInfo.methods, + (manMethod: SmartContractInfoMethodDescriptor, debugMethod: DebugMethod) => { + if (manMethod.name !== debugMethod.name) { + throw new Error('Error processing methods. Method names do not match. Please report.'); + } + + if (manMethod.returnType.type !== debugMethod.returnType) { + throw new Error('Error processing methods. Method return types do not match. Please report.'); + } + + return { + manifestMethod: manMethod, + debugMethod, + }; + }, + ); + + const sourceMap = await finalResult.sourceMap; + const byteCode = finalResult.code; + const disassembled = disassembleByteCode(byteCode); + const jmpAddress = getJumpLength(disassembled[3].value); // First jump is now the fourth line + + const getMethodRanges = (consumer: SourceMapConsumer, line: number) => + consumer + .allGeneratedPositionsFor({ + source: filePath, + line, + column: undefined, + // tslint:disable-next-line: no-any + } as any) + .map(({ line: lineOut }) => { + if (lineOut !== null) { + return Number(disassembled[lineOut - 1].pc); + } + throw new Error('Unexpected error mapping source code'); + }) + .sort((a: number, b: number) => (a === b ? 0 : a > b ? 1 : -1)) + .filter((value) => value < jmpAddress); + + return SourceMapConsumer.with( + sourceMap, + // tslint:disable-next-line: no-null-keyword + null, + async (consumer) => + newDebugInfoMethods + .map(({ debugMethod: { range }, manifestMethod }) => { + const methodRange = getMethodRanges(consumer, range[0] + 1); + if (methodRange.length === 0) { + return { + ...manifestMethod, + offset: 0, + }; + // return undefined; // TODO: used to be undefined but we need to make sure methods like "deploy" make it into manifest + // even if it doesn't have any sourcemap mapping. clean this up when fixing how we call contract methods + // a few cases don't generate sourcemaps that we can process like top-level readonly storage + // throw new Error(`Error generating debug information, no map found for method: ${name}`); + } + + return { + ...manifestMethod, + offset: 0, // methodRange[0], // TODO: fix here for calling contracts + }; + }) + .filter(utils.notNull), + ); +}; diff --git a/packages/neo-one-smart-contract-compiler/src/utils/utils.ts b/packages/neo-one-smart-contract-compiler/src/utils/utils.ts new file mode 100644 index 0000000000..5324c96e7a --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/utils/utils.ts @@ -0,0 +1,249 @@ +import { InvalidFormatError, utils as clientUtils, WildcardContainerJSON } from '@neo-one/client-common'; +import BigNumber from 'bignumber.js'; +import { BN } from 'bn.js'; +import { randomBytes } from 'crypto'; +import _ from 'lodash'; +import { StackItem } from '../StackItems'; +import { StorageItem } from '../StorageItem'; +import { BinaryReader } from './BinaryReader'; +import { deserializeStackItem } from './deserializeStackItem'; + +const toASCII = (bytes: Buffer) => { + let result = ''; + _.range(bytes.length).forEach((i) => { + result += String.fromCharCode(bytes.readUInt8(i)); + }); + + return result; +}; + +const toUTF8 = (bytes: Buffer) => bytes.toString('utf8'); + +const calculateClaimAmount = async ({ + coins, + decrementInterval, + generationAmount, + getSystemFee, +}: { + readonly coins: ReadonlyArray<{ + readonly value: BN; + readonly startHeight: number; + readonly endHeight: number; + }>; + readonly decrementInterval: number; + readonly generationAmount: readonly number[]; + readonly getSystemFee: (index: number) => Promise; +}): Promise => { + const grouped = Object.values(_.groupBy(coins, (coin) => `${coin.startHeight}:${coin.endHeight}`)); + + const claimed = await Promise.all( + grouped.map(async (coinsGroup) => { + const { startHeight, endHeight } = coinsGroup[0]; + + let amount = clientUtils.ZERO; + let ustart = Math.floor(startHeight / decrementInterval); + if (ustart < generationAmount.length) { + let istart = startHeight % decrementInterval; + let uend = Math.floor(endHeight / decrementInterval); + let iend = endHeight % decrementInterval; + if (uend >= generationAmount.length) { + uend = generationAmount.length; + iend = 0; + } + + if (iend === 0) { + uend -= 1; + iend = decrementInterval; + } + + // tslint:disable-next-line no-loop-statement + while (ustart < uend) { + amount = amount.addn((decrementInterval - istart) * generationAmount[ustart]); + + ustart += 1; + istart = 0; + } + + amount = amount.addn((iend - istart) * generationAmount[ustart]); + } + + const [sysFeeEnd, sysFeeStart] = await Promise.all([ + getSystemFee(endHeight - 1), + startHeight === 0 ? Promise.resolve(clientUtils.ZERO) : getSystemFee(startHeight - 1), + ]); + + amount = amount.add(sysFeeEnd.sub(sysFeeStart).div(clientUtils.ONE_HUNDRED_MILLION)); + const totalValue = coinsGroup.reduce((acc, { value }) => acc.add(value), clientUtils.ZERO); + + return [totalValue, amount]; + }), + ); + + return claimed.reduce( + (acc, [value, amount]) => acc.add(value.div(clientUtils.ONE_HUNDRED_MILLION).mul(amount)), + clientUtils.ZERO, + ); +}; + +const randomUInt64 = (): BN => new BN(randomBytes(8).toString('hex'), 16); + +const toKeyString = (clazz: { readonly name: string }, toKey: () => string) => () => `${clazz.name}:${toKey()}`; + +function lazyAsync(getValue: (input: Input) => Promise): (input: Input) => Promise { + let valuePromise: Promise | undefined; + + return async (input) => { + if (valuePromise === undefined) { + valuePromise = getValue(input); + } + + return valuePromise; + }; +} + +function lazyOrValue(getValue: (() => Value) | Value): () => Value { + // tslint:disable-next-line no-any + let settings: any = + typeof getValue === 'function' ? { type: 'lazy', getValue } : { type: 'evaluated', value: getValue }; + + return () => { + if (settings.type === 'lazy') { + settings = { type: 'evaluated', value: settings.getValue() }; + } + + return settings.value; + }; +} + +function weightedAverage( + input: ReadonlyArray<{ + readonly value: number; + readonly weight: BigNumber; + }>, +): number { + let sumWeight = new BigNumber(0); + let sumValue = new BigNumber(0); + input.forEach((value) => { + sumWeight = sumWeight.plus(value.weight); + sumValue = sumValue.plus(value.weight.times(value.value)); + }); + + if (sumValue.isEqualTo(0) || sumWeight.isEqualTo(0)) { + return 0; + } + + return sumValue.div(sumWeight).integerValue(BigNumber.ROUND_FLOOR).toNumber(); +} + +function weightedFilter( + input: readonly T[], + startIn: number, + endIn: number, + getValueIn: (value: T) => BN, +): ReadonlyArray { + const start = new BigNumber(startIn); + const end = new BigNumber(endIn); + const getValue = (value: T) => new BigNumber(getValueIn(value).toString(10)); + const amount = input.reduce((acc, value) => acc.plus(getValue(value)), new BigNumber(0)); + + let sum = new BigNumber(0); + let current = new BigNumber(0); + const mutableResult: Array = []; + // tslint:disable-next-line no-loop-statement + for (const value of input) { + if (current.gte(end)) { + break; + } + let weight = getValue(value); + sum = sum.plus(weight); + const old = current; + current = sum.div(amount); + if (current.lte(start)) { + // eslint-disable-next-line + continue; + } + if (old.lt(start)) { + weight = current.gt(end) ? end.minus(start).times(amount) : current.minus(start).times(amount); + } else if (current.gt(end)) { + weight = end.minus(old).times(amount); + } + + mutableResult.push([ + value, + weight.gte(0) ? weight.integerValue(BigNumber.ROUND_FLOOR) : weight.integerValue(BigNumber.ROUND_CEIL), + ]); + } + + return mutableResult; +} + +function equals( + // tslint:disable-next-line no-any readonly-array + clazz: new (...args: any[]) => T, + thiz: T, + equalsFunc: (other: T) => boolean, + // tslint:disable-next-line no-any +): (other: any) => boolean { + return (other): boolean => other != undefined && (thiz === other || (other instanceof clazz && equalsFunc(other))); +} + +const wildCardFromJSON = (json: WildcardContainerJSON, selector: (input: string) => T) => { + if (typeof json === 'string') { + if (json !== '*') { + throw new InvalidFormatError(); + } + + return '*'; + } + if (Array.isArray(json)) { + return json.map(selector); + } + + throw new InvalidFormatError(); +}; + +const getInteroperable = (item: StorageItem, fromStackItem: (item: StackItem) => T): T => { + const buffer = item.value; + const reader = new BinaryReader(buffer); + const deserializedStackItem = deserializeStackItem(reader, 16, 34); + + return fromStackItem(deserializedStackItem); +}; + +const getSerializableArray = ( + value: Buffer, + readValue: (reader: BinaryReader) => T, + max: number | BN = 0x1000000, +): readonly T[] => { + const reader = new BinaryReader(value); + + return reader.readArray(() => readValue(reader), max); +}; + +const getSerializableArrayFromStorageItem = ( + item: StorageItem, + readValue: (reader: BinaryReader) => T, + max: number | BN = 0x1000000, +): readonly T[] => { + const value = item.value; + + return getSerializableArray(value, readValue, max); +}; + +export const utils = { + ...clientUtils, + toASCII, + toUTF8, + calculateClaimAmount, + randomUInt64, + toKeyString, + equals, + lazyAsync, + lazyOrValue, + weightedAverage, + weightedFilter, + wildCardFromJSON, + getInteroperable, + getSerializableArray, + getSerializableArrayFromStorageItem, +}; diff --git a/packages/neo-one-smart-contract-test-common/src/withContracts.ts b/packages/neo-one-smart-contract-test-common/src/withContracts.ts index 1056b9cb4f..974470d3ee 100644 --- a/packages/neo-one-smart-contract-test-common/src/withContracts.ts +++ b/packages/neo-one-smart-contract-test-common/src/withContracts.ts @@ -128,7 +128,9 @@ export const withContracts = async ( if (autoSystemFee) { client.hooks.beforeRelay.tapPromise('AutoSystemFee', async (options) => { // tslint:disable-next-line no-object-mutation - options.systemFee = new BigNumber(-1); + options.maxSystemFee = new BigNumber(-1); + // tslint:disable-next-line no-object-mutation + options.maxNetworkFee = new BigNumber(-1); }); } if (autoConsensus) { @@ -141,7 +143,7 @@ export const withContracts = async ( const deployedContracts = await contracts.reduce>(async (accIn, { filePath, name }) => { const acc = await accIn; - const { contract, sourceMap, abi } = compileContract( + const { contract, sourceMap } = await compileContract( filePath, name, createCompilerHost(), @@ -155,9 +157,15 @@ export const withContracts = async ( let result: TransactionResult; // tslint:disable-next-line prefer-conditional-expression if (deploy) { - result = await client.publishAndDeploy(contract, abi, [], { systemFee: new BigNumber(-1) }, mutableSourceMaps); + result = await client.publishAndDeploy( + contract, + contract.manifest, + ['deploy', []], // TODO: fix contract calling here + { maxSystemFee: new BigNumber(-1), maxNetworkFee: new BigNumber(-1) }, + mutableSourceMaps, + ); } else { - result = await client.publish(contract, { systemFee: new BigNumber(-1) }); + result = await client.publish(contract, { maxSystemFee: new BigNumber(-1), maxNetworkFee: new BigNumber(-1) }); } const [receipt] = await Promise.all([result.confirmed({ timeoutMS: 2500 }), developerClient.runConsensusNow()]); @@ -167,7 +175,7 @@ export const withContracts = async ( const smartContract = client.smartContract({ networks: { [networkName]: { address } }, - abi, + manifest: contract.manifest, sourceMaps: mutableSourceMaps, }); mutableLinked[filePath] = { [name]: address }; diff --git a/packages/neo-one-smart-contract-test/src/createNode.ts b/packages/neo-one-smart-contract-test/src/createNode.ts index 298839907d..b8ca9d95e8 100644 --- a/packages/neo-one-smart-contract-test/src/createNode.ts +++ b/packages/neo-one-smart-contract-test/src/createNode.ts @@ -1,6 +1,6 @@ import { common, crypto } from '@neo-one/client-common'; import { FullNode } from '@neo-one/node'; -import { createMain } from '@neo-one/node-neo-settings'; +import { createPriv } from '@neo-one/node-neo-settings'; import { constants } from '@neo-one/utils'; import _ from 'lodash'; import MemDown from 'memdown'; @@ -14,8 +14,8 @@ export const createNode = async () => { const node = new FullNode({ options: { - blockchain: createMain({ - privateNet: true, + blockchain: createPriv({ + // privateNet: true, // TODO: fix here standbyValidators: [constants.PRIVATE_NET_PUBLIC_KEY], extraCommitteeMembers: [], }), diff --git a/packages/neo-one-smart-contract/src/index.d.ts b/packages/neo-one-smart-contract/src/index.d.ts index a8b9a0d2f7..3c2bd6ec20 100644 --- a/packages/neo-one-smart-contract/src/index.d.ts +++ b/packages/neo-one-smart-contract/src/index.d.ts @@ -65,6 +65,18 @@ export interface AddressConstructor { * @returns true if `Address` signed this `Transaction` */ readonly isSender: (address: Address) => boolean; + /** + * `Address` of the NEO `Contract`. + */ + readonly NEO: Address; + /** + * `Address` of the GAS `Contract`. + */ + readonly GAS: Address; + /** + * `Address` of the Policy `Contract`. + */ + readonly Policy: Address; readonly [OpaqueTagSymbol0]: unique symbol; } @@ -91,14 +103,6 @@ export interface Hash256Constructor { * @returns `Hash256` for the specified `value` */ readonly from: (value: string) => Hash256; - /** - * `Hash256` of the NEO `Asset`. - */ - readonly NEO: Hash256; - /** - * `Hash256` of the GAS `Asset`. - */ - readonly GAS: Hash256; readonly [OpaqueTagSymbol0]: unique symbol; } @@ -151,111 +155,24 @@ export type Fixed8 = Fixed<8>; /** * `Attribute` usage flag indicates the type of the data. * - * @see BufferAttributeUsage - * @see PublicKeyAttributeUsage - * @see AddressAttributeUsage - * @see Hash256AttributeUsage + * @see HighPriorityAttributeUsage */ export enum AttributeUsage { - ContractHash = 0x00, - ECDH02 = 0x02, - ECDH03 = 0x03, - Script = 0x20, - Vote = 0x30, - DescriptionUrl = 0x81, - Description = 0x90, - Hash1 = 0xa1, - Hash2 = 0xa2, - Hash3 = 0xa3, - Hash4 = 0xa4, - Hash5 = 0xa5, - Hash6 = 0xa6, - Hash7 = 0xa7, - Hash8 = 0xa8, - Hash9 = 0xa9, - Hash10 = 0xaa, - Hash11 = 0xab, - Hash12 = 0xac, - Hash13 = 0xad, - Hash14 = 0xae, - Hash15 = 0xaf, - Remark = 0xf0, - Remark1 = 0xf1, - Remark2 = 0xf2, - Remark3 = 0xf3, - Remark4 = 0xf4, - Remark5 = 0xf5, - Remark6 = 0xf6, - Remark7 = 0xf7, - Remark8 = 0xf8, - Remark9 = 0xf9, - Remark10 = 0xfa, - Remark11 = 0xfb, - Remark12 = 0xfc, - Remark13 = 0xfd, - Remark14 = 0xfe, - Remark15 = 0xff, + HighPriority = 0x01, + Reserved = 0xff, // Strange behavior in TypeScript compiler API makes this necessary for now } - -/** - * `Attribute` usage flag indicating the data is an arbitrary `Buffer` - * - * @see BufferAttribute - */ -export type BufferAttributeUsage = - | AttributeUsage.DescriptionUrl - | AttributeUsage.Description - | AttributeUsage.Remark - | AttributeUsage.Remark1 - | AttributeUsage.Remark2 - | AttributeUsage.Remark3 - | AttributeUsage.Remark4 - | AttributeUsage.Remark5 - | AttributeUsage.Remark6 - | AttributeUsage.Remark7 - | AttributeUsage.Remark8 - | AttributeUsage.Remark9 - | AttributeUsage.Remark10 - | AttributeUsage.Remark11 - | AttributeUsage.Remark12 - | AttributeUsage.Remark13 - | AttributeUsage.Remark14 - | AttributeUsage.Remark15; -/** - * `Attribute` usage flag indicating the data is a `PublicKey` - * - * @see PublicKeyAttribute - */ -export type PublicKeyAttributeUsage = AttributeUsage.ECDH02 | AttributeUsage.ECDH03; /** - * `Attribute` usage flag indicating the data is an `Address` + * `Attribute` usage flag indicating the data is high priority. * - * @see AddressAttribute + * @see HighPriorityAttribute */ -export type AddressAttributeUsage = AttributeUsage.Script; +export type HighPriorityAttributeUsage = AttributeUsage.HighPriority; /** - * `Attribute` usage flag indicating the data is a `Hash256` + * `Attribute` placeholder for TypeScript compiler. * - * @see Hash256Attribute + * @see ReservedAttribute */ -export type Hash256AttributeUsage = - | AttributeUsage.ContractHash - | AttributeUsage.Vote - | AttributeUsage.Hash1 - | AttributeUsage.Hash2 - | AttributeUsage.Hash3 - | AttributeUsage.Hash4 - | AttributeUsage.Hash5 - | AttributeUsage.Hash6 - | AttributeUsage.Hash7 - | AttributeUsage.Hash8 - | AttributeUsage.Hash9 - | AttributeUsage.Hash10 - | AttributeUsage.Hash11 - | AttributeUsage.Hash12 - | AttributeUsage.Hash13 - | AttributeUsage.Hash14 - | AttributeUsage.Hash15; +export type ReservedAttributeUsage = AttributeUsage.Reserved; /** * Base interface for `Attribute`s @@ -265,263 +182,84 @@ export type Hash256AttributeUsage = export const AttributeBase: AttributeBaseConstructor; export interface AttributeBase { readonly usage: AttributeUsage; - readonly data: Buffer; readonly [OpaqueTagSymbol0]: unique symbol; } + export interface AttributeBaseConstructor { readonly [OpaqueTagSymbol0]: unique symbol; } -/** - * `Attribute` whose data is an arbitrary `Buffer`. - */ -export interface BufferAttribute extends AttributeBase { - readonly usage: BufferAttributeUsage; - readonly data: Buffer; -} -/** - * `Attribute` whose data is a `PublicKey`. - */ -export interface PublicKeyAttribute extends AttributeBase { - readonly usage: PublicKeyAttributeUsage; - readonly data: PublicKey; -} -/** - * `Attribute` whose data is an `Address`. - */ -export interface AddressAttribute extends AttributeBase { - readonly usage: AddressAttributeUsage; - readonly data: Address; +export interface HighPriorityAttribute extends AttributeBase { + readonly usage: HighPriorityAttributeUsage; } -/** - * `Attribute` whose data is a `Hash256`. - */ -export interface Hash256Attribute extends AttributeBase { - readonly usage: Hash256AttributeUsage; - readonly data: Hash256; + +export interface ReservedAttribute extends AttributeBase { + readonly usage: ReservedAttributeUsage; } /** * `Attribute`s are used to store additional data on `Transaction`s. Most `Attribute`s are used to store arbitrary data, whereas some, like `AddressAttribute`, have specific uses in the NEO - * protocol. + * protocol. The only attribute currently available in the Neo v3 protocol is the "HighPriority" attribute. */ -export type Attribute = BufferAttribute | PublicKeyAttribute | AddressAttribute | Hash256Attribute; +export type Attribute = HighPriorityAttribute | ReservedAttribute; + +export enum WitnessScope { + None = 0x00, + CalledByEntry = 0x01, + CustomContracts = 0x10, + CustomGroups = 0x20, + Global = 0x80, +} +export const WitnessScopeBase: WitnessScopeBaseConstructor; /** - * `Output`s represent the destination `Address` and amount transferred of a given `Asset`. + * Base interface for `WitnessScope` * - * The sum of the unspent `Output`s of an `Address` represent the total balance of the `Address`. + * @see WitnessScope */ -export const Output: OutputConstructor; -export interface Output { - /** - * Destination `Address`. - */ - readonly address: Address; - /** - * `Hash256` of the `Asset` that was transferred. - */ - readonly asset: Hash256; - /** - * Amount transferred. - */ - readonly value: Fixed8; +export interface WitnessScopeBase { + readonly scope: WitnessScope; readonly [OpaqueTagSymbol0]: unique symbol; } -export interface OutputConstructor { + +export interface WitnessScopeBaseConstructor { readonly [OpaqueTagSymbol0]: unique symbol; } -/** - * `Input`s are a reference to an `Output` of a `Transaction` that has been persisted to the blockchain. The sum of the `value`s of the referenced `Output`s is the total amount transferred in the `Transaction`. - */ -export const Input: InputConstructor; -export interface Input { - /** - * `Hash256` of the `Transaction` this input references. - */ - readonly hash: Hash256; - /** - * `Output` index within the `Transaction` this input references. - */ - readonly index: Integer; - readonly [OpaqueTagSymbol0]: unique symbol; +export interface NoneWitnessScope extends WitnessScopeBase { + readonly scope: WitnessScope.None; } -export interface InputConstructor { - readonly [OpaqueTagSymbol0]: unique symbol; + +export interface CalledByEntryWitnessScope extends WitnessScopeBase { + readonly scope: WitnessScope.CalledByEntry; } -/** - * Constants that specify the type of a `Transaction`. - */ -export enum TransactionType { - /** - * First `Transaction` in each block which contains the `Block` rewards for the consensus node that produced the `Block`. - * - * @see MinerTransaction - */ - Miner = 0x00, - /** - * Issues new currency of a first-class `Asset`. - * - * @see IssueTransaction - */ - Issue = 0x01, - /** - * Claims GAS for a set of spent `Output`s. - * - * @see ClaimTransaction - */ - Claim = 0x02, - /** - * Enrolls a new validator for a given `PublicKey`. - * - * @see EnrollmentTransaction - * @deprecated - */ - Enrollment = 0x20, - /** - * Registers a new first class `Asset` - * - * @see RegisterTransaction - * @deprecated Replaced by `Client#registerAsset` - */ - Register = 0x40, - /** - * Transfers first class `Asset`s - * - * @see ContractTransaction - */ - Contract = 0x80, - State = 0x90, - /** - * Registers a new `Contract` - * - * @see PublishTransaction - * @deprecated Replaced by `Client#publish` - */ - Publish = 0xd0, - /** - * Runs a script in the NEO VM. - * - * @see InvocationTransaction - */ - Invocation = 0xd1, +export interface CustomContractsWitnessScope extends WitnessScopeBase { + readonly scope: WitnessScope.CustomContracts; } -/** - * Base interface for all `Transaction`s. - */ -export const TransactionBase: TransactionBaseConstructor; -export interface TransactionBase { - /** - * `Hash256` of this `Transaction`. - */ - readonly hash: Hash256; - /** - * Type of the `Transaction`. - * - * @see TransactionType - */ - readonly type: TransactionType; - /** - * `Attribute`s attached to the `Transaction`. - * - * @see Attribute - */ - readonly attributes: Attribute[]; - /** - * `Output`s of the `Transaction`. - * - * @see Output - */ - readonly outputs: Output[]; - /** - * `Input`s of the `Transaction`. - * - * @see Input - */ - readonly inputs: Input[]; +export interface CustomGroupsWitnessScope extends WitnessScopeBase { + readonly scope: WitnessScope.CustomGroups; +} + +export interface GlobalWitnessScope extends WitnessScopeBase { + readonly scope: WitnessScope.Global; +} + +export const Signer: SignerConstructor; +export interface Signer { /** - * Corresponding `Output`s for the `Input`s of the `Transaction`. - * - * @see Output + * `Address` representing the account of this signer. */ - readonly references: Output[]; + readonly account: Address; /** - * `Output`s which have not been spent. - * - * @see Output + * `Scopes` of this signature. */ - readonly unspentOutputs: Output[]; + readonly scopes: WitnessScope; readonly [OpaqueTagSymbol0]: unique symbol; } -export interface TransactionBaseConstructor {} +export interface SignerConstructor {} -/** - * First `Transaction` in each `Block` which contains the `Block` rewards for the consensus node that produced the `Block`. - */ -export interface MinerTransaction extends TransactionBase { - readonly type: TransactionType.Miner; -} -/** - * Issues new currency of a first-class `Asset`. - */ -export interface IssueTransaction extends TransactionBase { - readonly type: TransactionType.Issue; -} -/** - * Claims GAS for a set of spent `Output`s. - */ -export interface ClaimTransaction extends TransactionBase { - readonly type: TransactionType.Claim; -} -/** - * Enrolls a new validator for a given `PublicKey`. - * - * @deprecated - */ -export interface EnrollmentTransaction extends TransactionBase { - readonly type: TransactionType.Enrollment; -} -/** - * Registers a new first class `Asset`. - * - * @deprecated Replaced by `Client#registerAsset` - */ -export interface RegisterTransaction extends TransactionBase { - readonly type: TransactionType.Register; -} -/** - * `Transaction` that transfers first class `Asset`s. - */ -export interface ContractTransaction extends TransactionBase { - readonly type: TransactionType.Contract; -} -/** - * Contains the state of votes. - */ -export interface StateTransaction extends TransactionBase { - readonly type: TransactionType.State; -} -/** - * Registers a new `Contract` - * - * @deprecated Replaced by `Client#publish` - */ -export interface PublishTransaction extends TransactionBase { - readonly type: TransactionType.Publish; -} -/** - * `Transaction` which runs a script in the NEO VM. - */ -export interface InvocationTransaction extends TransactionBase { - readonly type: TransactionType.Invocation; - /** - * Code that was executed in NEO VM. - */ - readonly script: Buffer; -} /** * `Transaction`s are persisted to the blockchain and represent various functionality like transferring first class `Asset`s or executing smart contracts. * @@ -531,132 +269,60 @@ export interface InvocationTransaction extends TransactionBase { * * const transactionHash = Hash256.from('0xd6572a459b95d9136b7a713c5485ca709f9efa4f08f1c25dd792672d2bd75bfb'); * const transaction = Transaction.for(transactionHash); - * const transactionOutputs = transaction.outputs; * */ export const Transaction: TransactionConstructor; -export type Transaction = - | MinerTransaction - | IssueTransaction - | ClaimTransaction - | EnrollmentTransaction - | RegisterTransaction - | ContractTransaction - | StateTransaction - | PublishTransaction - | InvocationTransaction; -export interface TransactionConstructor { - /** - * @returns `Transaction` for the specified `hash`. - */ - readonly for: (hash: Hash256) => Transaction; - readonly [OpaqueTagSymbol0]: unique symbol; -} - -/** - * Balance and vote information for an `Address`. - * - * @example - * - * const address = Address.from('ALq7AWrhAueN6mJNqk6FHJjnsEoPRytLdW'); - * const account = Account.for(address); - * const neoBalance = account.getBalance(Hash256.NEO); - * - */ -export const Account: AccountConstructor; -export interface Account { - /** - * `Address` of this `Account`. - */ - readonly address: Address; - /** - * Retrieve the balance for a first class `Asset` based on its `Hash256`. - */ - readonly getBalance: (asset: Hash256) => Fixed8; - readonly [OpaqueTagSymbol0]: unique symbol; -} -export interface AccountConstructor { - /** - * @returns `Account` for the specified `address`. - */ - readonly for: (address: Address) => Account; - readonly [OpaqueTagSymbol0]: unique symbol; -} - /** - * Constants that specify the type of the `Asset`. + * Interface for all `Transaction`s. */ -export enum AssetType { - Credit = 0x40, - Duty = 0x80, +export interface Transaction { /** - * Reserved for the NEO `Asset`. + * `Hash256` of this `Transaction`. */ - Governing = 0x00, + readonly hash: Hash256; /** - * Reserved for the GAS `Asset`. + * Neo protocol version. */ - Utility = 0x01, - Currency = 0x08, - Share = 0x90, - Invoice = 0x98, - Token = 0x60, -} - -/** - * Attributes of a first class asset. - * - * Smart contract authors will typically only interact with the NEO and GAS `Asset`s. - * - * @example - * - * const asset = Asset.for(Hash256.NEO); - * const neoAmount = asset.amount; - * - */ -export const Asset: AssetConstructor; -export interface Asset { + readonly version: number; /** - * `Hash256` of this `Asset`. + * Unique number in order to ensure the hash for this contract is unique. */ - readonly hash: Hash256; + readonly nonce: number; /** - * `AssetType` of the `Asset` - * - * @see AssetType + * `Address` of the transaction sender. */ - readonly type: AssetType; + readonly sender: Address; /** - * Total possible supply of the `Asset` + * GAS execution fee for the transaction. */ - readonly amount: Fixed8; + readonly systemFee: number; /** - * Amount currently available of the `Asset` + * GAS network priority fee for the transaction. */ - readonly available: Fixed8; + readonly networkFee: number; /** - * Precision (number of decimal places) of the `Asset` + * Block expiration time. */ - readonly precision: Integer; + readonly validUntilBlock: number; /** - * Owner of the `Asset`. + * The index of the `Transaction` within the `Block` */ - readonly owner: PublicKey; + readonly height: number; /** - * Admin of the `Asset`. + * Code that was executed in NEO VM. */ - readonly admin: Address; + readonly script: Buffer; /** - * Issuer of the `Asset`. + * `Notification`s emitted by the `Transaction`. */ - readonly issuer: Address; + // readonly notifications: Notification[]; readonly [OpaqueTagSymbol0]: unique symbol; } -export interface AssetConstructor { +export interface TransactionConstructor { /** - * @returns `Asset` for the specified `hash`. + * @returns `Transaction` for the specified `hash`. */ - readonly for: (hash: Hash256) => Asset; + readonly for: (hash: Hash256) => Transaction; readonly [OpaqueTagSymbol0]: unique symbol; } @@ -677,7 +343,15 @@ export interface Contract { */ readonly script: Buffer; /** - * Flag that indicates if the `Contract` supports receiving `Asset`s. + * A string representation of the contract's manifest + */ + readonly manifest: string; + /** + * If `true` then contract uses blockchain storage. + */ + readonly hasStorage: boolean; + /** + * If `true` then contract is payable. */ readonly payable: boolean; readonly [OpaqueTagSymbol0]: unique symbol; @@ -692,17 +366,63 @@ export interface ContractConstructor { readonly [OpaqueTagSymbol0]: unique symbol; } +// export enum StackItemType { +// Any = 0x00, +// Pointer = 0x10, +// Boolean = 0x20, +// Integer = 0x21, +// ByteString = 0x28, +// Buffer = 0x30, +// Array = 0x40, +// Struct = 0x41, +// Map = 0x48, +// InteropInterface = 0x60, +// } + +// export interface StackItemBase { +// readonly type: StackItemType; +// } + +// export interface BufferStackItem extends StackItemBase { +// readonly type: StackItemType.Buffer; +// readonly value: Buffer; +// } + +// export type StackItem = BufferStackItem; + +// /** +// * +// */ +// export interface Notification { +// /** +// * +// */ +// readonly scriptHash: Address; +// /** +// * The name of the notification event. "Transfer" in the event of a transfer. +// */ +// readonly eventName: string; +// /** +// * +// */ +// readonly state: StackItem[]; +// } + /** - * Attributes of a `Block` persisted to the blockchain. `Header` includes all information except the list of `Transaction`s. + * Attributes of a `Block` persisted to the blockchain. + * + * @example + * + * const genesisBlock = Block.for(0); * * @example * * const blockHash = Hash256.from('0xd6572a459b95d9136b7a713c5485ca709f9efa4f08f1c25dd792672d2bd75bfb'); - * const header = Header.for(blockHash); + * const arbitraryBlock = Block.for(blockHash); * */ -export const Header: HeaderConstructor; -export interface Header { +export const Block: BlockConstructor; +export interface Block { /** * `Block` hash. */ @@ -731,32 +451,10 @@ export interface Header { * Next consensus address. */ readonly nextConsensus: Address; - readonly [OpaqueTagSymbol0]: unique symbol; -} -export interface HeaderConstructor { - /** - * Accepts either the `Hash256` or the index of the `Block`. - * - * @returns `Header` for the specified `hashOrIndex`. - */ - readonly for: (hashOrIndex: Hash256 | Integer) => Header; - readonly [OpaqueTagSymbol0]: unique symbol; -} - -/** - * Attributes of a `Block` persisted to the blockchain. - * - * @example - * - * const genesisBlock = Block.for(0); - * - */ -export const Block: BlockConstructor; -export interface Block extends Header { /** - * `Transaction`s contained in the `Block`. + * The number of `Transaction`s contained in the `Block`. */ - readonly transactions: Transaction[]; + readonly transactionsLength: Integer; } export interface BlockConstructor { /** @@ -1041,9 +739,9 @@ export interface BlockchainConstructor { */ readonly currentHeight: number; /** - * `InvocationTransaction` this smart contract is executed in. + * `Transaction` this smart contract is executed in. */ - readonly currentTransaction: InvocationTransaction; + readonly currentTransaction: Transaction; /** * The `Address` of the smart contract that directly invoked the contract. * @@ -1286,15 +984,59 @@ type IsValidSmartContract = { }; /** - * Object with string literals for the contract properties to be used in deployment. + * Object that defines a contract group for use in deployment. + * + * See the [Deployment](https://neo-one.io/docs/deployment#Properties) chapter of the main guide for more information. + */ +export interface ContractGroup { + /** + * The public key of the group. + */ + readonly publicKey: string; + /** + * The signature of the contract hash. + */ + readonly signature: string; +} + +/** + * Object that defines a contract permission for use in deployment. + * + * See the [Deployment](https://neo-one.io/docs/deployment#Properties) chapter of the main guide for more information. + */ +export interface ContractPermission { + /** + * An object indicating the contract to be invoked. It can be the hash of a single contract or the public key of a contract group. + * If it specifies the hash of a contract then the contract can be invoked. + * If it specifies the public key of a group, then any contract in this group can be invoked + * If this object has hash and group as undefined then this will be considered a wildcard ("*") and any contract can be invoked. + */ + readonly contract: { readonly hash?: string; readonly group?: string }; + /** + * An array of methods that are allowed to be called. An empty array means that no methods will be allowed to be called. This can also be a wildcard string: "*", which means that any method can be called. + */ + readonly methods: string | readonly string[]; +} + +/** + * Object with literals for the contract properties to be used in deployment. * * See the [Deployment](https://neo-one.io/docs/deployment#Properties) chapter of the main guide for more information. */ export interface ContractProperties { - readonly codeVersion: string; - readonly author: string; - readonly email: string; - readonly description: string; + /** + * A group represents a set of mutually trusted contracts. A contract will trust and allow any contract in the same group to invoke it, and the user interface will not give any warnings. + */ + readonly groups: readonly ContractGroup[]; + /** + * The permissions field is an array containing a set of `ContractPermission` objects. It describes which contracts may be invoked and which methods are called. + */ + readonly permissions: readonly ContractPermission[]; + /** + * The trusts field is an array containing a set of contract hashes or group public keys. It can also be assigned with a wildcard *. If it is a wildcard *, then it means that this contract trusts any contract. + * If a contract is trusted, the user interface will not give any warnings when called by the contract. + */ + readonly trusts: string | readonly string[]; } /** @@ -1311,24 +1053,6 @@ export class SmartContract { * `Address` of the `SmartContract`. */ public readonly address: Address; - /** - * Stores `Transaction` hashes that have been processed by a method marked with `@receive`, `@send`, or `@sendUnsafe`. - * - * Used to enforce that a `Transaction` with native `Asset`s is only ever processed once by an appropriate `@receive`, `@send`, or `@sendUnsafe` method. - * - * Unprocessed transactions that sent assets to the smart contract can be refunded by using `refundAssets`. - * - * See the [Native Assets](https://neo-one.io/docs/native-assets) chapter of the advanced guide for more information. - */ - protected readonly processedTransactions: SetStorage; - /** - * Stores `Transaction` hashes that have been claimed by an address with a method marked with `@send`. - * - * The first contract output of a claimed transaction may be sent to the receiver by using `completeSend`. - * - * See the [Native Assets](https://neo-one.io/docs/native-assets) chapter of the advanced guide for more information. - */ - protected readonly claimedTransactions: MapStorage; /** * Property primarily used internally to validate that the smart contract is deployed only once. */ @@ -1357,34 +1081,12 @@ export class SmartContract { * See the [Deployment](https://neo-one.io/docs/deployment#Destroy) chapter of the main guide for more information. */ protected readonly destroy: () => void; - /** - * Method automatically added for refunding native `Asset`s. - * - * See the [Native Assets](https://neo-one.io/docs/native-assets) chapter of the advanced guide for more information. - */ - public readonly refundAssets: () => boolean; - /** - * Method automatically added for sending native `Asset`s that have been claimed by a `@send` method. - * - * See the [Native Assets](https://neo-one.io/docs/native-assets) chapter of the advanced guide for more information. - */ - public readonly completeSend: () => boolean; /** * Used internally by client APIs to upgrade the contract. Control whether an invocation is allowed to upgrade the contract by overriding `approveUpgrade`. * * See the [Deployment](https://neo-one.io/docs/deployment#Upgrade) chapter of the main guide for more information. */ - public readonly upgrade: ( - script: Buffer, - parameterList: Buffer, - returnType: number, - properties: number, - contractName: string, - codeVersion: string, - author: string, - email: string, - description: string, - ) => boolean; + public readonly upgrade: (script: Buffer, manifest: Buffer) => boolean; /** * Returns the singleton instance of the `SmartContract` defined by the interface `T` at `address`. * @@ -1439,16 +1141,16 @@ export type Hashable = number | string | boolean | Buffer; * Contains various cryptography functions. */ export interface CryptoConstructor { - /** - * Returns a `Buffer` of the SHA1 hash of the input - */ - readonly sha1: (value: Hashable) => Buffer; /** * Returns a `Buffer` of the SHA256 hash of the input */ readonly sha256: (value: Hashable) => Buffer; /** - * Returns a `Buffer` of the RMD160 hash of the SHA256 hash of the input. + * Returns a `Buffer` of the RIPEMD160 hash of the input. + */ + readonly ripemd160: (value: Hashable) => Address; + /** + * Returns a `Buffer` of the RIPEMD160 hash of the SHA256 hash of the input. */ readonly hash160: (value: Hashable) => Address; /** diff --git a/packages/neo-one-utils/src/constants.ts b/packages/neo-one-utils/src/constants.ts index 3192caf1e9..26b3a0fa3d 100644 --- a/packages/neo-one-utils/src/constants.ts +++ b/packages/neo-one-utils/src/constants.ts @@ -3,4 +3,8 @@ export const constants = { PRIVATE_NET_WIF: 'L4qhHtwbiAMu1nrSmsTP5a3dJbxA3SNS6oheKnKd8E7KTJyCLcUv', PRIVATE_NET_PRIVATE_KEY: 'e35fa5d1652c4c65e296c86e63a3da6939bc471b741845be636e2daa320dc770', PRIVATE_NET_PUBLIC_KEY: '0248be3c070df745a60f3b8b494efcc6caf90244d803a9a72fe95d9bae2120ec70', + PRIVATE_NET_ADDRESS: 'NfZhRHq4fxKHcH8yidE3fubHVypbxc1Ht2', + PRIVATE_NET_SCRIPT_HASH: '0xaf6e1dd6d44f5adff2f2973354abf831fd088dd7', + PRIVATE_NET_CONSENSUS_ADDRESS: 'NfdKztHauMe8n8HnSbzCUZCNfQY7gToy2q', + PRIVATE_NET_CONSENSUS_SCRIPT_HASH: '0x51b2dd775a36b91db9e6b79b39b536505ad13cd8', }; diff --git a/packages/neo-one-website/docs/0-installation/1-environment-setup.md b/packages/neo-one-website/docs/0-installation/1-environment-setup.md index 05b10e51ae..348c03e327 100644 --- a/packages/neo-one-website/docs/0-installation/1-environment-setup.md +++ b/packages/neo-one-website/docs/0-installation/1-environment-setup.md @@ -31,6 +31,8 @@ This page describes how to setup NEO•ONE using `yarn` or `npm`. **Once you have a project setup**, the next step is to add NEO•ONE to it. NEO•ONE is organized into multiple individual packages. Use as much or as little as you like. Each package may be installed using either [yarn](https://yarnpkg.com/) (`yarn add `) or [npm](https://www.npmjs.com/) (`npm install `). Each package has the form `@neo-one/`, for example, `@neo-one/client`. +Make sure to install the correct versions of these packages. If you are working on Neo2 then make sure you are installing NEO•ONE packages at version 2.x.x or lower. Version 3.0.0 or higher will be for Neo3. + Install all the neo-one packages with yarn by running: ```bash diff --git a/packages/neo-one-website/docs/1-main-concepts/03-standard-library.md b/packages/neo-one-website/docs/1-main-concepts/03-standard-library.md index 31b8794340..50bec9be16 100644 --- a/packages/neo-one-website/docs/1-main-concepts/03-standard-library.md +++ b/packages/neo-one-website/docs/1-main-concepts/03-standard-library.md @@ -63,3 +63,105 @@ The `Blockchain` value contains several properties pertaining to the current sta If you look at the definition file for the standard library, you might notice a property `OpaqueTagSymbol0`, `OpaqueTagSymbol1`, `one0` or `one1` that is present on all types, including global types like `Array` or `Map`. In order to emit the most efficient NEO VM bytecode possible, we have specialized implementations of all of the standard library types. One limitation of this approach, however, is that you must explicitly use the types. For example, you can't pass an `Array` where an `Array`-like but not `Array` interface is expected. Adding the `OpaqueTagSymbol0`, `OpaqueTagSymbol1`, `one0`, or `one1` properties helps enforce this as a static type error, but it does not catch all cases (though we're working on improving this). As a rule of thumb, don't rely on ["Duck Typing"](https://en.wikipedia.org/wiki/Duck_typing), instead always be explicit about the types you're using. + +## JavaScript Semantics + +The NEO•ONE compiler is as close to regular TypeScript as possible. But there are a few areas where our compiler does not exactly match normal JavaScript semantics. These areas almost never come up, but could cause strange behavior if you are expecting your Smart Contract code to behave exactly like JavaScript. One of those is when using native `Map`s and `Set`s. In normal JavaScript if you use a structural type as a key in a `Map` or a member in a `Set`, you can only retrieve that key/member later if it's the same reference. Trying to retrieve that key/member with the same value of a different reference will not work in regular JavaScript. But it WILL work in our compiler. The best way to demonstrate this is with examples. + +### `Set` Example + +This test would pass in regular TS: + +```typescript +const x = new Set>(); +const y = [0]; +const z = [0]; +x.add(y).add(z); + +assertEqual(x.has(y), true); +assertEqual(x.has(z), true); +assertEqual(x.has([0]), false); // notice difference here +assertEqual(x.size, 2); // notice difference here + +x.delete(y); +assertEqual(x.delete(z), true); // notice difference here +assertEqual(x.delete(z), false); +assertEqual(x.size, 0); +assertEqual(x.has(y), false); +assertEqual(x.has(z), false); +``` + +But this test will pass in our TS compiler: + +```typescript +const x = new Set>(); +const y = [0]; +const z = [0]; +x.add(y).add(z); + +assertEqual(x.has(y), true); +assertEqual(x.has(z), true); +assertEqual(x.has([0]), true); // notice difference here +assertEqual(x.size, 1); // notice difference here + +x.delete(y); +assertEqual(x.delete(z), false); // notice difference here +assertEqual(x.delete(z), false); +assertEqual(x.size, 0); +assertEqual(x.has(y), false); +assertEqual(x.has(z), false); +``` + +### `Map` Example + +This test would pass in regular TS: + +```typescript +const x = new Map, string>(); +const y = [0]; +const z = [0]; +x.set(y, 'bar').set(z, 'baz'); + +assertEqual(x.get(y), 'bar'); // notice difference here +assertEqual(x.has(y), true); +assertEqual(x.get(z), 'baz'); +assertEqual(x.has(z), true); +assertEqual(x.get([0]), undefined); // notice difference here +assertEqual(x.has([0]), false); // notice difference here +assertEqual(x.size, 2); // notice difference here + +x.delete(y); +assertEqual(x.delete(z), true); // notice difference here +assertEqual(x.delete(z), false); +assertEqual(x.size, 0); +assertEqual(x.get(y), undefined); +assertEqual(x.has(y), false); +assertEqual(x.get(z), undefined); +assertEqual(x.has(z), false); +``` + +But this test will pass in our TS compiler: + +```typescript +const x = new Map, string>(); +const y = [0]; +const z = [0]; +x.set(y, 'bar').set(z, 'baz'); + +assertEqual(x.get(y), 'baz'); // notice difference here +assertEqual(x.has(y), true); +assertEqual(x.get(z), 'baz'); +assertEqual(x.has(z), true); +assertEqual(x.get([0]), 'baz'); // notice difference here +assertEqual(x.has([0]), true); // notice difference here +assertEqual(x.size, 1); // notice difference here + +x.delete(y); +assertEqual(x.delete(z), false); // notice difference here +assertEqual(x.delete(z), false); +assertEqual(x.size, 0); +assertEqual(x.get(y), undefined); +assertEqual(x.has(y), false); +assertEqual(x.get(z), undefined); +assertEqual(x.has(z), false); +``` diff --git a/packages/neo-one-website/docs/1-main-concepts/12-deployment.md b/packages/neo-one-website/docs/1-main-concepts/12-deployment.md index 396684c765..b31b3555d8 100644 --- a/packages/neo-one-website/docs/1-main-concepts/12-deployment.md +++ b/packages/neo-one-website/docs/1-main-concepts/12-deployment.md @@ -130,7 +130,7 @@ This will ensure that after deploying the `ico` contract (and confirming it is d Once you have successfully configured your `migration` file as explained above you are all set to deploy your Smart Contract! Using the set of [networks](/docs/config-options) defined in `.neo-one.config.js` you can deploy using the command: ```bash -yarn neo-one deploy -- +yarn neo-one deploy --network ``` where `network` is one of the keys provided by your configuration. By default `yarn neo-one deploy` will use the `test` key. diff --git a/packages/neo-one-website/docs/3-node/4-build-from-source.md b/packages/neo-one-website/docs/3-node/4-build-from-source.md index daec147b88..5dc6431243 100644 --- a/packages/neo-one-website/docs/3-node/4-build-from-source.md +++ b/packages/neo-one-website/docs/3-node/4-build-from-source.md @@ -63,10 +63,10 @@ can be run using node neo-one-node --config /path/to/config.json ``` -individual options can also be layered on top of our configuration +Individual options can also be layered on top of our configuration: ```bash node neo-one-node --config /path/to/config.json --environment.logger.level=trace ``` -Finally you have the option of adding a `.neo-onerc` app configuration file anywhere in the app directory (recommended at `/neo-one/`) to apply you configuration by default; See [rc](https://github.com/dominictarr/rc#rc). +Finally you have the option of adding a `.neo-onerc` app configuration file anywhere in the app directory (recommended at `/neo-one/`) to apply your configuration by default. See [rc](https://github.com/dominictarr/rc#rc) for more information on `rc` files. diff --git a/packages/neo-one-website/docs3/0-installation/0-getting-started.md b/packages/neo-one-website/docs3/0-installation/0-getting-started.md new file mode 100644 index 0000000000..aeed1587a2 --- /dev/null +++ b/packages/neo-one-website/docs3/0-installation/0-getting-started.md @@ -0,0 +1,86 @@ +--- +slug: getting-started +title: Getting Started +--- + +This page is an overview of the NEO•ONE documentation and related resources. + +**NEO•ONE** makes coding, testing and deploying NEO dapps easy, fast, efficient and enjoyable. + +--- + +[[toc]] + +--- + +## Try NEO•ONE + +NEO•ONE has been designed as a full end-to-end toolkit for building NEO dapps. From developing a smart contract, to testing, to interacting with it from your front-end, the entire dapp lifecycle is covered with NEO•ONE. However, it's not necessary to use NEO•ONE for every part of your dapp, you can pick and choose the parts of NEO•ONE that make sense for your development. + +The links in this section will help you get started. + +### Courses + +If you're interested in playing around with NEO•ONE or you prefer to **learn by doing**, check out [NEO•ONE Courses](/course). As you work through the first two lessons you'll experience the entire development lifecycle of a dapp by deploying a fully functioning ICO, from the smart contract that powers it all to the UI that enables participation. All directly from your browser - no environment setup required. + +### Tutorial + +If you'd prefer to use your own editor, you can work through the [NEO•ONE Tutorial](/tutorial). The tutorial covers roughly the same content as the first course and by the end of it you'll be ready to start building your own unique dapp. + +### Playground + +Setup the [NEO•ONE Playground](/docs/playground) repository to get a feel for NEO•ONE in a real-world setting. Try modifying the smart contracts, adding to the tests or playing with the UI. Once you're comfortable, you can even try adding your own dapp! + +--- + +## Learn NEO•ONE + +NEO•ONE covers the entire development lifecycle of a dapp, so it's best to learn it one step at a time. + +### First Examples + +The [NEO•ONE Homepage](/) contains a full editor with a simplified token smart contract example and tests. Even if you don't know anything about building dapps, check it out to see what's possible. + +### TypeScript Resources + +NEO•ONE is written in TypeScript and the documentation assumes some familiarity with TypeScript. If you've never used TypeScript before, or it's been a while, keep the [TypeScript documentation](https://www.typescriptlang.org/docs/handbook/basic-types.html) handy while working through the NEO•ONE documentation. + +Prefer JavaScript or don't want to use TypeScript? No problem! NEO•ONE smart contracts are the only part of the framework that requires coding in TypeScript, otherwise you're free to use either JavaScript or TypeScript. + +### Blockchain Resources + +The majority of the documentation assumes general familiarity with blockchain and the NEO blockchain in particular. Check out the [Blockchain Basics](/docs/blockchain-basics) chapter of the main guide if you are unfamiliar with the general blockchain concepts or need a refresher. + +### Step-by-Step Guide + +If you'd prefer to just get an overview of NEO•ONE and learn about the core concepts, check out the [guide to main concepts](/docs/hello-world). Every chapter builds on the knowledge introduced in previous chapters so you won't miss a thing. + +### Advanced Guides + +Once you're comfortable with the main concepts and have built some simple dapps with NEO•ONE, you might be interested in some of the more advanced features NEO•ONE has to offer. The advanced guides section will introduce you to some less commonly used, but powerful, features. + +### API Reference + +This documentation section is useful for learning about specific details of the NEO•ONE API. For example, the [@neo-one/smart-contract API reference](/reference/@neo-one/smart-contract) can provide details on the APIs available for smart contracts. + +--- + +## Staying Informed + +The [NEO•ONE blog](/blog) is the official source of updates from the NEO•ONE team. Here you will find things like release notes and deprecation notices. + +Additionally, you can get the same updates by following [@neo-one-suite](https://twitter.com/neo_one_suite) on Twitter. + +Finally, feel free to chat with us directly on the [NEO•ONE Discord](https://discord.gg/S86PqDE). + +--- + +## Help + +Need help? NEO•ONE is developed by community members just like you. Contributors are often around and available for questions. First, see if you can find what you're looking for in the docs. If you can't find the answer, come chat with us in the [#support](https://discord.gg/S86PqDE) channel in the NEO•ONE Discord community. Many members of the community also use Stack Overflow. Read through [existing questions](https://stackoverflow.com/questions/tagged/neo-one) tagged with **neo-one** or [ask your own](https://stackoverflow.com/questions/ask)! + +--- + +## Something Missing? + +If something is missing from the NEO•ONE documentation or you found something confusing, please submit an issue to the [NEO•ONE GitHub](https://github.com/neo-one-suite/neo-one) with your suggestions. You can also tweet [@neo-one-suite](https://twitter.com/neo_one_suite) or let us know directly on the [NEO•ONE Discord](https://discord.gg/S86PqDE). We'd love to hear from you! diff --git a/packages/neo-one-website/docs3/0-installation/1-environment-setup.md b/packages/neo-one-website/docs3/0-installation/1-environment-setup.md new file mode 100644 index 0000000000..7c75068e4f --- /dev/null +++ b/packages/neo-one-website/docs3/0-installation/1-environment-setup.md @@ -0,0 +1,94 @@ +--- +slug: environment-setup +title: Environment Setup +--- + +NEO•ONE was designed to get your dapp up and running quickly. + +This page describes how to setup NEO•ONE using `yarn` or `npm`. + +--- + +[[toc]] + +--- + +## Requirements + +- [Node](https://nodejs.org) >= 10.16.0 (We recommend the latest version) + - Linux and Mac: We recommend using [Node Version Manager](https://github.com/creationix/nvm). + - Windows: We recommend using [Chocolatey](https://chocolatey.org/). + +--- + +## Installation + +**If you're just getting started**, try out one of the following toolchains for setting up your project: + +- [Create React App](https://github.com/facebook/create-react-app) - Generates a [React](https://reactjs.org/) starter app. +- [Angular CLI](https://cli.angular.io/) - Generates an [Angular](https://angular.io/) starter app. +- [Vue CLI](https://cli.vuejs.org/) - Generate a [Vue](https://vuejs.org/) starter app. + +**Once you have a project setup**, the next step is to add NEO•ONE to it. NEO•ONE is organized into multiple individual packages. Use as much or as little as you like. Each package may be installed using either [yarn](https://yarnpkg.com/) (`yarn add `) or [npm](https://www.npmjs.com/) (`npm install `). Each package has the form `@neo-one/`, for example, `@neo-one/client`. + +Make sure to install the correct versions of these packages. If you are working on Neo3 then make sure you are installing NEO•ONE packages at version 3.0.0 or higher. + +Install all the neo-one packages with yarn by running: + +```bash +yarn add @neo-one/client @neo-one/cli @neo-one/smart-contract @neo-one/smart-contract-test @neo-one/smart-contract-lib @neo-one/smart-contract-typescript-plugin +``` + +Install all the neo-one packages with npm by running: + +```bash +npm install @neo-one/client @neo-one/cli @neo-one/smart-contract @neo-one/smart-contract-test @neo-one/smart-contract-lib @neo-one/smart-contract-typescript-plugin +``` + +and then follow the [main guide](/docs/hello-world) or the [tutorial](/tutorial). By the end of it you'll know which features of NEO•ONE you're using and which packages to keep. + +Know what you want to use from NEO•ONE? Read on to see which packages to install for specific functionality. + +For interacting with smart contracts, you should install + +- `@neo-one/client` - Main entrypoint to the most common NEO•ONE client APIs. + +For local network and smart contract management, you should install + +- `@neo-one/cli` - Provides the `neo-one` cli command which manages common tasks like building and deploying smart contracts and spinning up local networks. + +In addition to the above, if you're developing TypeScript smart contracts using NEO•ONE, you should install + +- `@neo-one/smart-contract` - TypeScript smart contract standard library. +- `@neo-one/smart-contract-test` - TypeScript smart contract testing utilitiees. +- `@neo-one/smart-contract-lib` - Template library for common smart contract patterns. +- `@neo-one/smart-contract-typescript-plugin` - TypeScript language server plugin for inline compiler diagnostics in your favorite IDE. + +### Update + +```bash +#npm update @neo-one/cli +yarn upgrade @neo-one/cli +``` + +### Editor Setup + +Configure your IDE to use your local TypeScript installation and the `@neo-one/smart-contract-typescript-plugin` in order to take advantage of inline compiler diagnostics. These instructions are for [VSCode](https://code.visualstudio.com/), but they should be similar for any editor that supports TypeScript IntelliSense. + +1. Ensure `@neo-one/cli` and `@neo-one/smart-contract-typescript-plugin` are installed. +2. Run `yarn neo-one init` or `npx neo-one init`. This will create a `tsconfig.json` file in the configured smart contract directory (by default, `neo-one/contracts/tsconfig.json`). +3. Open a TypeScript file, then click the TypeScript version number in the lower right hand side of your editor and choose "Use Workspace Version" + +That's it! Enjoy inline smart contract compiler diagnostics. + +## Javascript Environment Requirements + +NEO•ONE depends on several types which older browser may not support. NEO•ONE requires the collection types [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) as well as [Symbol.asyncIterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator). If you support older browsers and devices which may not yet provide these natively, consider including a global polyfill in your bundled application, such as [core-js](https://github.com/zloirock/core-js) or [babel-polyfill](https://babeljs.io/docs/en/babel-polyfill/). + +To polyfill an environment for NEO•ONE using core-js, include the following lines at the top of your entry point. + +```typescript +import 'core-js/es/map'; +import 'core-js/es/set'; +import 'core-js/es/symbol/async-iterator'; +``` diff --git a/packages/neo-one-website/docs3/0-installation/2-cli.md b/packages/neo-one-website/docs3/0-installation/2-cli.md new file mode 100644 index 0000000000..1ceb3b3472 --- /dev/null +++ b/packages/neo-one-website/docs3/0-installation/2-cli.md @@ -0,0 +1,103 @@ +--- +slug: cli +title: CLI +--- + +The NEO•ONE CLI is your entry point for all of NEO•ONE's functionality. + +Run `yarn neo-one --help` to see the CLI commands available and their descriptions. +Run `yarn neo-one --help` to see what arguments are available for that command. +Run `yarn neo-one --version` to get the version of NEO•ONE that you are running. + +--- + +[[toc]] + +--- + +## neo-one init + +Initializes a new project in the current directory. This will create a default `.neo-one.config.ts` configuration file, +a sample `Hello World` smart contract in `neo-one/contracts/HelloWorld.ts`, and a unit test in +`src/__tests__/HelloWorld.ts`. + +| Argument | Type | Default | Description | +| --------- | --------- | ------- | -------------------------------------------------------------------------------------------------------- | +| `--react` | `boolean` | `false` | Setting this to true will generate an example. React component that uses the `HelloWorld` smart contract | + +--- + +## neo-one build + +Builds the project and deploys it to the local development network based on the configuration found in the +NEO•ONE config file. + +| Argument | Type | Default | Description | +| --------- | --------- | ------- | ------------------------------------------------- | +| `--reset` | `boolean` | `false` | Setting this to true will reset the local project | + +--- + +## neo-one new + +Create new resources. `neo-one new private-key` is the only available option for now, which will generate a +new private key. + +--- + +## neo-one start + +Start NEO•ONE services. This command takes one argument after the command (`neo-one start `) which +can be either `network` or `neotracker`. `neo-one start network` will start the local development network. +`neo-one start neotracker` will start the local NEO Tracker instance. + +--- + +## neo-one stop + +Stop NEO•ONE services. This command takes one argument after the command (`neo-one stop `) which +can be either `network` or `neotracker`. `neo-one stop network` will stop the local development network. +`neo-one stop neotracker` will stop the local NEO Tracker instance. + +--- + +## neo-one deploy + +Deploys the project using the migration file. + +| Argument | Type | Default | Description | +| ----------- | -------- | -------- | ------------------------------- | +| `--network` | `string` | `"test"` | Network to run the migration on | + +--- + +## neo-one info + +Prints the project configuration. + +--- + +## neo-one compile + +Compiles a project's smart contracts and outputs the code to a local directory. You can set the arguments for this command +either in the NEO•ONE config file (`.neo-one.config.ts`) or as a CLI argument. A CLI argument will override what is found in the +config file. If an argument is not defined as a CLI argument and is not defined in the config file then the below defaults will be used. + +| Argument | Type | Default | Description | +| ----------- | --------- | ------------------- | ---------------------------------------------------------------------------- | +| `--outDir` | `string` | `neo-one/compiled` | Directory to output the compiled code | +| `--path` | `string` | `neo-one/contracts` | Path to the smart contract directory | +| `--json` | `boolean` | `true` | Output the contract with the JSON format | +| `--avm` | `boolean` | `false` | Output the contract with the AVM format | +| `--debug` | `boolean` | `false` | Output additional debug information | +| `--opcodes` | `boolean` | `false` | Output the AVM in a human-readable format for debugging (requires `--debug`) | + +--- + +## neo-one console + +Starts a REPL with project contracts and NEO•ONE Client APIs. + +| Argument | Type | Default | Description | +| ------------ | ------- | ----------- | ----------------------------------------------- | +| `--networks` | `array` | `["local"]` | Networks to initialize before starting the REPL | diff --git a/packages/neo-one-website/docs3/0-installation/3-playground.md b/packages/neo-one-website/docs3/0-installation/3-playground.md new file mode 100644 index 0000000000..28f46c17c3 --- /dev/null +++ b/packages/neo-one-website/docs3/0-installation/3-playground.md @@ -0,0 +1,63 @@ +--- +slug: playground +title: Playground +--- + +The NEO•ONE Playground showcases what's possible with NEO•ONE. + +This guide will walk you through getting started with the [NEO•ONE Playground](https://github.com/neo-one-suite/neo-one-playground). + +--- + +[[toc]] + +--- + +## Requirements + +- [Node](https://nodejs.org) >= 10s.16.0 (We recommend the latest version) +- a package manager: [yarn](https://yarnpkg.com/) **OR** npm (distributed with Node) + +--- + +## Installation + +```bash +git clone https://github.com/neo-one-suite/neo-one-playground.git +cd neo-one-playground +# npm install +yarn install +``` + +--- + +## Compile + +```bash +# npx neo-one build +yarn neo-one build +``` + +This will start up a local network, compile the smart contracts located in the `neo-one/contracts` directory and publish them to your local network. Add `--watch` to listen for changes to the smart contracts and trigger automatic recompilation and deployment. + +--- + +## Start the Playground + +```bash +# npm start +yarn start +``` + +This will open a browser window with the playground. Modify the files in the `src` directory to get a feel for using the NEO•ONE client APIs. + +--- + +## Run the tests + +```bash +# npm test +yarn test +``` + +Smart contract tests in the playground are written in Jest and are located in the `src/__tests__` directory. Play around with them to see how easy it is to test smart contracts! diff --git a/packages/neo-one-website/docs3/0-installation/config.json b/packages/neo-one-website/docs3/0-installation/config.json new file mode 100644 index 0000000000..ef25c89ade --- /dev/null +++ b/packages/neo-one-website/docs3/0-installation/config.json @@ -0,0 +1,4 @@ +{ + "title": "Installation", + "numbered": false +} diff --git a/packages/neo-one-website/docs3/1-main-concepts/00-hello-world.md b/packages/neo-one-website/docs3/1-main-concepts/00-hello-world.md new file mode 100644 index 0000000000..d6ce4aa70d --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/00-hello-world.md @@ -0,0 +1,48 @@ +--- +slug: hello-world +title: Hello World +--- + +The smallest NEO•ONE smart contract looks like this + +```typescript +export class HelloWorld extends SmartContract {} +``` + +This smart contract doesn't do a whole lot, in fact it does nothing, but this is the smallest compilable smart contract. + +--- + +[[toc]] + +--- + +## How to Read This Guide + +In this guide, we will work through creating a dapp with NEO•ONE starting from writing the smart contract, to building and deploying the smart contract, to testing the smart contract, and all the way up to interacting with the smart contract from a dapp UI. Once you master the basics through this guide, you'll be able to create complex dapps using NEO•ONE. + +::: warning + +Tip + +This guide is designed for people who prefer **learning concepts step by step**. If instead you'd like to learn by doing, check out [NEO•ONE Courses](/course) or the [tutorial](/tutorial). This guide can also serve as a complementary resource to the courses and tutorial. + +::: + +This chapter provides an overview and serves as the first chapter in a step-by-step guide about the main NEO•ONE concepts. In the navigation sidebar you'll find a list of all its chapters. On a mobile device, access the guide navigation by pressing the button in the bottom right corner of your screen. + +Each chapter in this guide builds on the lessons learned in earlier chapters. **You can learn most of NEO•ONE by reading the “Main Concepts” guide chapters in the order they appear in the sidebar.** If you plan to use only one piece of NEO•ONE, then you might find it useful to skip around to the parts that are relevant to you. + +--- + +## Expected Knowledge + +NEO•ONE is a JavaScript library so we'll assume you have a basic understanding of the JavaScript language. **If you're not sure, we recommend taking a [JavaScript tutorial](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript) to check your knowledge level**. It might take some time to complete, but then you won't be trying to learn both NEO•ONE and JavaScript at the same time. + +NEO•ONE itself is written in [TypeScript](http://www.typescriptlang.org/) and throughout the guide we will use TypeScript, however the guide assumes no prior knowledge. We will introduce TypeScript specific concepts as they're used, with links to documentation to learn more. + +--- + +## Let's Get Started! + +At the bottom of each page in the guide, including this one, you'll find the link to the [next chapter of the guide](/docs/blockchain-basics) right before the website footer. diff --git a/packages/neo-one-website/docs3/1-main-concepts/01-blockchain-basics.md b/packages/neo-one-website/docs3/1-main-concepts/01-blockchain-basics.md new file mode 100644 index 0000000000..942e82b71a --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/01-blockchain-basics.md @@ -0,0 +1,94 @@ +--- +slug: blockchain-basics +title: Blockchain Basics +--- + +Blockchain can be a complex concept, but this chapter should help distill down the most important parts required to become an effective dapp developer. + +We'll take a look at some of the foundational technologies of blockchain and learn how they each contribute to the larger picture. If you feel like you already have a strong grasp of blockchain fundamentals and just want to learn about NEO blockchain specifics, feel free to skip to the NEO Specifics section. + +--- + +[[toc]] + +--- + +## Peer to Peer Network + +Blockchain is a large peer to peer network, which means that there is no centralized server or authority. We typically refer to a peer in a blockchain network as a **node**. Each node is equal, though in some blockchains certain nodes have more responsibilities than others by taking on a specific role within the network ecosystem, such as that of a block producing node (sometimes called a miner). Some nodes are referred to as a full node which means they hold a copy of the entire blockchain on a single device. This adds resiliency to the network, as long as a single full node exists with a full copy of the blockchain, the network can be rebuilt. This is one of the key advantages to blockchain compared to traditional client-server models; there is no central point of failure, making it far less vulnerable to being exploited or lost. There is no central or dominant authority and no single party can control the network for their own gain. Blockchain networks are therefore both _distributed_ and _decentralized_. + +--- + +## Cryptography + +Blockchain uses cryptography to maintain network integrity. Once something is recorded on the blockchain, anyone can verify that it was done so legitimately and in a manner that preserves security. In particular, blockchain employs [public-key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography) to secure communication on the network. Public-key cryptography enables users to digitally sign a message with a private key, typically represented as a string of random characters. Anyone can verify that they signed the message using the associated public key for that private key. The public key is generated directly from the private key in a way that cannot be reversed while still enabling the ability to verify that a given digital signature was produced by a particular (unknown) private key. Through public-key cryptography, blockchain is capable of ensuring that any data being recorded onto it has not been tampered with. + +::: warning + +Note + +The public key is typically referred to as the address of a user. In some blockchains, like NEO, a public key is further encoded to produce a valid address. + +::: + +--- + +## Hashing + +A hash function takes an input of any length and uses a mathematical algorithm to produce a fixed length output. Cryptographic hashing takes this one step further by making the hash cryptographically secure. In summary, a cryptographic hash function has several qualities: + +1. Impossible to produce the same hash value from different inputs. +2. The same input will always produce the same hash value. +3. Computationally inexpensive to produce a hash value. +4. Impossible to determine the input based on the hash value. + +Another way to think about hashing is that it produces a unique digital fingerprint of the input. In blockchain, we see hashes everywhere. Transaction hashes are produced by hashing the contents of the transaction and are often referred to as the transaction id or TXID. Block hashes are produced by hashing the contents of the block. + +--- + +## Blockchain Data Structure + +Blockchain at it's core is just a data structure. It's a linked list of blocks where links are direct references to the previous block's hash. Since the previous block's hash is part of the content of the block, it makes it difficult to tamper with the blockchain. For example, changing the 10th block in the blockchain would change the hash of not only that block, but every block afterwards, making changes easy to detect. + +In addition to the hash of the previous block, block's contain: + +1. Root of the transaction hash tree (Merkle Tree). +2. Timestamp at which the block was produced. +3. Index of the block within the blockchain +4. Transactions (not included in the hash, instead the root of Merkle Tree is included) + +::: warning + +Note + +You might be wondering why a [Merkle Tree](https://en.wikipedia.org/wiki/Merkle_tree) is used rather than just hashing the list of transactions. In short, a Merkle Tree is an efficient way to not only produce the hash of a given set of hashes, but also to enable verification that a given hash exists within the set. + +::: + +Transactions are simply a store of data. In Bitcoin, for example, they are comprised of a data structure of inputs and outputs that represent financial transactions. This system is called unspent transaction outputs, or UTXO, for short. NEO adopts this system for its native assets, NEO and GAS, which we'll discuss more later in this chapter. + +In NEO as well as other smart contract platforms like Ethereum, the transaction also contains the script to run on the platform's virtual machine. + +--- + +## Consensus + +Consensus is the mechanism by which the peer-to-peer networks comes to agreement on the next block to add to the blockchain. There are two main consensus algorithms, Proof of Work (PoW) and Proof of Stake (PoS), from which many variations are produced. PoW requires miner nodes to solve cryptographic puzzles in order to earn the right to add blocks to the chain. PoS requires block producing nodes to stake value (currency) in order to earn the right to add blocks to the chain. In both cases, nodes are incentivized to act honestly and to not produce blocks that have been tampered with or break the rules of the blockchain. The key insight is that acting dishonestly is both easily detectable by other nodes on the network and that by having a block rejected there is an economic penalty. In PoW the economic penalty comes in the form of cost to produce the block - that is, the pure resource cost (energy, price of equipment) required to solve the cryptographic puzzles. In PoS the economic penalty results from a punishment for acting dishonestly, that is, a portion of the staked currency is taken by the network. + +Delegated Proof of Stake (dPOS) works in a similar way to PoS, however instead of block producing nodes staking to earn the right to produce blocks, the users of the network vote on nodes with weight proportional to their holdings. In this system nodes are incentivized to act honestly, otherwise they will be voted out. Voters are incentivized to vote for nodes that will act honestly because the integrity of the network is at stake, and thus the value of their holdings. + +--- + +## NEO Specifics + +NEO's blockchain data structure is very similar to other blockchains and the general outline we gave above. Like Bitcoin, NEO uses the UTXO model for its native assets, NEO and GAS. Like Ethereum, NEO is a full smart contract platform with its own virtual machine. + +One differentiating factor to be aware of is that NEO has several different types of transactions that can be included in a block; we'll list the most important ones below: + +1. `ContractTransaction` - Used for transferring native assets. May only contain inputs and outputs. +2. `InvocationTransaction` - Used for invoking smart contracts. May contain inputs and outputs. +3. `ClaimTransaction` - Used for claiming accrued GAS + +Take a look at the [@neo-one/client](/reference/@neo-one/client) reference for more details on the specific properties stored on each transaction type. Note the final transaction in that list, the `ClaimTransaction`, refers to claiming GAS. GAS is produced every block and allocated to every NEO holder in proportion to their holdings. NEO holders claim their GAS by submitting a `ClaimTransaction` to the network. GAS is used to "fuel" the network; it's used primarily for transaction fees and is also meant as the primary currency. NEO, on the other hand, is meant to represent ownership of the network and is used only for voting and generating GAS. + +NEO uses a form of dPOS called Delegated Byzantine Fault Tolerance (dBFT). While we won't go into detail on the algorithm, the key differentiator of dBFT is that it results in one block finality. Once a block has been propagated on the network it cannot be reversed. Contrast this with most blockchain consensus algorithms which can have anywhere from 6 blocks to 40 or more block finality. NEO holders vote in consensus nodes which participate in producing new blocks via dBFT. diff --git a/packages/neo-one-website/docs3/1-main-concepts/02-smart-contract-basics.md b/packages/neo-one-website/docs3/1-main-concepts/02-smart-contract-basics.md new file mode 100644 index 0000000000..e39a2d37a1 --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/02-smart-contract-basics.md @@ -0,0 +1,61 @@ +--- +slug: smart-contract-basics +title: Smart Contract Basics +--- + +NEO•ONE enables writing NEO smart contracts in TypeScript. This chapter will cover the basics of smart contract authoring. + +--- + +[[toc]] + +--- + +## Why TypeScript? + +The first question you might ask is "why should I write my smart contract in TypeScript?" Aside from the many benefits of first-class integration in the NEO•ONE toolchain, there are many standalone advantages to NEO•ONE TypeScript smart contracts. + +1. TypeScript smart contracts enforce strict static types, adding an extra safety net of protection against bugs in your code compared to untyped languages. +2. We can offer an experience that is almost identical to writing normal TypeScript code that runs in the browser or in Node, due to strong support for leveraging the TypeScript type checker within the NEO•ONE compiler. +3. TypeScript has a strong and growing ecosystem built around it - linters, editor support, documentation and tutorials. +4. With inline NEO•ONE compiler diagnostics (in addition to the normal TypeScript diagnostics), you're never left wondering if a particular piece of syntax or logic is supported by the NEO•ONE compiler. + +The NEO•ONE toolchain currently only supports TypeScript smart contracts due to the wealth of static type information they provide. In the future we'd like to support other languages, but for now we highly recommend writing your smart contracts in TypeScript, even if you've never written TypeScript before. + +--- + +## Toolchain + +If you haven't already, prepare your project by following the instructions in the [Environment Setup](/docs/environment-setup) section. + +The NEO•ONE toolchain expects all smart contracts in your project to be contained within one parent folder. By default, that folder is `one/contracts`, though this location is [configurable](/docs/config-options). The main command you'll use from the NEO•ONE toolchain is: + +```bash +neo-one build +``` + +This command compiles your smart contracts, sets up a local private network, deploys your smart contracts to that network and generates testing utilities and client APIs for interacting with your smart contract. Appending the command with `--watch` will watch for changes in your smart contracts and automatically run the build command. + +--- + +## First Steps + +Every NEO•ONE smart contract starts with a TypeScript source file that exports a single [class](https://www.typescriptlang.org/docs/handbook/classes.html) extending `SmartContract`. The simplest smart contract looks like: + +```typescript +export class HelloWorld extends SmartContract {} +``` + +::: warning + +Note + +Throughout the guide and examples elsewhere in the documentation, we will refrain from explicitly importing values to keep the examples short and to the point. All values that are not global can be imported from `'@neo-one/smart-contract'` + +::: + +--- + +## Mental Model + +While the above smart contract is just a shell and doesn't look like it does much, it does have an implicit `constructor` which allows us to create new instances of the class using `new HelloWorld()`. However, unlike a normal TypeScript program, we won't ever explicitly construct instances of a smart contract. Instead, the way to think about your smart contract is that on deployment to the blockchain we automatically construct an instance of it. We then use that one instance for all smart contract method calls. In essence, the smart contract class follows the [singleton pattern](https://en.wikipedia.org/wiki/Singleton_pattern). diff --git a/packages/neo-one-website/docs3/1-main-concepts/03-standard-library.md b/packages/neo-one-website/docs3/1-main-concepts/03-standard-library.md new file mode 100644 index 0000000000..50bec9be16 --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/03-standard-library.md @@ -0,0 +1,167 @@ +--- +slug: standard-library +title: Standard Library +--- + +NEO•ONE includes a library of standard smart contract values, functions, interfaces and classes. + +This chapter will go into detail on some of the more common values and types that we will use throughout the guide. While working through the rest of the chapters you may want to keep this page handy. + +For more details, check out the [Smart Contract](/reference/@neo-one/smart-contract) reference. + +--- + +[[toc]] + +--- + +## Value Types + +The standard library includes several specialized value types which are defined in a way that makes them difficult to use incorrectly. For example, it's a static compile time error to pass an `Address` where a `Hash256` is expected, even though both are really just [`Buffer`s](https://nodejs.org/api/buffer.html) underneath the hood. + +- `Address` - a `Buffer` that represents a NEO address. +- `Hash256` - a `Buffer` that represents a NEO 256 bit hash, most commonly used for asset ids like `NEO` or `GAS` asset ids. +- `PublicKey` - a `Buffer` that represents a public key. + +Each of the value types can be created from a string literal using the `from` [static method](https://www.typescriptlang.org/docs/handbook/classes.html#static-properties), for example, `Address.from('APyEx5f4Zm4oCHwFWiSTaph1fPBxZacYVR')`. `Hash256` also contains static properties for the `NEO` and `GAS` `Hash256` values. + +The `Address` type has a commonly used static method, `isCaller`, which is used to check that the passed `Address` directly called and approved the current method invocation. + +```typescript +Address.isCaller(address); +``` + +`Address.isCaller` should be used whenever you want to take an action for a given `Address`. For example, you would want to check `Address.isCaller(address)` before transferring tokens from the `address` to another party. + +--- + +## Tagged Types + +Tagged types are the same as their underlying type, but we've "tagged" them with a piece of compile-time data. NEO•ONE currently contains two tagged types, and their tags are used exclusively for generating the corresponding NEO•ONE client APIs for the smart contract. The most common tagged type and the only one we'll use throughout the guide is the `Fixed` type. + +The `Fixed` type tags a `number` with the number of decimals that it represents. All `number`s in TypeScript smart contracts are integers since there are no floating point values in smart contracts. However, we typically consider the values we're working with to have decimals from the user's point of view and `Fixed` helps capture that notion. + +For example, the `Fixed<2>` type tells the NEO•ONE toolchain that the integer value represents a fixed point decimal with 2 places. In other words, when we have the value `1250` in a smart contract, it really means `12.50` to the user. The NEO•ONE toolchain uses this information to generate client APIs that automatically convert from the integer representation to the decimal point representation and visa-versa. + +This makes it easy to do things like display the result of a smart contract method invocation that returns a `Fixed<2>`. Simply convert it to a string since the client APIs have already converted it to the decimal representation. Similarly, for dapp inputs, simply take the user's decimal value and pass it directly to the NEO•ONE client APIs, under the hood it will convert appropriately. + +--- + +## Blockchain and Transaction Information + +The `Blockchain` value contains several properties pertaining to the current state of the blockchain, the current transaction and the current invocation: + +- `Blockchain.currentBlockTime` - the timestamp of the `Block` that this `Transaction` will be included in. +- `Blockchain.currentHeight` - index of the last `Block` persisted to the blockchain. +- `Blockchain.currentTransaction` - the current `InvocationTransaction`. +- `Blockchain.currentCallerContract` - the `Address` of the smart contract that directly invoked this contract. May be `undefined` if the current invocation was not from another smart contract. + +--- + +## Opaque Tag Symbol + +If you look at the definition file for the standard library, you might notice a property `OpaqueTagSymbol0`, `OpaqueTagSymbol1`, `one0` or `one1` that is present on all types, including global types like `Array` or `Map`. In order to emit the most efficient NEO VM bytecode possible, we have specialized implementations of all of the standard library types. One limitation of this approach, however, is that you must explicitly use the types. For example, you can't pass an `Array` where an `Array`-like but not `Array` interface is expected. Adding the `OpaqueTagSymbol0`, `OpaqueTagSymbol1`, `one0`, or `one1` properties helps enforce this as a static type error, but it does not catch all cases (though we're working on improving this). + +As a rule of thumb, don't rely on ["Duck Typing"](https://en.wikipedia.org/wiki/Duck_typing), instead always be explicit about the types you're using. + +## JavaScript Semantics + +The NEO•ONE compiler is as close to regular TypeScript as possible. But there are a few areas where our compiler does not exactly match normal JavaScript semantics. These areas almost never come up, but could cause strange behavior if you are expecting your Smart Contract code to behave exactly like JavaScript. One of those is when using native `Map`s and `Set`s. In normal JavaScript if you use a structural type as a key in a `Map` or a member in a `Set`, you can only retrieve that key/member later if it's the same reference. Trying to retrieve that key/member with the same value of a different reference will not work in regular JavaScript. But it WILL work in our compiler. The best way to demonstrate this is with examples. + +### `Set` Example + +This test would pass in regular TS: + +```typescript +const x = new Set>(); +const y = [0]; +const z = [0]; +x.add(y).add(z); + +assertEqual(x.has(y), true); +assertEqual(x.has(z), true); +assertEqual(x.has([0]), false); // notice difference here +assertEqual(x.size, 2); // notice difference here + +x.delete(y); +assertEqual(x.delete(z), true); // notice difference here +assertEqual(x.delete(z), false); +assertEqual(x.size, 0); +assertEqual(x.has(y), false); +assertEqual(x.has(z), false); +``` + +But this test will pass in our TS compiler: + +```typescript +const x = new Set>(); +const y = [0]; +const z = [0]; +x.add(y).add(z); + +assertEqual(x.has(y), true); +assertEqual(x.has(z), true); +assertEqual(x.has([0]), true); // notice difference here +assertEqual(x.size, 1); // notice difference here + +x.delete(y); +assertEqual(x.delete(z), false); // notice difference here +assertEqual(x.delete(z), false); +assertEqual(x.size, 0); +assertEqual(x.has(y), false); +assertEqual(x.has(z), false); +``` + +### `Map` Example + +This test would pass in regular TS: + +```typescript +const x = new Map, string>(); +const y = [0]; +const z = [0]; +x.set(y, 'bar').set(z, 'baz'); + +assertEqual(x.get(y), 'bar'); // notice difference here +assertEqual(x.has(y), true); +assertEqual(x.get(z), 'baz'); +assertEqual(x.has(z), true); +assertEqual(x.get([0]), undefined); // notice difference here +assertEqual(x.has([0]), false); // notice difference here +assertEqual(x.size, 2); // notice difference here + +x.delete(y); +assertEqual(x.delete(z), true); // notice difference here +assertEqual(x.delete(z), false); +assertEqual(x.size, 0); +assertEqual(x.get(y), undefined); +assertEqual(x.has(y), false); +assertEqual(x.get(z), undefined); +assertEqual(x.has(z), false); +``` + +But this test will pass in our TS compiler: + +```typescript +const x = new Map, string>(); +const y = [0]; +const z = [0]; +x.set(y, 'bar').set(z, 'baz'); + +assertEqual(x.get(y), 'baz'); // notice difference here +assertEqual(x.has(y), true); +assertEqual(x.get(z), 'baz'); +assertEqual(x.has(z), true); +assertEqual(x.get([0]), 'baz'); // notice difference here +assertEqual(x.has([0]), true); // notice difference here +assertEqual(x.size, 1); // notice difference here + +x.delete(y); +assertEqual(x.delete(z), false); // notice difference here +assertEqual(x.delete(z), false); +assertEqual(x.size, 0); +assertEqual(x.get(y), undefined); +assertEqual(x.has(y), false); +assertEqual(x.get(z), undefined); +assertEqual(x.has(z), false); +``` diff --git a/packages/neo-one-website/docs3/1-main-concepts/04-properties-and-storage.md b/packages/neo-one-website/docs3/1-main-concepts/04-properties-and-storage.md new file mode 100644 index 0000000000..05d7a27b10 --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/04-properties-and-storage.md @@ -0,0 +1,78 @@ +--- +slug: properties-and-storage +title: Properties and Storage +--- + +NEO•ONE stores persistent data in the class properties of the smart contract. + +--- + +[[toc]] + +--- + +## Properties and Accessors + +Using the mental model of a singleton instance of our smart contract, it becomes clear that all properties of the smart contract are automatically persisted between invocations of the smart contract, just like a normal class instance. In TypeScript we can declare several types of instance properties of a class - [private, protected, public and readonly](https://www.typescriptlang.org/docs/handbook/classes.html#public-private-and-protected-modifiers). The following example explores each of these: + +```typescript +export class HelloWorld extends SmartContract { + public mutableString = 'goodnightMoon'; + public readonly string = 'goodnightMoon'; + protected mutableNumber = 0; + protected readonly number = 0; + private mutableBoolean = true; + private readonly boolean = true; +} +``` + +Each property uses the property initializer syntax which sets the initial value at construction. + +One thing to consider in the mental model of smart contracts is that at a low-level smart contracts only have methods. So when we define a `public` `readonly` property, it will be translated to a method of the same name that takes no arguments and returns the current value of the property. A `public` mutable property, like `mutableString` above, will translate to two methods, a method of the same name that takes no arguments and returns the current value of the property and a method called `set` that takes one argument and sets the value of that property to the argument. For example, `mutableString` will translate to `mutableString` and `setMutableString` methods. + +[Property accessors](https://www.typescriptlang.org/docs/handbook/classes.html#accessors) work identically to properties in terms of the low-level translation to exposed smart contract methods. + +::: warning + +Note + +Properties declared as `protected` or `private` are only "private" within the scope of TypeScript - all NEO smart contracts have fully public storage, so no property is ever truly private. In other words, do not store sensitive data within a `private` property with the expectation that no one can view it + +::: + +--- + +## Structured Storage + +Properties work well for storing primitive values and while you can use an `Array`, `Set` or `Map` as a property for storing structured data, this will store the entire container in a single key in smart contract storage. This is not very efficient, so instead NEO•ONE offers similarly named `ArrayStorage`, `SetStorage` and `MapStorage` classes. These classes are special in that they may only be used as properties of a smart contract class: + +```typescript +export class HelloWorld extends SmartContract { + private readonly mapStorage = MapStorage.for(); + private readonly setStorage = SetStorage.for(); + private readonly arrayStorage = ArrayStorage.for(); +} +``` + +Notice that we construct the structured storage classes using the [static](https://www.typescriptlang.org/docs/handbook/classes.html#static-properties) `for` method and 1-2 [type parameters](https://www.typescriptlang.org/docs/handbook/generics.html), which makes it read as " for ". For example, the `mapStorage` property is a "MapStorage for string to number". + +Aside from the limitations mentioned above, each of the structured storage classes work identically to their `Array`, `Set` and `Map` counterparts. + +--- + +## Storage Types + +The only limitation on storage types is that you cannot use an instance of a class or a functon. This is because we cannot reliably serialize and deserialize arbitrary instances when we store the values in the underlying smart contract storage. For similar reasons, we cannot store arbitrary functions. However, you may declare a `readonly` property that is a function. This can be useful for declaring event notifiers as properties of the class: + +```typescript +export class Contract extends SmartContract { + private readonly notifyTransfer = createEventNotifier
>( + 'transfer', + 'from', + 'to', + 'amount', + ); +} +``` + +We'll learn more about event notifiers in a later chapter of the guide. diff --git a/packages/neo-one-website/docs3/1-main-concepts/05-methods.md b/packages/neo-one-website/docs3/1-main-concepts/05-methods.md new file mode 100644 index 0000000000..05ce14a9bc --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/05-methods.md @@ -0,0 +1,66 @@ +--- +slug: methods +title: Methods +--- + +Methods are the core component of smart contract logic. + +--- + +[[toc]] + +--- + +## Constructor + +The constructor of the smart contract is invoked exactly once on deployment of the smart contract. The constructor can have parameters so that you can deploy with different values on the MainNet vs TestNet vs a local private network, but they must always have a [default](https://www.typescriptlang.org/docs/handbook/functions.html#optional-and-default-parameters) value. The default value is used during automatic deployment to your local private network during manual testing, as well as to the private network used during automated unit tests, so it's typically best to choose defaults that tailor to those two deployments. For example, you might set a time dependent property to a parameter with a default that is computed based on the current time, or you might set an `Address` property, such as the owner, to the current sender address: + +```typescript +export class HelloWorld extends SmartContract { + public constructor( + // Blockchain.currentBlockTime contains the timestamp of the current block, i.e. the block that + // the transaction which invoked this method is included in. + public readonly startTime = Blockchain.currentBlockTime + 60 * 60, + // Deploy.senderAddress is a special property that is filled in with the Address + // of the user who deployed the contract. + public readonly owner = Deploy.senderAddress, + ) {} +} +``` + +Note in this example we've used [parameter properties](https://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties) which are a shortcut for declaring a constructor parameter and instance property with a single declaration. + +--- + +## Instance Methods + +Public instance methods come in several flavors but they effectively break down into 3 categories: + +1. Normal instance methods. These have no restrictions and work identically to instance methods in normal TypeScript. +2. Constant instance methods. Designated with the `@constant` decorator, these methods may not modify smart contract properties. These methods can be called by any contract. Even if the contract's manifest specifies trusted contracts, trusted groups, and permissions, any contract will be able to call a method marked as `@constant`. +3. Native asset instance methods. Designated with the `@receive`, `@sendUnsafe`, `@send` and `@claim` decorators. Read more about these in the [Native Assets](/docs/native-assets) advanced guide. + +Public instance methods define the API of the smart contract. In the following example we have two methods. One is a constant method since it's decorated with `@constant`. The other is a normal instance method which modifies the smart contract property `mutableClosing`. + +```typescript +export class HelloWorld extends SmartContract { + private mutableClosing = 'goodbye'; + + public setClosing(closing: string): void { + this.mutableClosing = closing; + } + + @constant + public goodbyeMoon(value: string): string { + return `${this.mutableClosing} ${value}`; + } +} +``` + +Private and protected instance methods are just helper methods, same as normal TypeScript, but be aware that any private or protected methods invoked from a public method must respect the restrictions of the public method. For example, you can't call a private or protected method which modifies a smart contract property from a `@constant` public method. + +--- + +## Parameter and Return Types + +Similar to storage properties, parameter and return types for public instance methods may not be classes or functions. diff --git a/packages/neo-one-website/docs3/1-main-concepts/06-events-and-logs.md b/packages/neo-one-website/docs3/1-main-concepts/06-events-and-logs.md new file mode 100644 index 0000000000..eebe7136be --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/06-events-and-logs.md @@ -0,0 +1,45 @@ +--- +slug: events-and-logs +title: Events and Logs +--- + +Smart contracts may emit events to allow listeners to _react_ to changes in smart contract state. + +--- + +[[toc]] + +--- + +## Events + +Decentralized apps commonly need to know the current state of a smart contract, sometimes by employing a centralized storage solution, For example, they may employ a relational database to store the current state in a more efficiently queryable way. Rather than poll the smart contract for the entire state every block, we can react to events emitted by the contract which represent the important state changes. + +Create an event notifier using `createEventNotifier` and then call it to emit an event: + +```typescript +const notifyActionHappened = createEventNotifier>('actionHappened', 'target', 'value'); + +export class HelloWorld extends SmartContract { + public action(target: Address, value: Fixed<8>): boolean { + notifyActionHappened(target, value); + + return true; + } +} +``` + +The `createEventNotifier` function requires an event name as the first argument, and any number of strings that define the event parameter names as the following arguments. For each event parameter name, you must define the type of that parameter using a [type parameter](http://www.typescriptlang.org/docs/handbook/generics.html). In the example above, we've defined an event called `'actionHappened'` with two parameters: + +1. `target` which is an `Address` +2. `value` which is a `Fixed<8>` + +Events must be unique throughout a smart contract. + +--- + +## Debugging with Logs + +Smart contract debugging with NEO•ONE is as simple as adding a `console.log` statement wherever you would in a normal JavaScript program to aid in debugging. All types can be logged as well as converted to strings in a similar fashion to `console.log` in a JavaScript program. The logs will be printed in your terminal when executing smart contract methods through Node. They will also be printed to the developer tools console in your browser. + +Don't forget to remove the `console.log` statements before going to production! diff --git a/packages/neo-one-website/docs3/1-main-concepts/07-calling-smart-contracts.md b/packages/neo-one-website/docs3/1-main-concepts/07-calling-smart-contracts.md new file mode 100644 index 0000000000..564918219b --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/07-calling-smart-contracts.md @@ -0,0 +1,71 @@ +--- +slug: calling-smart-contracts +title: Calling Smart Contracts +--- + +Smart contracts are not very useful in isolation, they typically interact with other smart contracts that make up the building blocks of a larger piece of infrastructure. + +--- + +[[toc]] + +--- + +## Calling One of Your Smart Contracts + +Calling another one of your smart contracts requires using `LinkedSmartContract.for`. Given the following contract in `Foo.ts`: + +```typescript +export class Foo extends SmartContract { + public takeAction(): boolean { + return true; + } +} +``` + +We can get the singleton instance of `Foo` using `LinkedSmartContract.for()`: + +```typescript +import { Foo } from './Foo'; + +export class Bar extends SmartContract { + public callOtherContract(): boolean { + const foo = LinkedSmartContract.for(); + return foo.takeAction(); + } +} +``` + +Once we have an instance of the contract we can access any of its public properties and methods. Events from the original contract are also propagated automatically and are made available in the NEO•ONE client APIs. + +--- + +## Calling an Arbitrary Smart Contract + +Continuing from the examples above, let's say we want to invoke the `takeAction` method of a smart contract at a given arbitrary `Address`. Similar to `LinkedSmartContract.for`, we can get the instance of the smart contract using `SmartContract.for(address)` where `address` is the `Address` of the smart contract: + +```typescript +interface Foo { + readonly takeAction: () => boolean; +} +declareEvent('actionTaken', 'value'); + +export class Bar extends SmartContract { + public callOtherContract(address: Address): boolean { + const foo = SmartContract.for(address); + return foo.takeAction(); + } +} +``` + +Notice that we also have to define the interface of the smart contract explicitly. The instance returned by `SmartContract.for` will match the interface we've defined and then we can access any of its public properties and methods. + +We also have to declare the events we expect to be emitted by the underlying contract explicitly using `declareEvent`. The `declareEvent` method works the same as `createEventNotifier` except it does not return a function that can be called to emit an event. Instead, it just informs the NEO•ONE toolchain that there are additional events that it needs to register with the NEO•ONE client APIs. + +::: warning + +Note + +A common, but advanced, usage pattern for invoking other arbitrary smart contract is to forward argument values to the invoked method. See the advanced guide on [Forward Values](/docs/forward-values) to learn more. + +::: diff --git a/packages/neo-one-website/docs3/1-main-concepts/08-client-apis.md b/packages/neo-one-website/docs3/1-main-concepts/08-client-apis.md new file mode 100644 index 0000000000..79196f7afd --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/08-client-apis.md @@ -0,0 +1,156 @@ +--- +slug: client-apis +title: Client APIs +--- + +Now it's time to take a look at the client APIs and learn how to interact with smart contracts from a dapp. + +The NEO•ONE client APIs are organized into two packages, `@neo-one/client` which contains the most commonly used functionality, and `@neo-one/client-full` which contains extended but rarely used functionality. In general a dapp developer only needs to concern themselves with the APIs offered by `@neo-one/client`. Learn more about the `@neo-one/client-full` APIs in the [Extended Client APIs](/docs/extended-client-apis) advanced guide. + +--- + +[[toc]] + +--- + +## Client + +The `@neo-one/client` APIs center around instances of the `Client` class. The `Client` class abstracts away user accounts and even how those accounts are provided to your dapp, for example, they might come from an extension like NEX, dapp browser like nOS or through some other integration. + +::: warning + +Tip + +Do not roll your own wallet when creating a dapp. This fractures the ecosystem and in the worst case, requires users to trust every dapp with their private keys. Instead, configure your `Client` to work with one of the existing wallets. Read more in the [User Accounts](/docs/user-accounts) advanced guide. + +::: + +The `Client` class also contains a few methods that may be useful in the course of developing a dapp: + +- `getCurrentUserAccount(): UserAccount | undefined` - Returns the currently selected `UserAccount`. Returns `undefined` if there are no `UserAccount`s. +- `getCurrentNetwork(): NetworkType` - Returns the currently selected network, a string that will be `'main'` for the MainNet, `'test'` for the TestNet, and typically `'local'` for a local private network. +- `getAccount(id: UserAccountID): Promise` - Returns an object containing the native asset balances for a given `UserAccountID`. + +The `Client` class also contains two methods for creating transactions. + +```typescript +class Client { + public async transfer( + amount: BigNumber, + asset: Hash256String, + to: AddressString, + options?: TransactionOptions, + ): Promise>; + public async transfer(transfers: readonly Transfer[], options?: TransactionOptions): Promise; + + public async claim(optionsIn?: TransactionOptions): Promise; +} +``` + +- `transfer` creates a transaction for transferring native assets from the currently selected account (by default) to the specified address(es). +- `claim` creates a transaction for claiming unclaimed GAS for the currently selected account. + +We'll go into more detail on the shape of the `TransactionResult` object and the semantics of creating transactions in the next chapter. + +All methods that relay transactions to the blockchain optionally accept a `TransactionOptions` object (or an extension of it) for customizing the relayed transaction: + +```typescript +interface TransactionOptions { + /** + * The `UserAccount` that the transaction is "from", i.e. the one that will be used for native asset transfers, claims, and signing the transaction. + * + * If unspecified, the currently selected `UserAccount` is used as the `from` address. + * + * DApp developers will typically want to leave this unspecified. + */ + from?: UserAccountID; + /** + * Additional attributes to include with the transaction. + */ + attributes?: readonly Attribute[]; + /** + * An optional network fee to include with the transaction. + */ + networkFee?: BigNumber; + /** + * A maximum system fee to include with the transaction. Note that this is a maximum, the client APIs will automatically calculate and add a system fee to the transaction up to the value specified here. + * + * Leaving `systemFee` `undefined` is equivalent to `new BigNumber(0)`, i.e. no system fee. + * + * A `systemFee` of `-1`, i.e. `new BigNumber(-1)` indicates no limit on the fee. This is typically used only during development. + */ + systemFee?: BigNumber; +} +``` + +Putting this all together, if we wanted to transfer funds to another account, but only if the account is empty, we would do: + +```typescript +const account = await client.getAccount(otherAccountID); +if (account.balances[Hash256.NEO] === undefined) { + await client.transfer.confirmed(new BigNumber(10), Hash256.NEO, otherAccountID.address); +} +``` + +We'll learn more about the `confirmed` property in the next chapter. Also take note of the `Hash256.NEO` property, which works just like the `Hash256.NEO` property in smart contracts and can be imported directly from `@neo-one/client`. + +--- + +## Toolchain Code Generation + +The NEO•ONE toolchain generates many files that contain helpers and APIs that are essential for dapp development. Running `neo-one build` will emit TypeScript files. Let's briefly cover what each one contains. + +::: warning + +Note + +The output directory for generated files is configurable. You can also change the configuration to emit pure JavaScript files instead of TypeScript. See the [Configuration](/docs/configuration) reference for details. + +::: + +For each contract, the toolchain will emit 3 files: + +- `src/neo-one//abi.ts` - Contains the ABI that generates the client smart contract APIs at runtime that we'll discuss in the next chapter. +- `src/neo-one//contract.ts` - Contains the smart contract definition, which contains the ABI, the source maps for the contract and a mapping from network name to deployed address for the smart contract. Initially the network mapping will only contain the `local` network which represents your local development network. Once you deploy your smart contract to the TestNet or MainNet, it will also contain deployed contract addresses for those networks. The client APIs automatically choose which address to work with based on the network of the user account that is initiating the request. This file also contains a helper function for creating the smart contract APIs given a `Client`. +- `src/neo-one//types.ts` - Contains the TypeScript type definitions for the smart contract client APIs. + +5 files will also be emitted that are common to all of your smart contracts: + +- `src/neo-one/client.ts` - Contains helper functions for creating a fully configured `Client`. The `Client` is also configured automatically for local development with 11 user accounts that each have varying amounts of NEO and GAS. Additionally contains helper functions for creating `DeveloperClient`s which can be used to control your local development environment. These are generally passed on to the NEO•ONE Developer Tools which we'll talk about in a later chapter. +- `src/neo-one/react.tsx` - Contains two react components, that when used together allow you to easily access all of the tools you need to write a dapp with React throughout your component tree. Read more in the [React](/docs/react) advanced guide. We also provide similar tools for apps written in [Angular](/docs/angular) or [Vue](/docs/vue)! +- `src/neo-one/sourceMaps.ts` - Contains all of the smart contract source maps. These source maps are not included in the production build in order to reduce the bundle size. +- `src/neo-one/test.ts` - Contains the `withContracts` test helper. We'll learn more about this helper in the following chapters. +- `src/neo-one/contracts.ts` - Contains the `Contracts` type whose properties are the smart contract APIs for your dapp. + +--- + +## Integration + +Integrating the NEO•ONE client APIs in a vanilla JavaScript or TypeScript application is very simple - assuming we have a contract called `Token` and we're in the `src/index.ts` file using the default NEO•ONE toolchain paths: + +```typescript +import { createClient, createTokenSmartContract } from './neo-one'; + +const client = createClient(); +const token = createTokenSmartContract(client); +``` + +Now we can use both the base blockchain APIs offered by the `Client` class and the generated smart contract APIs that correspond to the `Token` contract. + +::: warning + +Note + +As you prepare your dapp for production, you'll likely want to configure additional `UserAccountProvider`s in the `Client`. Learn more about `UserAccount`s and `UserAccountProvider`s in the [User Accounts](/docs/user-accounts) advanced guide. + +::: + +--- + +## Utilities + +`@neo-one/client` exports many utility functions for working with private keys, addresses, public keys and script hashes: + +- The most common come in the form of conversion functions: `To`, for example, `privateKeyToAddress`. See the full list in the [@neo-one/client](/reference/@neo-one/client) reference. +- `createPrivateKey` returns a new private key. +- `decryptNEP2`, `encryptNEP2` and `isNEP2` implement [NEP-2](https://github.com/neo-project/proposals/blob/master/nep-2.mediawiki) diff --git a/packages/neo-one-website/docs3/1-main-concepts/09-smart-contract-apis.md b/packages/neo-one-website/docs3/1-main-concepts/09-smart-contract-apis.md new file mode 100644 index 0000000000..a29ba417a8 --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/09-smart-contract-apis.md @@ -0,0 +1,377 @@ +--- +slug: smart-contract-apis +title: Smart Contract APIs +--- + +The generated smart contract client APIs correspond directly with the properties and methods of your smart contract. + +The smart contract APIs are created at runtime based on the generated ABI in `src/neo-one//abi.ts`. The exact structure of the ABI is not too important, we just need to understand what's happening at a high level. For every public property and method of your smart contract, a corresponding method is created on the smart contract object. + +--- + +[[toc]] + +--- + +## Properties + +Each public property is translated to either a single method or two methods: + +- If the property is `readonly`, then it's translated to a method with the same name. +- If the property is mutable, then it's translated to two methods. One that's named the same as the property and serves to fetch the current value. The other is named `set` and serves to set the value of the property. + +Let's take a look at an example: + +```typescript +export class Contract extends SmartContract { + public myValue = 'value'; + public constructor(public readonly owner = Deploy.senderAddress) {} +} +``` + +Then calling the generated helper method `createContractSmartContract`: + +```typescript +const contract = createContractSmartContract(client); +``` + +would result in an object with three properties: + +- `owner(): Promise` - a method that returns a `Promise` which resolves to the current value of the `owner` property of the smart contract. +- `myValue(): Promise` - a method that returns a `Promise` which resolves to the current value of the `myValue` property of the smart contract. +- `setMyValue(value: string): Promise` - a method which takes a `string` parameter to set as the current value of `myProperty` and that returns a `Promise` that resolves to a `TransactionResult` object. We'll talk more about the `TransactionResult` type in the next section. + +Notice how the smart contract client APIs correspond directly with the properties defined in the smart contract. The main difference is that reading properties requires an asynchronous action - we need to make a request to a node to determine the current value. Thus, the methods return a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which will resolve to a value with the type of the property. + +`setMyValue` works the same as a normal instance method, which we'll cover in the next section. + +--- + +## Methods + +Recall that the smart contract methods we've seen thus far in this guide come in two forms, normal instance methods and constant instance methods - designated by the `@constant` decorator. + +### Constant + +Constant methods correspond 1:1 with generated methods on the smart contract API object. Given the following contract: + +```typescript +export class Contract extends SmartContract { + @constant + public balanceOf(address: Address): Fixed<8> { + return 0; + } +} +``` + +The generated helper method `createContractSmartContract` will return an object with one property: + +- `balanceOf(value: AddressString): Promise` - a method that returns a `Promise` which resolves to the result of calling `balanceOf` on the smart contract with the provided `address`. + +Later in this chapter we'll provide a type conversion table that elaborates how types are converted from the smart contract APIs to the client APIs. + +### Normal + +Unlike constant methods and reading property values, normal methods require submitting a transaction to the blockchain for processing. The NEO•ONE client APIs model this with a 2 step process: + +1. Construct and relay the transaction to the blockchain. +2. Wait for the transaction to be confirmed. + +Given the following smart contract: + +```typescript +export class Contract extends SmartContract { + public transfer(from: Address, to: Address, amount: Fixed<8>): boolean { + return true; + } +} +``` + +The smart contract object returned by `createContractSmartContract` will contain one property: + +```typescript +transfer(from: AddressString, to: AddressString, amount: Fixed<8>): Promise, InvocationTransaction>> +``` + +Calling this method corresponds to the first step in the process. The `Promise` will resolve once the transaction has been relayed to the blockchain. The `TransactionResult` object contains two properties: + +```typescript +interface TransactionResult { + readonly transaction: TTransaction; + readonly confirmed: (options?: GetOptions) => Promise; +} +``` + +The `transaction` property contains the relayed transaction object. In the above case it will be an `InvocationTransaction` since all normal smart contract methods correspond to relaying an `InvocationTransaction` which invokes the method. + +The `confirmed` method corresponds to the second step of the process. Calling `confirmed` returns a `Promise` which resolves once the transaction has been confirmed on and permanently persisted to the blockchain. The `Promise` resolves to a "receipt" of this confirmation. Every transaction receipt contains at least three properties: + +```typescript +interface TransactionReceipt { + /** + * `Block` index of the `Transaction` for this receipt. + */ + readonly blockIndex: number; + /** + * `Block` hash of the `Transaction` for this receipt. + */ + readonly blockHash: Hash256String; + /** + * Transaction index of the `Transaction` within the `Block` for this receipt. + */ + readonly transactionIndex: number; +} +``` + +Normal instance method invocations return a special receipt called an `InvokeReceipt` which contains additional information: + +```typescript +interface InvokeReceipt> extends TransactionReceipt { + /** + * The result of the invocation. + */ + readonly result: InvocationResult; + /** + * The events emitted by the smart contract during the invocation. + */ + readonly events: ReadonlyArray; + /** + * The logs emitted by the smart contract during the invocation. + */ + readonly logs: ReadonlyArray; + /** + * The original, unprocessed, raw invoke receipt. The `RawInvokeReceipt` is transformed into this object (the `InvokeReceipt`) using the ABI to parse out the events and transaction result. + */ + readonly raw: RawInvokeReceipt; +} +``` + +The `result` property indicates success or failure based on the `state` property of the object - either `'HALT'` for success, or `'FAULT'` for failure. On success, the return value of the invocation is stored in the `value` property of the object. On failure, a descriptive message of the reason why the transaction failed is stored in the `message` property. + +```typescript +interface InvocationResultBase { + /** + * GAS consumed by the operation. This is the total GAS consumed after the free GAS is subtracted. + */ + readonly gasConsumed: BigNumber; + /** + * The total GAS cost before subtracting the free GAS. + */ + readonly gasCost: BigNumber; +} + +interface InvocationResultSuccess extends InvocationResultBase { + /** + * Indicates a successful invocation + */ + readonly state: 'HALT'; + /** + * The return value of the invocation. + */ + readonly value: TValue; +} + +interface InvocationResultError extends InvocationResultBase { + /** + * Indicates a failed invocation + */ + readonly state: 'FAULT'; + /** + * Failure reason. + */ + readonly message: string; +} +``` + +Both successful and failed invocation results contain properties for the total GAS consumed and cost. + +Putting this all together, a common pattern for invoking smart contract methods is the following: + +```typescript +// Indicate in the UI that the transaction is being relayed. + +const result = await contract.transfer(from, to, amount); + +// Indicate in the UI that we're waiting for confirmation +// and process the transaction that was relayed +const transaction = result.transaction; + +const receipt = await result.confirmed(); +if (receipt.result.state === 'FAULT') { + // Handle the failure, possibly processing the error message for display in the UI +} else { + // Do something with the result of the call + const value = receipt.result.value; + // Do something with the emitted events + const events = receipt.events; +} +``` + +### Confirmed Transaction Shortcut + +Every normal instance method also contains a `confirmed` property which is a shortcut for the above process. The `Promise` it returns instead resolves once the transaction is both relayed and confirmed: + +```typescript +// Indicate in the UI that the transaction is being processed (both relayed and confirmed). + +const result = await contract.transfer.confirmed(from, to, amount); + +// Process the transaction that was relayed AND confirmed +const transaction = receipt.transaction; + +if (receipt.result.state === 'FAULT') { + // Handle the failure, possibly processing the error message for display in the UI +} else { + // Do something with the result of the call + const value = receipt.result.value; + // Do something with the emitted events + const events = receipt.events; +} +``` + +The only difference is the `Promise` resolves with an additional property, `transaction`, on the receipt object that contains the `Transaction` that was relayed and confirmed. + +--- + +## Common Properties + +In addition to the generated methods mentioned above, the smart contract object contains a few common properties: + +```typescript +interface SmartContract> { + /** + * The `SmartContractDefinition` that generated this `SmartContract` object. + */ + readonly definition: SmartContractDefinition; + /** + * The underlying `Client` used by this `SmartContract`. + */ + readonly client: TClient; + /** + * Iterate over the events emitted by the smart contract. + * + * @returns an `AsyncIterable` over the events emitted by the smart contract. + */ + readonly iterEvents: (options?: SmartContractIterOptions) => AsyncIterable; + /** + * Iterate over the logs emitted by the smart contract. + * + * @returns an `AsyncIterable` over the logs emitted by the smart contract. + */ + readonly iterLogs: (options?: SmartContractIterOptions) => AsyncIterable; + /** + * Iterate over the events and logs emitted by the smart contract. + * + * @returns an `AsyncIterable` over the events and logs emitted by the smart contract. + */ + readonly iterActions: (options?: SmartContractIterOptions) => AsyncIterable; + /** + * Converts a `RawAction`, typically from the raw results found in a `Block` to a processed `Action` or `undefined` if the action is not recognized by the ABI. + * + * @returns `Action` if the `action` parameter is recognized by the `ABI` of the smart contract, `undefined` otherwise. + */ + readonly convertAction: (action: RawAction) => Action | undefined; +} +``` + +Let's go through each in more detail. + +`definition` is simply the `SmartContractDefinition` that generated the smart contract API object. This is the object created by the automatically generated helper method in `src/neo-one//contract.ts`. This is most commonly used to get the current `Address` of the smart contract we're interacting with: + +```typescript +const network = client.getCurrentNetwork(); +const tokenAddress = token.definition.networks[network].address; +``` + +`client` is the `Client` that was used to create the smart contract API object, and is the underlying client used for all smart contract operations. + +`iterEvents` returns an `AsyncIterable` which allows for [asynchronous iteration](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-3.html#async-iteration) over all of the events emitted by the smart contract: + +```typescript +for await (const event of contract.iterEvents()) { + // Do something with each event +} +``` + +`iterLogs` is the same as `iterEvents` but for log notifications, i.e. unstructured strings. Note that NEO•ONE smart contracts intentionally do not support nor emit log events because any time you might want to emit a log event, we believe it's more future-proof to emit a structured event. However, when integrating with external contracts, you may want to iterate over the logs that it emits. + +`iterActions` is simply an `AsyncIterable` over both the events and logs of the smart contract in the order that they were seen. + +All of the `iter` methods accept a `SmartContractIterOptions` object: + +```typescript +/** + * Additional optional options for methods that read data from a smart contract. + */ +export interface SmartContractReadOptions { + /** + * The network to read the smart contract data for. By default this is the network of the currently selected user account. + */ + readonly network?: NetworkType; +} + +/** + * Filter that specifies (optionally) a block index to start at and (optionally) a block index to end at. + */ +export interface BlockFilter { + /** + * The inclusive start index for the first block to include. Leaving `undefined` means start from the beginning of the blockchain, i.e. index 0. + */ + readonly indexStart?: number; + /** + * The exclusive end index for the block to start at. Leaving `undefined` means continue indefinitely, waiting for new blocks to come in. + */ + readonly indexStop?: number; +} + +/** + * Additional optional options for methods that iterate over data from a smart contract. + */ +export interface SmartContractIterOptions extends SmartContractReadOptions, BlockFilter {} +``` + +The `SmartContractIterOptions` object allows specifying the `network` to iterate over and the iteration parameters, which block to start from and which block to end at. + +`convertAction` takes a `RawAction` and converts it using the ABI of the smart contract. This conversion includes parsing out the relevant events and automatically converting the raw parameters. See the [Raw Client APIs](/docs/raw-client-apis) documentation for more details. + +::: warning + +Tip + +Read more about asynchronous iteration [here](http://2ality.com/2016/10/asynchronous-iteration.html) + +::: + +--- + +## Type Conversion Table + +| Smart Contract Type | Client API Type | Notes | +| ------------------- | --------------- | ---------------------------------------------------------------------- | +| boolean | boolean | | +| string | string | | +| number | BigNumber | | +| Fixed | BigNumber | Value is automatically converted to a BigNumber with N decimal places. | +| Buffer | BufferString | Hex encoded byte array | +| Address | AddressString | Base58 encoded NEO address | +| Hash256 | Hash256String | Hex encoded string prefixed by '0x' | +| PublicKey | PublicKeyString | Hex encoded string | +| Array | Array | | +| Map | Map | | +| Object | Object | Object properties are follow the same conversions as above | + +Here are some examples of each of the types in the front-end: + +| Client API Type | Example | +| --------------- | ---------------------------------------------------------------------- | +| boolean | `true` | +| string | `'hello world'` | +| BigNumber | `new BigNumber(10)` | +| BigNumber | `new BigNumber(10)` | +| BufferString | `'02028a'` | +| AddressString | `'APyEx5f4Zm4oCHwFWiSTaph1fPBxZacYVR'` | +| Hash256String | `'0x7f48028c38117ac9e42c8e1f6f06ae027cdbb904eaf1a0bdc30c9d81694e045c'` | +| PublicKeyString | `'02028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef'` | +| Array | `[0, 1, 2]` | +| Map | `new Map().set('hello', 'world');` | +| Object | `{ key: 'value' }` | diff --git a/packages/neo-one-website/docs3/1-main-concepts/10-testing.md b/packages/neo-one-website/docs3/1-main-concepts/10-testing.md new file mode 100644 index 0000000000..d6401893a8 --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/10-testing.md @@ -0,0 +1,205 @@ +--- +slug: testing +title: Testing +--- + +Use your favorite unit test framework to test smart contracts using the NEO•ONE client APIs. + +--- + +[[toc]] + +--- + +## withContracts + +The NEO•ONE toolchain generates a helper function called `withContracts` in `src/neo-one/test.ts` that makes testing a breeze: + +```typescript +import { withContracts } from '../neo-one/test'; + +describe('Token', () => { + test('the token has NEP-5 properties', async () => { + await withContracts(async ({ token }) => { + const [name, symbol, decimals, totalSupply, initialBalance, owner] = await Promise.all([ + token.name(), + token.symbol(), + token.decimals(), + token.totalSupply(), + ]); + expect(name).toEqual('Eon'); + expect(symbol).toEqual('EON'); + expect(decimals.toNumber()).toEqual(8); + expect(totalSupply.toNumber()).toEqual(100_000_000); + }); + }); +}); +``` + +By convention, smart contract tests are located in `src/__tests__`, but you can place them wherever you'd like. + +::: warning + +Note + +In all of our examples we'll use [Jest](https://jestjs.io/) for the testing framework, but the `withContracts` function is framework agnostic, so you may use it with any testing framework. + +::: + +The `withContracts` function starts up a fresh network for each test case, compiles all of your smart contracts, deploys them to the local network, pre-configures a `Client` as well as a `DeveloperClient` and creates the smart contract APIs. It then passes these tools as properties of an object to an async callback function where your testing logic should reside. The properties available to your function are: + +```typescript +interface TestOptions { + /** + * The local network name that the smart contracts have been deployed to and the `client` has been configured with. + */ + readonly networkName: string; + /** + * `Client` that has been pre-configured with the master account for the local network as well as each of the accounts in `accountIDs`. + */ + readonly client: Client<{ + readonly memory: LocalUserAccountProvider; + }>; + /** + * `DeveloperClient` that's been configured to point at the local testing network. + */ + readonly developerClient: DeveloperClient; + /** + * `UserAccountID` of the "master" account - the account that contains ~100 million NEO and ~58 million GAS. + * + * This user account is also the currently selected user account in the `Client` and the one that deployed the contracts. + */ + readonly masterAccountID: UserAccountID; + /** + * Private key for the `masterAccountID`. + */ + readonly masterPrivateKey: string; + /** + * 10 additional user accounts that have been configured in the client with varying amounts of NEO and GAS: + * + * At index: + * 0. 0 NEO and GAS + * 1. 1 NEO and GAS + * 2. 10 NEO and GAS + * 3. 100 NEO and GAS + * 4. 1000 NEO and GAS + * 5. 10000 NEO and GAS + * 6. 100000 NEO and GAS + * 7. 1000000 NEO and GAS + * 8. 5 NEO and GAS + * 9. 20 NEO and GAS + */ + readonly accountIDs: readonly UserAccountID[]; +} +``` + +In addition to the properties listed above, the object will contain a smart contract API object property for each smart contract in your project, configured with the `Client` at the `client` property. The example at the beginning of this section shows how you could access the smart contract API for a smart contract called `Token`. + +Within the callback to the `withContracts` function, we can test our smart contracts using the same NEO•ONE client APIs that we use to interact with the contract in production (and that we've discussed over the previous 2 chapters). + +To run tests quickly, the network and clients are setup to run consensus immediately with every transaction. This way, tests do not have to wait for blocks to be produced every 15 seconds. If you'd like to turn off this behavior, or configure other aspects of `withContracts`, you may pass in an options object as the second parameter: + +```typescript +interface WithContractsOptions { + /** + * Ignore compiler warnings. Useful during smart contract development. + * + * Defaults to `false`. + */ + readonly ignoreWarnings?: boolean; + /** + * Automatically deploy smart contracts using the defaults specified in the constructor arguments. + * + * Defaults to `true`. + */ + readonly deploy?: boolean; + /** + * Automatically run consensus whenever a transaction is relayed. + * + * Defaults to `true`. + */ + readonly autoConsensus?: boolean; + /** + * Automatically provide the necessary system fee for every transaction to execute. + * + * Defaults to `true`. + */ + readonly autoSystemFee?: boolean; +} +``` + +For example, to turn off automatic consensus: + +```typescript +describe('Token', () => { + test('has nep-5 properties', async () => { + await withContracts( + async ({ token }) => { + // Test that it has the expected properties + }, + { autoConsensus: false }, + ); + }); +}); +``` + +--- + +## DeveloperClient + +`DeveloperClient` is a class that is configured to point at a local development network. This class provides methods that are useful during testing: + +- `runConsensusNow(): Promise` - trigger consensus to run immediately. +- `fastForwardOffset(seconds: number): Promise` - fast forward the local network by `seconds` into the future. Use this method to test time-dependent smart contracts. +- `fastForwardToTime(seconds: number): Promise` - fast forward to a particular unix timestamp in the future. +- `reset(): Promise` - reset the local network to it's initial state starting at the genesis block. +- `getSettings(): Promise` - Get the current settings of the private network. +- `updateSettings(options: Partial): Promise` - update settings for the private network. Currently only has a property for controlling the seconds per block. +- `getNEOTrackerURL(): Promise` - fetches the NEO Tracker URL for the project. + +Putting it all together, we might test a time dependent ICO contract like so: + +```typescript +describe('Token', () => { + test('allows participation in the ICO during the allotted time', async () => { + await withContracts(async ({ token, developerClient }) => { + // Fast forward to the start of the ICO + await developerClient.fastForwardOffset(60 * 60); + + // Verify that we can participate in the ICO + const receipt = await token.mintTokens.confirmed({ + sendTo: [ + { + asset: Hash256.NEO, + amount: new BigNumber(10), + }, + ], + }); + if (receipt.result.state === 'FAULT') { + throw new Error(receipt.result.message); + } + expect(receipt.result.value).toBeUndefined(); + + // Fast forward past the end of the ICO + await developerClient.fastForwardOffset(24 * 60 * 60); + + // Verify that contributing after the end of the ICO throws an error. + // We could also do a similar verification above before the start of the ICO. + let error: Error | undefined; + try { + await token.mintTokens.confirmed({ + sendTo: [ + { + asset: Hash256.NEO, + amount: new BigNumber(10), + }, + ], + }); + } catch (err) { + error = err; + } + expect(error).toBeDefined(); + }); + }); +}); +``` diff --git a/packages/neo-one-website/docs3/1-main-concepts/11-dapps.md b/packages/neo-one-website/docs3/1-main-concepts/11-dapps.md new file mode 100644 index 0000000000..b9c05712cf --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/11-dapps.md @@ -0,0 +1,144 @@ +--- +slug: dapps +title: Decentralized Apps +--- + +Building a decentralized app doesn't have to be hard, use these tools from NEO•ONE to make it quick and easy. + +In addition to the client APIs we've already walked through, there are a few properties on the `Client` that help make your app reactive. We'll also cover using the NEO•ONE Developer Tools to help speed up manual testing of your dapp. + +--- + +[[toc]] + +--- + +## Reactive + +NEO•ONE uses [Observables](http://reactivex.io/) with [RxJS](http://reactivex.io/rxjs) to enable reactivity in dapps. The `Client` class has several `Observable` properties that can be subscribed to in order to update application state and the application UI. The most commonly used is the `block$` property: + +```typescript +class Client { + /** + * Emits a value whenever a block is persisted to the blockchain. + * + * Immediately emits the latest block/network when subscribed to. + */ + public readonly block$: Observable<{ + readonly block: Block; + readonly network: NetworkType; + }>; +} +``` + +The `Observable` emits a value whenever a new block is persisted to the blockchain for the given network. The `network` property corresponds to the currently selected user account's network. The `Observable` automatically updates to start emitting new blocks from another network whenever the underlying network changes due to a change in the selected user account. + +We can update application state that depends on new blocks by subscribing to the `block$` `Observable`: + +```typescript +client.block$.subscribe(({ block, network }) => { + // Update application state using the latest block and network +}); +``` + +::: warning + +Tip + +If you're using React, check out the `FromStream` component in the [React](/docs/react) advanced guide for a streamlined way to integrate `Observable`s in your application. If you're using Angular or Vue, check out the [Angular](/docs/angular) or [Vue](/docs/vue) advanced guides for examples with those frameworks. + +::: + +One common use-case is to update the user balance whenever a new block is persisted. For example, if we're displaying the user's NEO and GAS balance: + +```typescript +client.block$ + .pipe( + switchMap(async () => { + const userAccount = client.getCurrentUserAccount(); + if (userAccount === undefined) { + return undefined; + } + + const account = await client.getAccount(userAccount.id); + + return { neo: account.balances[Hash256.NEO], gas: account.balances[Hash256.GAS] }; + }), + ) + .subscribe((result) => { + if (result === undefined) { + // Update the UI when a user account is not selected + } else { + const { neo, gas } = result; + // Update the UI with the new neo and gas values. + } + }); +``` + +This is a fairly common pattern, so `Client` already exposes an `Observable` for it: + +```typescript +class Client { + /** + * Emits a value whenever a new user account is selected and whenever a block is persisted to the blockchain. + * + * Immediately emits the latest value when subscribed to. + */ + public readonly accountState$: Observable< + | { + readonly currentUserAccount: UserAccount; + readonly account: Account; + } + | undefined + >; +} +``` + +Thus, we can simplify the above example to just: + +```typescript +client.accountState$.subscribe((result) => { + if (result === undefined) { + // Update the UI when a user account is not selected + } else { + const neo = result.account.balances[Hash256.NEO]; + const gas = result.account.balances[Hash256.GAS]; + // Update the UI with the new neo and gas values. + } +}); +``` + +Take a look at the [@neo-one/client](/reference/@neo-one/client) reference for details on all available `Observable`s. + +--- + +## Developer Tools + +NEO•ONE Developer Tools simplify the process of developing and manually testing your dapp. They contain all of the functionality necessary to control your private network: + +- Immediately run consensus +- Fast forward to a future time +- Reset the local network to it's initial state +- Full wallet implementation with the same set of pre-configured wallets as tests +- Settings for controlling automatic consensus and system fees, seconds per block and adding NEP-5 token addresses to the wallet +- Notifications when transactions are confirmed with links to view the transaction on a local NEO Tracker instance + +Enabling the Developer Tools is easy: + +```typescript +const client = createClient(); +const developerClients = createDeveloperClients(); +DeveloperTools.enable({ client, developerClients }); +``` + +Simply use the generated helper functions in `src/neo-one/client.ts` to construct the various clients the Developer Tools require and then call `enable`. + +::: warning + +Note + +If you've integrated NEO•ONE using the [React](/docs/react) advanced guide, then the Developer Tools are automatically enabled with no additional calls or configuration required. + +::: + +When building for production, the Developer Tools are automatically replaced with an empty implementation, so they won't show up for your users nor affect the bundle size. diff --git a/packages/neo-one-website/docs3/1-main-concepts/12-NEP-5.md b/packages/neo-one-website/docs3/1-main-concepts/12-NEP-5.md new file mode 100644 index 0000000000..7d6f653503 --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/12-NEP-5.md @@ -0,0 +1,97 @@ +--- +slug: nep-5 +title: NEP-5 +--- + +NEP-5 is a Neo Improvement Proposal that defines a token standard for Neo smart contracts. + +--- + +[[toc]] + +--- + +## Properties + +According to the NEP-5 standard a NEP-5 smart contract must have the following properties: + +- `decimals` +- `symbol` +- `name` + +The standard actually calls them "methods", but for NEO•ONE smart contracts they will be public readonly properties which compile down to methods. + +Let's take a look at an example: + +```typescript +export class Token extends SmartContract { + public readonly name = 'Eon'; + public readonly symbol = 'EON'; + public readonly decimals = 8; +} +``` + +## Methods + +According to the NEP-5 standard a NEP-5 smart contract must have the following methods: + +- `balanceOf` +- `totalSupply` +- `transfer` + +Let's take a look at an example: + +```typescript +export class Token extends SmartContract { + @constant + public get totalSupply(): Fixed<8> { + return this.mutableSupply; + } + + @constant + public balanceOf(address: Address): Fixed<8> { + const balance = this.balances.get(address); + + return balance === undefined ? 0 : balance; + } + + public transfer(from: Address, to: Address, amount: Fixed<8>): boolean { + // Sanity check that amount. + if (amount < 0) { + throw new Error(`Amount must be greater than 0: ${amount}`); + } + + // Verify that the `from` `Address` has approved this call. + if (!Address.isCaller(from)) { + throw new Error('from Address did not approve the transfer'); + } + + // Sanity check that the `from` `Address` has enough balance + const fromBalance = this.balanceOf(from); + if (fromBalance < amount) { + throw new Error('From balance is insufficient'); + } + + // Update balances accordingly + const toBalance = this.balanceOf(to); + this.balances.set(from, fromBalance - amount); + this.balances.set(to, toBalance + amount); + + return true; + } +} +``` + +## Events + +According to the NEP-5 standard a NEP-5 smart contract must emit the following events: + +- `transfer` + +Let's take a look at an example: + +```typescript +export class Token extends SmartContract {} +``` + +If all these criteria are met then the NEO•ONE compiler will produce a manifest with `"NEP-5"` included in the `supportedStandards` array. diff --git a/packages/neo-one-website/docs3/1-main-concepts/13-deployment.md b/packages/neo-one-website/docs3/1-main-concepts/13-deployment.md new file mode 100644 index 0000000000..2d8b2fec9e --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/13-deployment.md @@ -0,0 +1,175 @@ +--- +slug: deployment +title: Deployment +--- + +You've built your smart contract, tested it and built a dapp around it. Now it's time to deploy. + +Productionizing your smart contract for deployment to a network other than your local network requires keeping a few things in mind which we will cover in this chapter. + +--- + +[[toc]] + +--- + +## Deployment Specifics + +### Properties + +Smart contracts may specify an instance property called `properties` to specify some or all of the properties used during deployment: + +```typescript +export class Contract extends SmartContract { + public readonly properties = { + groups: [], + permissions: [], + trusts: '*', + }; +} +``` + +#### `groups` + +Groups is an array of objects that defines what groups your contract belongs to. + +#### `permissions` + +Permissions is an array of objects that defines what contracts/methods your contract is allowed to call. You only need to define a non-empty array here if you want your contract to be able to call other contracts. A valid permission object will contain a `hash` property or a `group` property, or neither (to denote a wildcard). + +For example: + +```typescript +export class Contract extends SmartContract { + public readonly properties = { + groups: [], + permissions: [], + trusts: '*', + }; +} +``` + +#### `payable` + +Payable determines if your contract is allowed to receive assets (like NEO and GAS). + +#### `trusts` + +Trusts is either a wildcard string (`"*"`) or an array of strings that defines which addresses are allowed to call your contract. + +If `properties` is not defined then the contract will compile correctly but the compiler will produce a warning to recommend defining the `properties` property. If it's not defined then the compiler will default to + +These properties are important for constructing your contract's manifest. The manifest is generated by the NEO•ONE compiler and is vital for deployment. + +When a smart contract is deployed, it must explicitly declare the features and permissions it will use. When it is running, it will be limited by its declared list of features and permissions, and cannot do anything beyond the scope of what's defined in the manifest. + +### Upgrade + +Every NEO•ONE smart contract automatically contains a public `upgrade` method. This method replaces the smart contract code as well as the static metadata associated with the contract while preserving the smart contract's storage. In other words, this method can be used to change the logic of your smart contract without losing the data. + +In order to make it possible to upgrade your contract, you _must_ specify the `approveUpgrade` `public` method. This method should return a `boolean` indicating if the `upgrade` is approved: + +```typescript +export class Contract extends SmartContract { + public constructor(public readonly owner = Deploy.senderAddress) {} + + public approveUpgrade(): boolean { + return Address.isCaller(this.owner); + } +} +``` + +Using `Address.isCaller(this.owner)` is the most typical approach. + +::: warning + +Note + +If you do not specify the `approveUpgrade` method, it is impossible for you or anyone else to `upgrade` the contract. + +::: + +### Destroy + +All smart contracts have a `protected` method called `destroy` which any method may use to permanently delete the smart contract. Once `destroy` is called the smart contract can no longer be invoked and the storage is no longer accessible. You're not required to have a method that calls `destroy`, but if you do, it should probably look something like: + +```typescript +export class Contract extends SmartContract { + public constructor(public readonly owner = Deploy.senderAddress) {} + + public permanentlyDestroy(): boolean { + if (!Address.isCaller(this.owner)) { + return false; + } + + this.destroy(); + + return true; + } +} +``` + +::: warning + +Note + +While the contract can no longer be invoked and the storage is not accessible, all of the past invocations still exist on the blockchain. The storage can still be accessed by replaying the blockchain from the beginning up until the point it was destroyed. + +::: + +--- + +### Migration File + +To deploy your contract to a network, you will need to define a `migration` file. The default location for this file is `neo-one/migration.ts`, but it can be [configured](/docs/config-options). A migration file simply exports a function to call the deploy method on your smart contracts with the appropriate arguments. It should look something like this: + +```typescript +import BigNumber from 'bignumber.js'; +import { MigrationContracts } from '../src/neo-one'; + +export default ({ token, ico, escrow }: MigrationContracts, _network: string) => { + token.deploy(); + ico.deploy(undefined, new BigNumber(1566864121), undefined); + escrow.deploy(); +}; +``` + +### MigrationSmartContract + +You may have noticed the new type we use in the above `migration` file, `MigrationContracts`. This is another type generated by NEO•ONE for use specifically in `migration` files and while it looks the same as its counterpart `SmartContract` it has a key difference in that there is no `.confirmed(...)` properties for any of its contract methods. This is because during migration _every_ contract invocation will be be awaited before proceeding to this next invocation. This can be useful when you would like to deploy contracts in series or if you would like to do some additional bootstrapping after the deployment of a contract. + +As an example, lets say you have an ICO contract and you would like to make sure you are the first person to mint a portion of the tokens. Then, going off the migration file above, we could run something like: + +```typescript +import BigNumber from 'bignumber.js'; +import { Hash256 } from '@neo-one/client'; +import { MigrationContracts } from '../src/neo-one'; + +export default ({ token, ico, escrow }: MigrationContracts, _network: string) => { + token.deploy(); + // here we set the startTime of the ICO to be immediate + ico.deploy(undefined, new BigNumber(0), undefined); + ico.mintTokens([{ amount: new BigNumber(10), asset: Hash256.NEO }]); + escrow.deploy(); +}; +``` + +This will ensure that after deploying the `ico` contract (and confirming it is deployed) the next action before deploying the `escrow` contract is to mint some of the ICO tokens to the currently selected `UserAccount`. While a more elegant and safe solution might be to allow the owner of the ICO to mint tokens before the timer has started this should make it clear how you can bootstrap a contract during migration. + +## Deploying to a Public Network + +Once you have successfully configured your `migration` file as explained above you are all set to deploy your Smart Contract! Using the set of [networks](/docs/config-options) defined in `.neo-one.config.js` you can deploy using the command: + +```bash +yarn neo-one deploy --network +``` + +where `network` is one of the keys provided by your configuration. By default `yarn neo-one deploy` will use the `test` key. + +::: warning + +Note + +We HIGHLY recommend deploying to both a local private network _and_ the Neo TestNet before attempting to deploy to the MainNet. + +::: diff --git a/packages/neo-one-website/docs3/1-main-concepts/config.json b/packages/neo-one-website/docs3/1-main-concepts/config.json new file mode 100644 index 0000000000..3cb4f3e1b2 --- /dev/null +++ b/packages/neo-one-website/docs3/1-main-concepts/config.json @@ -0,0 +1,4 @@ +{ + "title": "Main Concepts", + "numbered": true +} diff --git a/packages/neo-one-website/docs3/2-advanced-guides/00-native-assets.md b/packages/neo-one-website/docs3/2-advanced-guides/00-native-assets.md new file mode 100644 index 0000000000..43e9fb36a1 --- /dev/null +++ b/packages/neo-one-website/docs3/2-advanced-guides/00-native-assets.md @@ -0,0 +1,173 @@ +--- +slug: native-assets +title: Native Assets +--- + +Native assets like NEO and GAS require special handling in smart contracts. This guide will show you how. + +NEO employs the [Unspent Transaction Output](https://en.wikipedia.org/wiki/Unspent_transaction_output) (UTXO) system for native assets. Unfortunately, the UTXO system does not play well with smart contracts. Fortunately, NEO•ONE smart contracts abstract away most of the difficulty in handling native assets using the `@receive`, `@send`, `@sendUnsafe` and `@claim` [decorators](https://www.typescriptlang.org/docs/handbook/decorators.html). + +One commonality between every native asset method is that they must throw an error if the transaction should not proceed. + +--- + +[[toc]] + +--- + +## Receive Native Assets + +Decorate a method with `@receive` to allow the method to be invoked when receiving native assets: + +```typescript +export class Contract extends SmartContract { + @receive + public mintTokens(): void { + // Use Blockchain.currentTransaction to validate and process the inputs/outputs. + // Throw an error if it's an invalid combination + } +} +``` + +Methods decorated with `@receive` may also be decorated with `@sendUnsafe` to enable both sending and receiving assets to be verified by the method. + +Invoking a method marked with `@receive` is identical to a normal method, but the transaction options contain an additional property, `sendTo`, which can be used to specify the assets to send to the smart contract: + +```typescript +const receipt = await contract.mintTokens({ + sendTo: [ + { + asset: Hash256.NEO, + amount: new BigNumber(10), + }, + ], +}); +``` + +There are cases where a smart contract may receive native assets without a corresponding `@receive` method invocation, or sometimes even when the `@receive` method throws an error. Unfortunately this is unavoidable, and to solve these cases every smart contract has an automatically generated method called `refundAssets`. Users may call this method when they have sent assets to the contract that were not properly processed. Using the NEO•ONE client APIs: + +```typescript +const transactionHash = ... // Hash of the transaction that needs to be refunded +const receipt = await contract.refundAssets.confirmed(transactionHash); +``` + +--- + +## Send Native Assets + +NEO•ONE provides two methods for sending assets, one that is "unsafe" and one that is "safe". + +### Unsafe + +Decorate a method with `@sendUnsafe` to enable assets to be sent from the contract in a single transaction: + +```typescript +export class Contract extends SmartContract { + @sendUnsafe + public withdraw(): void { + // Typically check something like Address.isCaller(this.owner) + } +} +``` + +`@sendUnsafe` is unsafe because it potentially allows the equivalent of double spends. It's possible for a user to construct a series of parallel transactions that enable them to withdraw more than they should be allowed to. + +::: warning + +Note + +Only decorate a method with `@sendUnsafe` when the method checks that the caller is a "superuser", i.e. someone who is not going to attempt to cheat the contract. The most common case is to simply call `Address.isCaller(this.owner)` which checks that the method was only invoked by the owner of the smart contract. + +::: + +Calling a method marked with `@sendUnsafe` is similar to `@receive` in that it allows an additional options property called `sendFrom` which lets the user specify assets to transfer from the contract: + +```typescript +const receipt = await contract.withdraw.confirmed({ + sendFrom: [ + { + asset: Hash256.NEO, + amount: new BigNumber(10), + to: 'APyEx5f4Zm4oCHwFWiSTaph1fPBxZacYVR', + }, + ], +}); +``` + +### Safe + +Decorate a method with `@send` to enable assets to be sent from the contract safely. `@send` requires two transactions to send assets from the contract. At a high level the steps are: + +1. The user "marks" the assets they wish to withdraw from the contract by constructing a transaction that sends those assets back to the smart contract. +2. The user constructs a transaction that withdraws the previously "mark"ed assets to the desired address. + +NEO•ONE abstract this process such that you only need to define a method decorated with `@send` that throws an error on invalid transactions. NEO•ONE handles the rest. This method may also accept a final argument, a `Transfer` object, that contains the details of the pending transfer: + +```typescript +interface Transfer { + readonly amount: Fixed<8>; + readonly asset: Hash256; + readonly to: Address; +} +``` + +For example, if you wanted to have a method that required a single argument, `value`, of type `string`, you could define your method like so: + +```typescript +export class Contract extends SmartContract { + @send + public withdraw(value: string, transfer: Transfer): void { + // Validate the `transfer` should proceed. Throw an error if not. + } +} +``` + +Calling a method marked with `@send` is identical to `@sendUnsafe`, however, the transfer will not occur until the `completeSend` method is invoked with the transaction hash of the first transaction: + +```typescript +// This transaction only sends assets from the contract to itself, +// marking them for withdrawal by a followup transaction. +const receipt = await contract.withdraw.confirmed('value', { + sendFrom: [ + { + asset: Hash256.NEO, + amount: new BigNumber(10), + to: 'APyEx5f4Zm4oCHwFWiSTaph1fPBxZacYVR', + }, + ], +}); +// Complete the withdrawal process using the transaction hash +const finalReceipt = await contract.completeSend.confirmed(receipt.transaction.hash); +``` + +--- + +## Claim GAS + +Decorate a method with `@claim` to enable claiming GAS. `@claim` methods have a few restrictions: + +1. `@claim` methods may not modify contract storage. They act like `@constant` methods. +2. `@claim` methods may not access `Blockchain.currentTransaction`, instead they may optionally accept the `ClaimTransaction` that the method was invoked in as the final argument. + +```typescript +export class Contract extends SmartContract { + @claim + public claim(transaction: ClaimTransaction): void { + // Validate the ClaimTransaction and throw an error if it is invalid + } +} +``` + +The NEO•ONE client APIs currently only support claiming all available GAS for a smart contract and sending that GAS back to the smart contract. If you have another use-case that you'd like to see supported, please reach out on [Discord](https://discordapp.com/invite/S86PqDE) or open an issue on [GitHub](https://github.com/neo-one-suite/neo-one/issues/new). + +```typescript +await contract.claim.confirmed(); +``` + +::: warning + +Note + +`@claim` is similar to `@sendUnsafe` in terms of safety and thus you should only allow GAS claims that transfer the GAS to an `Address` that is not the contract itself to be done by superusers. To enable GAS claims for contracts without owners or superusers, instead only allow GAS claims that send the GAS back to the contract, and then implement transferring the GAS to the rightful owner using a method marked with `@send`. + +::: diff --git a/packages/neo-one-website/docs3/2-advanced-guides/01-forward-values.md b/packages/neo-one-website/docs3/2-advanced-guides/01-forward-values.md new file mode 100644 index 0000000000..c48289c899 --- /dev/null +++ b/packages/neo-one-website/docs3/2-advanced-guides/01-forward-values.md @@ -0,0 +1,99 @@ +--- +slug: forward-values +title: Forward Values +--- + +Forward values allow advanced interactivity between smart contracts, enabling use-cases that would not normally be possible. + +--- + +[[toc]] + +--- + +## Forward Value + +Before we dive into the specifics, let's look at an example of how forward values are used: + +```typescript +interface TokenPayableContract { + readonly approveReceiveTransfer: (from: Address, value: Fixed<8>, ...args: ForwardValue[]) => boolean; +} + +export class Token extends SmartContract { + // Note that the implementation here is only to show how we + // can use forward values and is an incomplete implementation of a + // Token transfer method. + public transfer(from: Address, to: Address, value: Fixed<8>, ...args: ForwardValue[]): boolean { + const contract = Contract.for(to); + if (contract !== undefined) { + const payableContract = SmartContract.for(to); + + return payableContract.approveReceiveTransfer(from, value, ...args); + } + + return true; + } +} +``` + +::: warning + +Note + +We're using a [rest](https://www.typescriptlang.org/docs/handbook/functions.html#rest-parameters) parameter as the final parameter of the `transfer` method. Declaring a rest parameter means that the function will accept 0 or more additional arguments of that type. + +::: + +`ForwardValue`s represent any type. They're opaque to the contract that declared them. Instead of using them directly, the contract forwards them to another contract. In the example above we check to see if the target or `to` `Address` is a smart contract. If it is, we get an instance of it and invoke the `approveReceiveTransfer` method, forwarding any additional arguments that we received in the call to `transfer`. + +This pattern allows the target contract a chance to react to the transfer, as well as allows the user to provide any additional arguments the contract may require to react to the transfer. + +--- + +## Forwarded Value + +The counterpart to `ForwardValue` is the tagged type `ForwardedValue`. `ForwardedValue` tags the type `T` such that the NEO•ONE toolchain will generate client APIs that simplify forwarding values. Given the following smart contract: + +```typescript +export class Escrow extends SmartContract { + public approveReceiveTransfer(from: Address, value: Fixed<8>, to: ForwardedValue
): boolean { + // Update the escrow account for [from, to] with value + return true; + } +} +``` + +The NEO•ONE toolchain will generate a method called `forwardApproveReceiveTransferArgs`: + +```typescript +const receipt = await token.transfer.confirmed( + from, + escrow.definition.networks[networkName].address, + value, + ...escrow.forwardApproveReceiveTransferArgs(to), +); +``` + +The `forwardApproveReceiveTransferArgs` call above not only sets up the call to forward the specified arguments, but it additionally adds the `Escrow` contracts events (if any) to the resulting `receipt`. + +Forwarding values also works recursively. For example, if the `Escrow` contract also specified a rest parameter of `ForwardValue`s and called another smart contract `Foo`'s `bar` method that expected a `ForwardedValue`, the client API invocation would look like: + +```typescript +const receipt = await token.transfer.confirmed( + from, + escrow.definition.networks[networkName].address, + value, + ...escrow.forwardApproveReceiveTransferArgs(to, ...foo.forwardBarArgs('value')), +); +``` + +In this case, the `receipt` would contain the events for the `transfer` call, the `approveReceiveTransfer` call and the `bar` call. + +--- + +## Reactive Smart Contracts + +Reactive smart contracts are powerful and enable many use-cases that would otherwise not be possible. We recommend the following pattern when implementing your smart contracts. + +Whenever your smart contract has a method that takes an `action` on an `Address`, always check to see if the target `Address` is a smart contract. If it is, invoke the `approveReceive` method of that smart contract with the same arguments `action` was called with, except the argument that is the smart contract `Address` itself. Additionally, pass a rest parameter of `ForwardValue`s to the method. Take a look at the `Token` example above to see this pattern in action. diff --git a/packages/neo-one-website/docs3/2-advanced-guides/02-user-accounts.md b/packages/neo-one-website/docs3/2-advanced-guides/02-user-accounts.md new file mode 100644 index 0000000000..009c20ff76 --- /dev/null +++ b/packages/neo-one-website/docs3/2-advanced-guides/02-user-accounts.md @@ -0,0 +1,123 @@ +--- +slug: user-accounts +title: User Accounts +--- + +NEO•ONE client APIs revolve around the concept of user accounts which represent a single address controlled by the user of the dapp. + +The `Client` class is an abstraction layer over `UserAccountProvider`s which implement the core logic. By using the `Client` class and the generated smart contract APIs throughout your dapp, you can ensure that your business logic is independent of the underlying `UserAccountProvider`s. + +--- + +[[toc]] + +--- + +## Client Configuration + +The `createClient` helper function generated by the NEO•ONE toolchain is configured with a `LocalUserAccountProvider` backed by an in-memory `LocalKeyStore` by default. This can be easily configured by passing in a callback of the form: + +```typescript +(provider: NEOONEProvider) => { [name: string]: UserAccountProvider } +``` + +This callback will be passed a default `NEOONEProvider` that's been configured to work with your local private network as well as public nodes for the TestNet and MainNet. The return value will be used to configure the `Client`. + +::: warning + +Tip + +You can configure the `Client` to only work with external wallets provided by an extension or a dapp browser by checking `process.env.NODE_ENV === 'production'` and returning a subset of the `UserAccountProvider`s used during development. + +::: + +Let's take a look at an example: + +```typescript +const getUserAccountProviders = (provider: NEOONEProvider) => { + const dapp = new DappBrowserUserAccountProvider(); + const extension = new BrowserExtensionUserAccountProvider(); + const other = new SomeOtherWalletProvider(); + if (process.env.NODE_ENV === 'production') { + return { dapp, extension, other }; + } + + const memory = new LocalUserAccountProvider({ + keystore: new LocalKeyStore(new LocalMemoryStore()), + provider, + }); + + return { dapp, extension, other, memory }; +}; + +const client = createClient(getUserAccountProviders); +``` + +This would configure a `Client` that knows how to communicate with a dapp browser (e.g. nOS), a browser extension (e.g. NEX) and some other integration provided by `SomeOtherWalletProvider`. In production, it would only communicate with those providers, while in development we've additionally configured a `LocalUserAccountProvider` with an in-memory `LocalKeyStore` for use in testing. + +::: warning + +Note + +In order to take advantage of the automatic local network configuration and pre-configured wallets, you must configure a `LocalUserAccountProvider` using the argument `provider` and an in-memory keystore, like the above example. + +::: + +--- + +## LocalUserAccountProvider + +`LocalUserAccountProvider` is a completely local to the application `UserAccountProvider` which directly connects to NEO•ONE RPC nodes in order to process read requests as well as create and send transactions. `LocalUserAccountProvider` must be configured with a `KeyStore` instance and a `Provider` instance. The `KeyStore` interface abstracts over `UserAccount`s, selecting them, getting the current one, as well as signing a message with a specified `UserAccount`. The `Provider` interface abstracts over specific RPC requests the `LocalUserAccountProvider` requires to function. + +In the example above, we've configured it to use a `LocalKeyStore` which is backed by a `LocalMemoryStore` which provides `UserAccount`s via an in-memory store. `LocalKeyStore` can be configured with any object that implements the `Store` interface and can be easily backed by persistent storage in files or within browser local storage: + +```typescript +import localforage from 'localforage'; + +const localStorage = new LocalUserAccountProvider({ + keystore: new LocalKeyStore(new LocalStringStore(localforage)), + provider, +}); +``` + +NEO•ONE currently also supports a `LedgerKeyStore`, which enables connecting to ledger devices in both NodeJS-like environments and browser-like environments. + +```typescript +const ledger = new LocalUserAccountProvider({ + keystore: new LedgerKeyStore(provider), + provider, +}); +``` + +--- + +## UserAccount and UserAccountID + +`UserAccount` is the main abstraction used to define the user's available accounts for signing transactions. It contains three properties: + +```typescript +interface UserAccount { + /** + * Uniquely identifies a `UserAccount` by its address and the network its used on. + */ + readonly id: UserAccountID; + /** + * The name to use when displaying this account in a user-facing UI. Can be a user configured name or just the address. + */ + readonly name: string; + /** + * The public key for the address. + */ + readonly publicKey: PublicKeyString; +} +``` + +`UserAccountID` is used throughout the `@neo-one/client` APIs to specify a particular account to take an action with. For example, all of the smart contract APIs accept an options object as the last parameter that can specify a `from` `UserAccountID` to invoke a method with. + +--- + +## Integrating With NEO•ONE + +Want to integrate your wallet with NEO•ONE? Then this section is for you. The best way to integrate is to use the NEO•ONE client APIs with a `LocalUserAccountProvider` within your wallet. As described above, the `LocalUserAccountProvider` can be customized with specific `KeyStore` implementations that should satisfy the majority of wallet use-cases. + +Once you've done that, come talk to us on [Discord](https://discord.gg/S86PqDE). The integration is currently a work in progress, but it's coming very soon. diff --git a/packages/neo-one-website/docs3/2-advanced-guides/03-extended-client-apis.md b/packages/neo-one-website/docs3/2-advanced-guides/03-extended-client-apis.md new file mode 100644 index 0000000000..713d9a4b86 --- /dev/null +++ b/packages/neo-one-website/docs3/2-advanced-guides/03-extended-client-apis.md @@ -0,0 +1,8 @@ +--- +slug: extended-client-apis +title: Extended Client APIs +--- + +The extended client APIs are targeted at users that require more information from the blockchain than a typical dapp. + +The primary use-case for the extended client APIs are for implementing block explorers and applications with similar requirements. Documentation coming soon! diff --git a/packages/neo-one-website/docs3/2-advanced-guides/04-raw-client-apis.md b/packages/neo-one-website/docs3/2-advanced-guides/04-raw-client-apis.md new file mode 100644 index 0000000000..66feb9223a --- /dev/null +++ b/packages/neo-one-website/docs3/2-advanced-guides/04-raw-client-apis.md @@ -0,0 +1,8 @@ +--- +slug: Raw-client-apis +title: Raw Client APIs +--- + +Similar to the [Extended Client APIs](/docs/extended-client-apis), the raw client APIs are targeted at users that require more information from the blockchain than a typical dapp. + +Documentation coming soon! diff --git a/packages/neo-one-website/docs3/2-advanced-guides/05-react.md b/packages/neo-one-website/docs3/2-advanced-guides/05-react.md new file mode 100644 index 0000000000..d9b7ad9404 --- /dev/null +++ b/packages/neo-one-website/docs3/2-advanced-guides/05-react.md @@ -0,0 +1,77 @@ +--- +slug: react +title: React +--- + +NEO•ONE has first-class integration with React applications. + +Integrating NEO•ONE with React is a breeze using the generated NEO•ONE client APIs. We also offer a `FromStream` component that make using `Observable`s in the client APIs within your React components much simpler. + +--- + +[[toc]] + +--- + +## Generated Code + +The NEO•ONE toolchain emits two components that aid in integrating a React application with NEO•ONE: `ContractsProvider` and `WithContracts`. + +### ContractProvider + +The `ContractsProvider` component should be used at the root of your application as it provides the NEO•ONE client and smart contract APIs to all children in its React tree using the [React context API](https://reactjs.org/docs/context.html): + +```tsx +import { ContractsProvider } from './neo-one'; +import * as ReactDOM from 'react-dom'; +import { App } from './App'; + +const app = ( + + + +); +ReactDOM.render(app, document.getElementById('app')); +``` + +`ContractsProvider` by default uses the generated helper methods to create the required props, but you may customize this by passing in your own `Client`, `DeveloperClient`s and/or `LocalClient`s: + +```tsx +import { ContractsProvider, createClient } from './neo-one'; +import * as ReactDOM from 'react-dom'; +import { App } from './App'; + +const client = createClient(); +const app = ( + + + +); +ReactDOM.render(app, document.getElementById('app')); +``` + +### WithContracts + +Once you've included `ContractsProvider` in your application, you may use the `WithContracts` component anywhere in your application to access the NEO•ONE client APIs. `WithContracts` is is a [render props](https://reactjs.org/docs/render-props.html) component that passes the `client` and your smart contract APIs to its child function: + +```tsx +{({ token }) =>
token.withdraw.confirmed()}>Withdraw
}
+``` + +--- + +## FromStream + +`@neo-one/react` contains one export, the `FromStream` component. `FromStream` is a [render props](https://reactjs.org/docs/render-props.html) component that subscribes to the `Observable` returned from invoking the `createStream` prop. It then passes the most recently emitted value to its children function: + +```tsx + + {({ client }) => ( + client.block$}> + {(block) =>
The current block index is: {block.index}
} +
+ )} +
+``` + +`FromStream` accepts one additional prop, `props`, which is a list of values that are used within the `createStream` function. Without `props`, `createStream` is called on every render of `FromStream` and the result is subscribed to. With `props`, a new stream is subscribed to only when the value of one of the elements of `props` does not match the previous render. In general, you should go ahead and include any values you use in your `createStream` function within the `props` prop. diff --git a/packages/neo-one-website/docs3/2-advanced-guides/06-angular.md b/packages/neo-one-website/docs3/2-advanced-guides/06-angular.md new file mode 100644 index 0000000000..ea311167b5 --- /dev/null +++ b/packages/neo-one-website/docs3/2-advanced-guides/06-angular.md @@ -0,0 +1,80 @@ +--- +slug: angular +title: Angular +--- + +NEO•ONE has first-class integration with Angular applications. + +Integrating NEO•ONE with Angular is a breeze using the generated NEO•ONE client APIs. + +--- + +[[toc]] + +--- + +## Generated Code + +The NEO•ONE toolchain emits an [Angular Service](https://angular.io/guide/dependency-injection#injecting-services) that aids in integrating an Angular application with NEO•ONE: `ContractsService`. + +### ContractsService + +The `ContractsService` can be injected into any component or service in which you need access to the client APIs or smart contract methods. + +```typescript +import { Component } from '@angular/core'; +import { ContractsService } from './neo-one'; + +@Component({ + selector: 'app-test-component', + templateUrl: './test-component.component.html', + styleUrls: ['./test-component.component.css'], +}) +export class TestComponent implements OnInit { + constructor(private contractsService: ContractsService) {} + + onWithdraw(): void { + this.contractsService.token.withdraw + .confirmed() + .then + // update something + (); + } +} +``` + +The `ContractsService` makes responding to updates in the blockchain easy by providing access to [Observables](https://angular.io/guide/observables-in-angular). Here's how you might use the `ContractsService` to build a simple Angular component to update the current block count. + +```typescript +import { Component, OnInit } from '@angular/core'; +import { ContractsService } from './neo-one'; + +@Component({ + selector: 'block-counter-component', + templateUrl: './block-counter.component.html', + styleUrls: ['./block-counter.component.css'], +}) +export class BlockCounter implements OnInit { + blockCount: number; + + constructor(private contractsService: ContractsService) { + this.blockCount = 0; + } + + ngOnInit() { + this.getBlocks(); + } + + getBlocks(): void { + this.contractsService.client.block$.subscribe((block) => { + this.blockCount = block.block.index; + }); + } +} +``` + +### Important Notes + +- For the smoothest experience using NEO•ONE with Angular 6+, you should use the browserified version of NEO•ONE. This version of NEO•ONE replaces Node.js builtin modules with their browser compatible shims. To use this version, you simply need to import any NEO•ONE client modules with the `-browserify` suffix. So, `@neo-one/client` is imported as `@neo-one/client-browserify`. +- `allowSyntheticDefaultImports` must be set to `true` in the top level `tsconfig.json`. +- `(window as any).global = window;` must be added in the `polyfill.ts` file. diff --git a/packages/neo-one-website/docs3/2-advanced-guides/07-vue.md b/packages/neo-one-website/docs3/2-advanced-guides/07-vue.md new file mode 100644 index 0000000000..1897847ed3 --- /dev/null +++ b/packages/neo-one-website/docs3/2-advanced-guides/07-vue.md @@ -0,0 +1,76 @@ +--- +slug: vue +title: Vue +--- + +NEO•ONE has integration with Vue applications. + +Integrating NEO•ONE with Vue is a breeze using the generated NEO•ONE client APIs. + +--- + +[[toc]] + +--- + +## Generated Code + +The NEO•ONE toolchain emits a service that aids in integrating a Vue application with NEO•ONE: `contractsService`. + +### ContractsService + +The `contractsService` is a singleton which provides access to all of the generated NEO•ONE client APIs and smart contract methods. + +```typescript + + + +``` + +The `contractsService` makes responding to updates in the blockchain easy by providing access to observables. Here's how you might use the `contractsService` to build a simple Vue component to update the current block count. + +```typescript + + + +``` diff --git a/packages/neo-one-website/docs3/2-advanced-guides/08-dapi-support.md b/packages/neo-one-website/docs3/2-advanced-guides/08-dapi-support.md new file mode 100644 index 0000000000..05bee9d5c2 --- /dev/null +++ b/packages/neo-one-website/docs3/2-advanced-guides/08-dapi-support.md @@ -0,0 +1,59 @@ +--- +slug: dapi-support +title: dAPI Support +--- + +NEO•ONE provides dAPI support through the familiar [User Accounts](/docs/user-accounts) interface. + +--- + +[[toc]] + +--- + +## What is the dAPI? + +The dAPI is an interface for interacting with the NEO blockchain using an existing dAPI enabled wallet provider. This means that actions like transferring NEO, claiming GAS, and invoking smart contracts can be handled by a trusted wallet provider without the user every having to give a new dApp access to their private key. This allows developers to focus on the development of their dApp without having to worry about the complexities and security concerns of managing user accounts. + +## DapiUserAccountProvider + +NEO•ONE abstracts away the dAPI into a `DapiUserAccountProvider`, an implementation of the [UserAccountProvider](/reference/@neo-one/client/useraccountprovider) interface. While the [LocalUserAccountProvider](/reference/@neo-one/client/localuseraccountprovider) provides a [Client](/reference/@neo-one/client/client) access to [User Accounts](/docs/user-accounts) stored locally, the `DapiUserAccountProvider` provides access to [User Accounts](/docs/user-accounts) stored by a wallet provider and accessed through the dAPI. + +To set up a `DapiUserAccountProvider`, simply import `neo-dapi` in your entry point and ensure it has been attached to the global object. We recommend using the [globalThis](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis) as it is compatible across environments. Once the `neo-dapi` has been attached to the global object, it can be passed from the global object into the constructor of a new `DapiUserAccountProvider`. With this setup, a dAPI enabled wallet running in the background will automatically be used to handle any `UserAccountProvider` methods. The `DapiUserAccountProvider` can then be used in place of a `LocalUserAccountProvider` when setting up a NEO•ONE `Client` as detailed in the [User Accounts](/docs/user-accounts) section. + +Entry point: + +```typescript +import neoDapi from 'neo-dapi'; + +// Attach the neo-dapi to the global object at the entry point +globalThis.neoDapi = neoDapi; +``` + +Elsewhere: + +```typescript +import { Client, DapiUserAccountProvider } from '@neo-one/client'; + +... + +const dapiUserAccountProvider = new DapiUserAccountProvider({ + // Use the global object to pass the neo-dapi to a DapiUserAccountProvider + dapi: globalThis.neoDapi, + provider, + onError: (error) => { + throw error; + }, +}); + +// Use the DapiUserAccountProvider to create a Client +const client = new Client({ dapi: dapiUserAccountProvider }); +``` + +## Codegen + +If you're using NEO•ONE to compile smart contracts and/or generate code with the `neo-one build` command, setting up the dAPI is even easier. Just make sure to attach the `neo-dapi` to the global object at your project's entry point and have a dAPI enabled wallet running in the background. The rest will be taken care of for you when you run `neo-one build`. The generated `Client` will automatically detect the `neo-dapi` attached to the global object and provide it access to a `DapiUserAccountProvider`. Note: This feature is only available with node version >= 12. + +## RemoteUserAccountProvider + +If for some reason the dAPI does not suit the needs for your dApp, NEO•ONE also provides a general `RemoteUserAccountProvider`. This allows communication between a `RemoteUserAccountProvider` in a dApp and a [UserAccountProvider](/reference/@neo-one/client/useraccountprovider) in a wallet through a [Message Channel](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel) interface. To use as `RemoteUserAccountProvider`, a wallet provider must implement a [UserAccountProvider](/reference/@neo-one/client/useraccountprovider), such as a [LocalUserAccountProvider](/reference/@neo-one/client/localuseraccountprovider) and call `connectRemoteUserAccountProvider` with the [UserAccountProvider](/reference/@neo-one/client/useraccountprovider) and the [Message Port](https://developer.mozilla.org/en-US/docs/Web/API/MessagePort) to define the channel. On the dApp's side, all that is required is to create a new `RemoteUserAccountProvider` with the other [Message Port](https://developer.mozilla.org/en-US/docs/Web/API/MessagePort). Note this feature should only be used in cases where the dAPI is insufficient, as the dAPI is the official standard for the NEO blockchain. If you'd like to use a `RemoteUserAccountProvider`, please contact us so we can work with you to ensure it meets the needs of your dApp. diff --git a/packages/neo-one-website/docs3/2-advanced-guides/09-configuration-options.md b/packages/neo-one-website/docs3/2-advanced-guides/09-configuration-options.md new file mode 100644 index 0000000000..7231e809ab --- /dev/null +++ b/packages/neo-one-website/docs3/2-advanced-guides/09-configuration-options.md @@ -0,0 +1,140 @@ +--- +slug: config-options +title: Configuration Options +--- + +NEO•ONE compiler configuration options. + +Configure NEO•ONE for your project. + +## Config File + +An [initialized environment](https://neo-one.io/tutorial#Setup-for-the-Tutorial) will have a `.neo-one.config.ts` file within the project root. + +### Example NEO•ONE configuration file + +The `.neo-one.config.ts` configuration file may look something like this: + +```typescript +import { defaultNetworks } from '@neo-one/cli'; + +export default { + contracts: { + // The NEO•ONE compile command will output the compile results in this directory. + outDir: 'neo-one/compiled', + // NEO•ONE will look for smart contracts in this directory. + path: 'neo-one/contracts', + // Set this to true if you want the compile command to output JSON. + // json: true, + // Set this to true if you want the compile command to output AVM. + // avm: false, + // Set this to true if you want the compile command to output additional debug information. + // debug: false, + // Set this to true if you want the compile command to output the AVM in a human-readable format for debugging (requires debug: true). + // opcodes: false, + }, + artifacts: { + // NEO•ONE will store build and deployment artifacts that should be checked in to vcs in this directory. + path: 'neo-one/artifacts', + }, + migration: { + // NEO•ONE will load the deployment migration from this path. + path: 'neo-one/migration.js', + }, + codegen: { + // NEO•ONE will write source artifacts to this directory. This directory should be committed. + path: 'src/neo-one', + // NEO•ONE will generate code in the language specified here. Can be one of 'javascript' or 'typescript'. + language: 'typescript', + // NEO•ONE will generate client helpers for the framework specified here. Can be one of 'react', 'angular', 'vue' or 'none'. + framework: 'react', + // Set this to true if you're using an environment like Expo that doesn't handle browserifying dependencies automatically. + browserify: false, + // Set this to true if you're running in codesandbox to workaround certain limitations of codesandbox. + codesandbox: false, + }, + network: { + // NEO•ONE will store network data here. This path should be ignored by your vcs, e.g. by specifiying it in a .gitignore file. + path: '.neo-one/network', + // NEO•ONE will start the network on this port. + port: 9040, + }, + // NEO•ONE will configure various parts of the CLI that require network accounts using the value provided here, for example, when deploying contracts. + // Refer to the documentation at https://neo-one.io/docs/config-options for more information. + networks: defaultNetworks, + neotracker: { + // NEO•ONE will start an instance of NEO Tracker using this path for local data. This directory should not be committed. + path: '.neo-one/neotracker', + // NEO•ONE will start an instance of NEO Tracker using this port. + port: 9041, + // Set to false if you'd like NEO•ONE to start an instance of NEO Tracker when running 'neo-one build'. You will need @neotracker/core installed as a dependency for this to work. + skip: true, + }, +}; +``` + +## Networks + +While we provide defaults for deployment networks it is also possible to use your own! You can provide a `name` and `rpcUrl` to our helper function `createUserAccountProviderFunc` from `@neo-one/cli`, which will prompt you to provide a list of `privateKeys` for use on the network when deploying: + +```typescript +import { createUserAccountProviderFunc, defaultNetworks } from '@neo-one/cli'; + +export default { + // ... + networks: { + ...defaultNetworks, + exampleNetwork: createUserAccountProviderFunc('exampleNetwork', 'exampleRpcUrl.io/rpc'); + } + // ... +} +``` + +This is what the `createUserAccountProviderFunc` will do to create the new `LocalUserAccountProvider`: + +```typescript +export const createUserAccountProviderFunc = (network: string, rpcURL: string) => async () => { + const keystore = new LocalKeyStore(new LocalMemoryStore()); + const { privateKeys } = await prompts({ + type: 'list', + name: 'privateKeys', + message: `Please enter one or more private keys separated by commas for use on the "${network}" network.`, + validate: (value) => (value.length > 0 ? true : 'Must enter at least one private key.'), + }); + await Promise.all(privateKeys.map((privateKey: string) => keystore.addUserAccount({ network, privateKey }))); + + return new LocalUserAccountProvider({ + keystore, + provider: new NEOONEProvider([{ network, rpcURL }]), + }); +}; +``` + +Or you can create your own hard-coded `async` function that returns a `UserAccountProvider`, like so: + +```typescript +export default { + // ... + networks: { + ...defaultNetworks, + exampleNetwork: async () => { + const keystore = new LocalKeyStore(new LocalMemoryStore()); + await keystore.addUserAccount('exampleNetwork', 'PRIVATE_KEY'); + + return new LocalUserAccountProvider({ + keystore, + provider: new NEOONEProvider([{ network: 'exampleNetwork', rpcUrl: 'exampleRpcUrl.io/rpc' }]), + }); + }, + }, + // ... +}; +``` + +::: warning + +Note + +While hard-coding the `LocalUserAccountProvider` is a viable option in testing this also requires storing a private key as plain text in the `.neo-one.config.ts` file that is traditionally checked into version control, like Git/GitHub. For this reason we recommend only using a hard coded private key value for local on-the-fly testing and debugging. + +::: diff --git a/packages/neo-one-website/docs3/2-advanced-guides/config.json b/packages/neo-one-website/docs3/2-advanced-guides/config.json new file mode 100644 index 0000000000..62d042b298 --- /dev/null +++ b/packages/neo-one-website/docs3/2-advanced-guides/config.json @@ -0,0 +1,4 @@ +{ + "title": "Advanced Guides", + "numbered": false +} diff --git a/packages/neo-one-website/docs3/3-node/1-docker.md b/packages/neo-one-website/docs3/3-node/1-docker.md new file mode 100644 index 0000000000..94aff69d6b --- /dev/null +++ b/packages/neo-one-website/docs3/3-node/1-docker.md @@ -0,0 +1,143 @@ +--- +slug: node-docker +title: Local Docker Development +--- + +In this section we will cover how to deploy a NEO•ONE Node locally using the NEO•ONE Node Docker image. + +If you are unfamiliar with Docker or do not have a version installed locally visit their [getting started](https://www.docker.com/get-started) page. + +--- + +[[toc]] + +--- + +## Requirements + +- [Docker](https://www.docker.com/get-started) + - Minimum: **_at least_** 2GB Memory, 1cpu, and 50GB Storage allocated + - Recommended: 4GB Memory, 2cpu, and 60GB+ Storage allocated + (if you plan to deploy to a cluster you will need this for _each_ pod/container) + +## Getting Started + +NEO•ONE pushes a new node image to [dockerhub](https://hub.docker.com/r/neoonesuite/node) every time a new version is published. We publish a new node image with each commit as well as tagged versions for official releases. We recommend using the most recent tagged version, such as `neoonesuite/node:neo-one-node-binv2.3.0`. + +After you have installed Docker, run the following in a terminal: + +```bash +docker pull neoonesuite/node +docker run neoonesuite/node +``` + +Voila! You should now be running the most recent NEO•ONE Node in a local docker container and will see logs to confirm it has started. Since the NEO•ONE Node uses [pino](https://www.npmjs.com/package/pino) for logging we recommend piping the logs through [pino-pretty](https://github.com/pinojs/pino-pretty) during development. Note that the node won't begin syncing with the blockchain until additional configuration is provided. + +## Configuring + +There are **several** ways to configure the node; any [rc](https://github.com/dominictarr/rc#rc) type configuration is accepted. as an example we can set the `logger` level of the node to _trace_ using either: + +```bash +docker run neoonesuite/node --telemetry.logging.level=trace +``` + +or through environment variables + +```bash +docker run -e neo-one_telemetry__logging__level=trace neoonesuite/node +``` + +Additionally you have the option of creating a `config` (no extension) file and mounting it directly to the container. By default the node will look for a config at `/etc/neo-one`. + +So if we have a config + +```bash +## /path/to/config +{ + "telemetry": { + "logging": { + "level": "trace" + } + } +} +``` + +located at `/path/to/config` we could mount this to the default location as: + +```bash +docker run -v /path/to:/etc/neo-one/ neoonesuite/node +``` + +(Note that you must mount the **entire** folder the config file is in) + +After running any the above you should see more logging on startup! For more configuration options see the [configuration reference](/docs/node-configuration). + +## Storage + +Similarly to how we can mount a configuration folder to the container for local testing we can also mount a folder for storing the blockchain data our node will collect. By default, the node will use `/root/.local/share/neo-one` as its storage. We can mount a local folder `/path/to/node-data/` using + +```bash +docker run -v /path/to/node-data:/root/.local/share/neo-one neoonesuite/node +``` + +This is helpful when testing locally as you won't have to re-sync your node-data on every restart. + +## Port Publishing + +By default the container will be able to access external resources, such as connecting and syncing with other relay nodes after setting `node.rpcURLs`. + +If you would like your local Docker container to be able to send its own data, you'll need to `publish` the port using docker commands. As an example we can enable node metrics using the following command: + +```bash +docker run -p 8001:8001 neoonesuite/node --telemetry.port=8001 +``` + +Upon visiting `localhost:8001/metrics` you should now see the node-metrics page. + +::: warning + +Note + +By default metrics are **disabled** so you _must_ include the `--telemetry.port=8001` argument or provide a telemetry port through other means of configuration (see above). + +::: + +## Examples + +The following configurations should be a solid jumping off point for working with the node. For each of the three examples here we will also show how to implement them using [Docker Compose](/docs/node-compose/). + +In all three examples we will use + +```bash +docker run -v /node-config/:/etc/neo-one/ -v /node-data/:/root/.local/share/neo-one neoonesuite/node +``` + +to mount our configuration and local data file before starting the node. Go ahead and create the two folders `node-config` and `node-data` if you would like to follow along. + +### Sync + +To sync your node with other nodes on the network, you must specify them using the `node.rpcURLs` configuration setting. A list of current mainnet nodes can be found at: http://monitor.cityofzion.io/ + +```bash +#/node-config/config +{ + "node": { + "rpcURLs": [ + "http://seed6.ngd.network:10332", + "http://node1.nyc3.bridgeprotocol.io:10332" + ] + } +} +``` + +Now, if we apply this configuration we can begin to request block information from other nodes. After saving this to `node-config/config`, run the command listed above. + +Upon successfully starting the node, you should begin to see `relay_block` events! + +::: warning + +Note + +Its worth mentioning that syncing the entire blockchain can take a **very** long time. If you plan on syncing/restoring multiple times it might be worth creating a backup of your `node-data` folder. + +::: diff --git a/packages/neo-one-website/docs3/3-node/2-kubernetes.md b/packages/neo-one-website/docs3/3-node/2-kubernetes.md new file mode 100644 index 0000000000..8eae821645 --- /dev/null +++ b/packages/neo-one-website/docs3/3-node/2-kubernetes.md @@ -0,0 +1,401 @@ +--- +slug: node-kubernetes +title: Kubernetes +--- + +In this section we will cover how to deploy a NEO•ONE Node to a Kubernetes cluster. + +If you are unfamiliar with Kubernetes visit their [getting started](https://kubernetes.io/docs/tutorials/kubernetes-basics/) page, +in particular we will be implementing a [StatefulSet](https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/) locally using Kubernetes through Docker. + +--- + +[[toc]] + +--- + +## Requirements + +- [Docker](https://www.docker.com/get-started) + - Minimum: **_at least_** 2GB Memory, and 50GB Storage allocated + - Recommended: 4GB Memory, 60GB+ Storage allocated (you will need ~60GB of storage per pod) +- [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) + - You can enable Kubernetes through the docker GUI; Docker >> Preferences... >> Kubernetes >> Enable Kubernetes + +--- + +## Getting Started + +The following deployment spec will create a StatefulSet of `n` nodes defined by `spec.replicas`. Each requests 60GB of storage and 4GB of memory. If you do not have a default storage class set (docker will automatically create one for local deployments) you will need to create one, see [storage classes](https://kubernetes.io/docs/concepts/storage/storage-classes/) for more information. + +A requirement of StateFul sets is a headless service, so we'll start by creating `neo-one-service`: + +```yml +#node-svc.yml +apiVersion: v1 +kind: Service +metadata: + name: neo-one-node + labels: + app: neo-one-node +spec: + ports: + - port: 8080 + name: node + clusterIP: None + selector: + app: neo-one-node +``` + +followed by the StatefulSet itself which we'll save as `node-spec.yml`: + +```yml +# node-spec.yml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: node +spec: + serviceName: "neo-one-node" + replicas: 1 + selector: + matchLabels: + app: neo-one-node + template: + metadata: + labels: + app: neo-one-node + spec: + containers: + - name: neo-one-node + image: neoonesuite/node + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + name: node + volumeMounts: + - name: node-data + mountPath: /root/.local/share/neo-one + args: [ + "--node.rpcURLs=http://seed6.ngd.network:10332", + "--node.rpcURLs=https://seed1.red4sec.com:10332" + ] + resources: + requests: + memory: "4Gi" + cpu: "1" + volumeClaimTemplates: + - metadata: + name: node-data + spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 60Gi +``` + +Running this deployment with + +```bash +kubectl apply -f node-svc.yml +kubectl apply -f node-spec.yml +``` + +will start a single pod which: + +- makes a persistent volume claim for 60GB of storage. +- starts the node with this volume mounted to the default node-storage path +- if node-data isn't present, restore from the public google-cloud backup +- sync the node using two seeds from http://monitor.cityofzion.io/ + +There are two main benefits to deploying the nodes this way. If a pod needs to restart for _any_ reason it will always attempt to bind to the same persistent volume and will not start until it is scheduled on the same machine as that volume. It also makes it incredibly simple to scale the number of nodes you would like to run. + +## Pause/Shutdown + +The simplest way to pause any pods from scheduling/running is by setting `spec.replicas: 0` in your `node-spec.yml` and running + +```bash +kubectl apply -f node-spec.yml +``` + +To purge the persisted volume space and shutdown the headless service you can simply delete both with: + +```bash +kubectl delete svc neo-one-service +kubectl delete statefulset node +``` + +## Configuration + +[Configuration Reference](/docs/node-configuration/) + +While the above examples shows how to configure our pods with environment variables we can also mount a [ConfigMap](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/) to our pods. As an example we will use a basic configuration: + +```bash +#/path/to/config.json +{ + "telemetry": { + "logging": { + "level": "debug" + } + } +} +``` + +Creating a ConfigMap is as easy as running: + +```bash +#create the configMap +kubectl create configmap example-config-map --from-file=config=/path/to/config.json +#inspect the configMap +kubectl describe configmap example-config-map +``` + +Then, we can apply the ConfigMap by modifying the node-spec above to the following: + +```yml +# node-spec.yml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: node +spec: + serviceName: 'neo-one-node' + podManagementPolicy: 'Parallel' + replicas: 1 + selector: + matchLabels: + app: neo-one-node + template: + metadata: + labels: + app: neo-one-node + spec: + containers: + - name: neo-one-node + image: neoonesuite/node + ports: + - containerPort: 8080 + name: node + volumeMounts: + - name: node-data + mountPath: /root/.local/share/neo-one + - name: config-volume + mountPath: /etc/neo-one/config + subPath: config + resources: + requests: + memory: '4Gi' + cpu: '1' + volumes: + - name: config-volume + configMap: + name: example-config-map + optional: true + + volumeClaimTemplates: + - metadata: + name: node-data + spec: + accessModes: ['ReadWriteOnce'] + resources: + requests: + storage: 60Gi +``` + +::: warning + +Note + +Because of how [rc](https://www.npmjs.com/package/rc) searches for configuration files the key of the configMap MUST be `config` no extension. + +::: + +## Health Probes + +Sometimes a node will go down and need to be restarted, more commonly a node gets 'stuck' while syncing the blockchain data from other nodes. Because of this it can be extremely useful to configure health probes alongside your pods. + +To enable health checks on the NEO•ONE Node you must first enable the options in your configuration. Assuming you have set up configuration mounting described above the following example `config.json` will enable health checks: + +```json +{ + "node": { + "rpcURLs": [ + "http://seed1.ngd.network:10332", + "http://seed2.ngd.network:10332", + "http://seed3.ngd.network:10332", + "http://seed4.ngd.network:10332", + "http://seed5.ngd.network:10332", + "http://seed6.ngd.network:10332", + "http://seed7.ngd.network:10332", + "http://seed8.ngd.network:10332", + "http://seed9.ngd.network:10332", + "http://seed10.ngd.network:10332", + "https://seed1.cityofzion.io:443", + "https://seed2.cityofzion.io:443", + "https://seed3.cityofzion.io:443", + "https://seed4.cityofzion.io:443", + "https://seed5.cityofzion.io:443" + ] + }, + "network": { + "listenTCP": { + "port": 8081 + } + }, + "rpc": { + "http": { + "port": 8080 + }, + "liveHealthCheck": { + "rpcURLs": [ + "http://seed1.ngd.network:10332", + "http://seed2.ngd.network:10332", + "http://seed3.ngd.network:10332", + "http://seed4.ngd.network:10332", + "http://seed5.ngd.network:10332", + "http://seed6.ngd.network:10332", + "http://seed7.ngd.network:10332", + "http://seed8.ngd.network:10332", + "http://seed9.ngd.network:10332", + "http://seed10.ngd.network:10332", + "https://seed1.cityofzion.io:443", + "https://seed2.cityofzion.io:443", + "https://seed3.cityofzion.io:443", + "https://seed4.cityofzion.io:443", + "https://seed5.cityofzion.io:443" + ] + }, + "readyHealthCheck": { + "rpcURLs": [ + "http://seed1.ngd.network:10332", + "http://seed2.ngd.network:10332", + "http://seed3.ngd.network:10332", + "http://seed4.ngd.network:10332", + "http://seed5.ngd.network:10332", + "http://seed6.ngd.network:10332", + "http://seed7.ngd.network:10332", + "http://seed8.ngd.network:10332", + "http://seed9.ngd.network:10332", + "http://seed10.ngd.network:10332", + "https://seed1.cityofzion.io:443", + "https://seed2.cityofzion.io:443", + "https://seed3.cityofzion.io:443", + "https://seed4.cityofzion.io:443", + "https://seed5.cityofzion.io:443" + ] + } + } +} +``` + +Be sure to apply this new config to your ConfigMap `example-config-map` by running: + +```bash +kubectl delete configmap example-config-map +kubectl create configmap example-config-map --from-file=config=/path/to/config.json +``` + +After our config has been mapped we can add the liveness/readiness configurations to our `node-spec.yml`: + +```yml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: node +spec: + selector: + matchLabels: + app: neo-one-node + serviceName: 'neo-one-node' + podManagementPolicy: 'Parallel' + replicas: 1 + template: + metadata: + labels: + app: neo-one-node + spec: + containers: + - name: neo-one-node + image: neoonesuite/node + ports: + - containerPort: 8080 + name: node + volumeMounts: + - name: node-data + mountPath: /root/.local/share/neo-one + - name: config-volume + mountPath: /etc/neo-one/config + subPath: config + resources: + requests: + memory: '4Gi' + cpu: '1' + livenessProbe: + httpGet: + path: /live_health_check + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 60 + readinessProbe: + httpGet: + path: /ready_health_check + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 15 + volumes: + - name: config-volume + configMap: + name: example-config-map + optional: true + + volumeClaimTemplates: + - metadata: + name: node-data + spec: + accessModes: ['ReadWriteOnce'] + resources: + requests: + storage: 60Gi +``` + +After starting this StatefulSet with + +```bash +kubectl apply -f node-spec.yml +``` + +you should be able to inspect the state of the health checks (once they start running) with + +```bash +kubectl describe pod node-0 +``` + +see [Kubernetes Documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#define-readiness-probes) for more information on health probes. + +## Exposing Pods of a StatefulSet Locally + +Since we start our StatefulSet under a headless service we do not have direct access to the underlying endpoints (see [headless services](https://kubernetes.io/docs/concepts/services-networking/service/#headless-services)). The solution to this issue is by creating _another_ service which explicitly targets the pods created by the stateful set. For our single pod example it is as simple as starting a service: + +```yml +#node-0-svc.yml +apiVersion: v1 +kind: Service +metadata: + name: node-0-svc +spec: + type: LoadBalancer + externalTrafficPolicy: Local + selector: + statefulset.kubernetes.io/pod-name: node-0 + ports: + - protocol: TCP + port: 8080 + targetPort: 8080 +``` + +Voilà! You should now be able to access the pod locally! You can test this by running + +```bash +curl localhost:8080/live_health_check +``` diff --git a/packages/neo-one-website/docs3/3-node/3-docker-compose.md b/packages/neo-one-website/docs3/3-node/3-docker-compose.md new file mode 100644 index 0000000000..5147a77fcb --- /dev/null +++ b/packages/neo-one-website/docs3/3-node/3-docker-compose.md @@ -0,0 +1,102 @@ +--- +slug: node-compose +title: Docker Compose +--- + +In this section we will cover how to deploy a NEO•ONE Node to a swarm using Docker Compose. + +If you haven't already be sure to check out the local docker development [section](/docs/node-docker) to familiarize yourself with the container we are deploying. Additionally, brushing up on [Docker-Compose](https://docs.docker.com/compose/) would also be worthwhile. + +--- + +[[toc]] + +## Getting Started + +We'll be deploying with docker-compose using `swarm` mode. The `docker-compose.yml` below is a very similar deployment to what we saw in the [kubernetes](/docs/node-kubernetes) section. We create a persistent named-volume for each container started and run our backup and sync configuration. + +```yml +## docker-compose.yml +version: "3.1" +services: + node: + image: neoonesuite/node + command: [ + "--node.rpcURLs=http://seed6.ngd.network:10332", + "--node.rpcURLs=https://seed1.red4sec.com:10332" + ] + deploy: + replicas: 1 + resources: + limits: + cpus: "1" + memory: 4G + restart_policy: + condition: on-failure + volumes: + - node-data:/root/.local/share/neo-one +volumes: + node-data: +``` + +To start a docker swarm and apply our deployment you can run + +```bash +docker swarm init +docker stack deploy -c docker-compose.yml test +``` + +You can then check this service is running with + +```bash +docker service ls +``` + +Finally, to shutdown this deployment kill the swarm using + +```bash +docker swarm leave --force +``` + +::: warning + +Note + +If you delete the service created by docker, you will still need to cleanup the volume, `node-data` in our example, that is created on startup. You can find the volume using `docker volume ls` and remove it using `docker volume rm `. + +::: + +## Logs + +You can list all of the containers being run using + +```bash +docker container ls +``` + +then to see its logs you can either attach directly to the container (we recommend this only for testing startup as SIGINT will kill the container) with + +```bash +docker attach +``` + +or check its most recent logs + +```bash +docker logs +``` + +## Health Checks + +You can add health checks to a docker swarm similar to a kubernetes setup. After enabling live checks in the NEO•ONE Node configuration we can enable a probe by adding the following to our compose configuration: + +```yml +healthcheck: + test: ['CMD', 'curl', '-f', 'http://localhost:/live_health_check'] + interval: 1m30s + timeout: 10s + retries: 3 + start_period: 45s +``` + +See [docker documentation](https://docs.docker.com/compose/compose-file/#healthcheck) for more information about health check configurations. diff --git a/packages/neo-one-website/docs3/3-node/4-build-from-source.md b/packages/neo-one-website/docs3/3-node/4-build-from-source.md new file mode 100644 index 0000000000..91d796c461 --- /dev/null +++ b/packages/neo-one-website/docs3/3-node/4-build-from-source.md @@ -0,0 +1,72 @@ +--- +slug: node-source +title: Building From Source +--- + +In this brief walk-through we will show you how to build the NEO•ONE Node from source code. + +This can be useful for local debugging and if you would like to make your own contribution to the node repository. + +--- + +[[toc]] + +--- + +## Requirements + +- [Node](https://nodejs.org) >= 10.16.0 (We recommend the latest version) + - Linux and Mac: We recommend using [Node Version Manager](https://github.com/creationix/nvm). + - Windows: We recommend using [Chocolatey](https://chocolatey.org/). +- [Yarn](https://yarnpkg.com/) (recommended) + +--- + +## Build + +Once you have cloned the [NEO•ONE repository](https://github.com/neo-one-suite/neo-one) (or preferably your own fork of the repository) you can run the following to build the node entry point + +```bash +cd neo-one +yarn install +yarn build:node +cd ./dist/neo-one/packages/neo-one-node-bin/bin/ +``` + +`yarn build:node` will build a bin for the node as well as the `@neo-one` packages that it depends on. For this tutorial we will `cd` into the entry point's build directory to save time. Running the new node then is as simple as + +```bash +node neo-one-node +``` + +## Configure + +[Configuration Reference](/docs/node-configuration) + +When running the node locally it is quite easy to apply a configuration file compared to docker since we don't have to mount it to a container. An example configuration for syncing the node + +```bash +## path/to/config.json +{ + "node": { + "rpcURLs": { + "http://seed6.ngd.network:10332", + "http://seed10.ngd.network:10332" + } + } +} +``` + +Can be run using: + +```bash +node neo-one-node --config /path/to/config.json +``` + +Individual options can also be layered on top of our configuration: + +```bash +node neo-one-node --config /path/to/config.json --environment.logger.level=trace +``` + +Finally you have the option of adding a `.neo-onerc` app configuration file anywhere in the app directory (recommended at `/neo-one/`) to apply your configuration by default. See [rc](https://github.com/dominictarr/rc#rc) for more info on `rc` files. diff --git a/packages/neo-one-website/docs3/3-node/5-heroku.md b/packages/neo-one-website/docs3/3-node/5-heroku.md new file mode 100644 index 0000000000..abe0156619 --- /dev/null +++ b/packages/neo-one-website/docs3/3-node/5-heroku.md @@ -0,0 +1,52 @@ +--- +slug: node-heroku +title: Heroku Deployment +--- + +The NEO•ONE Node can be quickly deployed on Heroku using the deployment button below. + +More information on Heroku can be found [here](https://heroku.com/). + +--- + +[[toc]] + +## Deploy! + +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/neo-one-suite/neo-one.git) + +Upon successfully building the node-container and launching your app, you should see the node logs in your apps logs. + +## Configure + +[Configuration Reference](/docs/node-configuration) + +You can quickly apply environment variable configuration options to the node using the **Config Vars** in App >> Settings >> Config Vars. As an example we can set the log-level using a `config var` with key:value + +```bash +neo-one_telemetry__logging__level verbose +``` + +After applying the node will restart and update its configuration. + +::: warning + +Note + +Because of the environment-variable syntax `rc` expects, you must use the `neo-one___` syntax when applying a value. + +::: + +## Caveats + +Currently it is **not** possible to enable two or more `port` requiring processes simultaneously. This is because Heroku only allocates a single port to the app. By default the node's rpc server is using this port so if you would like to enable telemetry through a `config var` you will also need to disable the rpc server. + +Additionally it is not possible right now to set environment variable values for Array config options. This should be addressed soon. + +::: warning + +Note + +If you _would_ like to see metrics or enable other features that require a port, you must assign the port to `$PORT`, this is the environment variable supplied by heroku. + +::: diff --git a/packages/neo-one-website/docs3/3-node/6-configuration.md b/packages/neo-one-website/docs3/3-node/6-configuration.md new file mode 100644 index 0000000000..60ffb70a5b --- /dev/null +++ b/packages/neo-one-website/docs3/3-node/6-configuration.md @@ -0,0 +1,261 @@ +--- +slug: node-configuration +title: Configuration Reference +--- + +This section will serve as a reference for the NEO•ONE Node's many configuration options. + +--- + +[[toc]] + +--- + +## Path + +```bash +... +{ + "path?": string +} +... +``` + +_defaults to the data path supplied by [env-paths](https://www.npmjs.com/package/env-paths)_ + +`path` is the path used for storing blockchain data. + +In the [local docker](/docs/node-docker#Examples) example we could store blockchain data in a location other than `/root/.local/share/neo-one`, it should be noted you will need to change the mount location as well. + +## Telemetry + +```bash +... +{ + "telemetry?": { + "logging?": { + "level": string + }, + "prometheus?": { + "prefix?": string, + "port?": number + }, + "jaeger?": { + "host?": string, + "port?": number, + "maxPacketSize?": number + } + "tracing?": { + "logLevel?": number, + "plugins?": {}, + "bufferSize?": number, + "bufferTimeout?": number + } + } +} +... +``` + +`telemetry` options control the collection and exporting of logs, metrics, and spans from the node. + +### Logging + +\*defaults to **{level: 'silent'}\*** + +Desired logging level and output path of the node logging, options are for level are: + +``` +"silent" | "fatal" | "error" | "warn" | "info" | "debug" | "trace" +``` + +### Prometheus + +_disabled by default_ + +Enables the Prometheus exporter for exporting metrics about the NEO•ONE Node. You can add an app prefix and choose a port. If no port is set prometheus will default to port `9464`. + +### Jaeger + +_disabled by default_ + +Enables the jaeger exporter for exporting spans from the NEO•ONE Node. You can optionally supply a host and port, as well as a limit on the exported packet size. See the [Jaeger homepage](https://www.jaegertracing.io/) for more. + +### Tracing + +_disabled by default_ + +Enables trace collection for the NEO•ONE Node. This must be used in tangent with `jaeger` options in order to collect AND export span information from the Node. As advanced options you can enable extra opencensus plugins, as well as limit the size and timeout of spans waiting to be exported. + +## Blockchain + +```bash +... +#basic configuration +{ + "blockchain": "main" | "test" +} +... +``` + +```bash +#advanced configuration +... +{ + "blockchain": { + "genesisBlock": string, + "governingToken": string, + "utilityToken": string, + "decrementInterval": number, + "generationAmount": number, + "fees": Record, + "registerValidatorFee": string, + "messageMagic": number, + "addressVersion": number, + "privateKeyVersion": number, + "standbyValidators": string[], + "vm": { + "storageContext": { + "v0": { + "index": number + } + } + }, + "secondsPerBlock": number, + "maxTransactionsPerBlock": number, + "memPoolSize": number + } +} +... +``` + +--- + +_defaults to `main`_ + +As a shortcut you can specify the blockchain default settings as `main` or `test` to point to the NEO mainnet/testnet. + +In most cases the above will be enough, but you have the ability to define serialized blockchain settings. See [neo-one-node-consensus-test/config](https://github.com/neo-one-suite/neo-one/blob/master/packages/neo-one-node-bin/src/__data__/configs/consensus.ts) for an example of quickly constructing a privateNet using this method. + +## RPC + +```bash +... +{ + "rpc": { + "http?": { + "port": number, + "host?": string, + "keepAliveTimeout?": number + }, + "liveHealthCheck?": { + "rpcURLs?": string[], + "offset?": number, + "timeoutMS?": number, + "checkEndpoints?": number + }, + "readyHealthCheck?": { + "rpcURLs?": string[], + "offset?": number, + "timeoutMS?": number, + "checkEndpoints?": number + } + } +} +... +``` + +`rpc` options configures the internal RPC Server of the node. See `@neo-one/node-http-rpc`. + +--- + +### HTTP + +_by default http is enabled on `localhost:8080` OR `localhost:$PORT` if you have set the `PORT` environment variable_ + +`rpc.http` is used to configure the rpc server’s host options. It is important in a kubernetes setup that `containerPort` matches `rpc.http.port`. + +`keepAliveTimeout`: if you would like your server to close after _x_ seconds without activity set a timeout here (in milliseconds). + +### Health Checks + +`liveHealthCheck` _&_ `readyHealthCheck` share the same configuration. + +- `rpcURLs`: a list of RPC URLs to compare our node to +- `offset`: the acceptable difference of blocks ahead/behind to count as `live` or `ready` +- `timeoutMS`: timeout for RPC connections +- `checkEndpoints`: the number of different endpoints to check against before passing `true`/`false`. + +## Node + +```bash +... +{ + "node": { + "externalPort?": number, + "rpcURLs?": string[], + "consensus?": { + "enabled": boolean, + "options": { + "privateKey": string, + "privateNet": boolean + } + } + } +} +... +``` + +`node` options control connections and consensus options for the NEO•ONE Node. + +--- + +`externalPort` specifies the external port of the node which it can send messages to peers on. Typically the same as `network.listenTCP`. + +`rpcURLs` specifies a list of known node RPC URLs you would like to try and connect to. A list of public mainnet hosts can be found at http://monitor.cityofzion.io/. + +`unhealthyPeerSeconds` sets how long (in seconds) to wait for a peer response before deeming it 'unhealthy'. Defaults to 300 seconds. + +`consensus` sets the consensus options for the node, requires a privateNet setup. + +- `enabled` enables consensus +- `options.privateKey` the key for the network +- `options.privateNet` true/false + +## Network + +```bash +... +{ + "network": { + "listenTCP": { + "port": number, + "host?": string + }, + "seeds?": string[], + "peerSeeds?": string[], + "externalEndpoints?": string[], + "maxConnectedPeers?": number, + "connectPeersDelayMS?": number, + "socketTimeoutMS?": number + } +} +... +``` + +`network` options can be used to control seeds, endpoints, and socketTimeout defaults. + +--- + +`listenTCP` when provided at least a port this allows other nodes to create TCP connections with this one over that port. `host` is optional and defaults to 'localhost'. + +`seeds` specifies external seeds you would like to connect to. + +`peerSeeds` specifies trusted seeds, typically ones run by yourself or on the same cluster. + +`externalEndpoints` specifies specific known external peers that you want to _ignore_ starting connections with, for instance endpoints in another cluster managed by you. + +`maxConnectedPeers` sets the maximum number of peers the node will attempt to hold a connection with at once. Defaults to 10. + +`connectPeersDelayMS` sets the amount of time (in milliseconds) to wait after requesting a peer connection before requesting another. Defaults to 5000. + +`socketTimeoutMS` sets the timeout of peer requests (in milliseconds). Defaults to 1 minute. diff --git a/packages/neo-one-website/docs3/3-node/config.json b/packages/neo-one-website/docs3/3-node/config.json new file mode 100644 index 0000000000..54969a7265 --- /dev/null +++ b/packages/neo-one-website/docs3/3-node/config.json @@ -0,0 +1,4 @@ +{ + "title": "Node", + "numbered": false +} diff --git a/packages/neo-one-website/docs3/4-contributing/0-how-to-contribute.md b/packages/neo-one-website/docs3/4-contributing/0-how-to-contribute.md new file mode 100644 index 0000000000..ec9c271bea --- /dev/null +++ b/packages/neo-one-website/docs3/4-contributing/0-how-to-contribute.md @@ -0,0 +1,77 @@ +--- +slug: how-to-contribute +title: How to Contribute +--- + +Welcome to the NEO•ONE community! We're always looking for more contributors and are happy to have you. This document should help make the process for contributing clear and answer some questions that you may have. + +Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved. + +Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue, assessing changes, and helping you finalize your pull requests. + +This project and everyone participating in it is governed by the [Code of Conduct](/docs/code-of-conduct). By participating, you are expected to uphold this code. Please report unacceptable behavior to [contact@neo-one.io](mailto:contact@neo-one.io). + +--- + +[[toc]] + +--- + +## How Can I Contribute? + +NEO•ONE is an open source project and we love to receive contributions from our community — you! There are many ways to contribute, from writing tutorials or blog posts, improving the documentation, submitting bug reports and feature requests or writing code which can be incorporated into NEO•ONE itself. + +Please, don't use the issue tracker for support questions. The [Help](/docs/getting-started#Help) section is the best place to start for getting support. + +### Reporting Bugs + +Well-written bug reports with consistently reproducible steps are invaluable to the development of NEO•ONE. Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). Before creating an issue, please perform a [search](https://github.com/neo-one-suite/neo-one/issues?q=is%3Aopen+is%3Aissue+label%3Abug) to see if the problem has already been reported. After you've determined a bug does not already exist, create an issue and fill in the template. + +### Suggesting Enhancements + +Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Please provide as much detail and context as possible. + +### How to Get Started in the NEO•ONE Repo + +- Make sure you have [Node](https://nodejs.org) >= 10.16.0 installed (We recommend the latest version). + - Linux and Mac: We recommend using [Node Version Manager](https://github.com/creationix/nvm). + - Windows: We recommend using [Chocolatey](https://chocolatey.org/). +- Install [RushJS](https://rushjs.io/) with `npm install -g @microsoft/rush`. + - We use RushJS for monorepo management. When you get started in the NEO•ONE repo you will use RushJS for nearly every task, like installing dependencies, building the packages, running tests, etc. + - For more information on RushJS, see the [docs](https://rushjs.io/pages/intro/welcome/). + - All Rush commands should be run inside the NEO•ONE repo. +- Clone the repo with `git clone https://github.com/neo-one-suite/neo-one.git`. +- Then run `rush install` to install the dependencies. +- Then run `rush build` to build the packages. Rush will perform an "incremental build", which means that it will only build packages whose source files have changed since the last successful build and the packages that depend on those packages. +- You should now be ready to start making changes to the source code. Once you're done making changes make sure to run `rush build` before running E2E tests or trying to run a bin. +- To run all the unit tests run `rush test`. To run all the E2E tests run `rush e2e`. + - There are A LOT of unit tests, which can take a few minutes to run all the way through. To only run a smaller set of tests you can specify a file or blob of tests to run with `rush test -t` or `rush e2e -t`. + - For example, if you wanted to only run the unit tests in `neo-one-client-common` you would run `rush test -t packages/neo-one-client-common/src/__tests__/**/*` +- If you want to test your changes with the NEO•ONE CLI run `rush build`. Then, to start the CLI you'd run `node packages/neo-one-cli/bin/neo-one.js` from inside the NEO•ONE repository. You will then be running the new NEO•ONE CLI with your changes. From there you can see your new code directly in action. +- To see all the available RushJS commands run `rush --help`. + +### Your First Code Contribution + +Unsure where to begin contributing to NEO•ONE? Here are some great ways to get started: + +- Chat with us on [Discord](https://discord.gg/S86PqDE) about ways to contribute! +- Documentation (like the text you are reading now) can always use improvement! All pages on this website include an edit button which you can click to modify the documentation. +- Adding test coverage is a great way to get familiar with the codebase. +- Find an existing issue with the [help wanted and good first issue](https://github.com/neo-one-suite/neo-one/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3Ahelp%20wanted+label%3Agood%20first%20issue) labels. + +Once you've had your first pull request approved and merged, find existing issues marked with [help wanted](https://github.com/neo-one-suite/neo-one/issues?utf8=%E2%9C%93&q=is%3Aopen+label%3Ahelp%20wanted) labels to continue contributing or suggest an enhancement. Respond on the issue thread expressing interest in working on it. This helps other people know that the issue is active, and hopefully prevents duplicated efforts. + +--- + +## Pull Requests + +- Follow the process outlined in [GitHub Standard Fork & Pull Request Workflow](https://gist.github.com/Chaser324/ce0505fbed06b947d962) when submitting a pull request. +- Fill in the pull request template. +- Pre-commit hooks will run basic checks automatically. +- Pull requests should typically be accompanied with tests. Your reviewers will request tests when appropriate if they are missing. + +--- + +## License + +By contributing to NEO•ONE, you agree that your contributions will be licensed under its MIT license. diff --git a/packages/neo-one-website/docs3/4-contributing/1-codebase-overview.md b/packages/neo-one-website/docs3/4-contributing/1-codebase-overview.md new file mode 100644 index 0000000000..313678f993 --- /dev/null +++ b/packages/neo-one-website/docs3/4-contributing/1-codebase-overview.md @@ -0,0 +1,272 @@ +--- +slug: codebase-overview +title: Codebase Overview +--- + +NEO•ONE is a very large project, which is organized into 50+ interdependent packages. Below is a breakdown +of what each package is used for, grouped by functionality. + +--- + +[[toc]] + +--- + +## Client + +### neo-one-client + +Exports nearly everything from `neo-one-client-common` and `neo-one-client-core`, plus `DeveloperTools` from `neo-one-developer-tools`. + +### neo-one-client-common + +One of the core client packages, which provides APIs for cryptography, commonly used client functions, reading binary input, building scripts, and more. + +### neo-one-client-core + +The core client package, which exports the NEO•ONE Client, which is used to construct and send transactions, read accounts, hold keys, read the blockchain, and much more. + +### neo-one-client-full + +Exports nearly everything from `neo-one-client` and `neo-one-client-full-core`. + +### neo-one-client-full-common + +Exports common models. + +### neo-one-client-full-core + +Contains an extension of the Client in `neo-one-client-core` which provides extra APIs and functionality, plus the ReadClient, and more. + +### neo-one-client-switch + +Provides NEO•ONE Client functionality that switches between NodeJS and browser environments. + +## Node + +### neo-one-node + +Contains the `FullNode` class which is used by the NEO•ONE CLI, `neo-one-node-bin`, and for testing purposes. + +### neo-one-node-bin + +Contains the `bin` for staring the NEO•ONE node. + +### neo-one-node-blockchain + +Primarily contains the `Blockchain` class which handles nearly every blockchain function for the node. + +### neo-one-node-browser + +Creates the full NEO•ONE node used in the browser, especially for the NEO•ONE website courses. + +### neo-one-node-browser-worker + +The web worker wrapper for the NEO•ONE node used in the browser. + +### neo-one-node-concensus + +Handles concensus for the node. + +### neo-one-node-core + +Contains all the objects for Accounts, Blocks, Transactions, Contracts, Headers, etc. used in the node and other packages. + +### neo-one-node-http-rpc + +Creates the actual HTTP server used by the node for relaying RPC calls. + +### neo-one-node-neo-settings + +Handles the node settings, like creating the genesis block, defining the governing token, and setting other key blockchain constants. + +### neo-one-node-network + +Contains the functionality for relaying information between the NEO•ONE node and other nodes in the network. + +### neo-one-node-offline + +Handles offline operations for the node, like dumping and loading chainfile data. + +### neo-one-node-protocol + +Handles the protocol for connecting to other nodes in the network. + +### neo-one-node-rpc-handler + +Contains the function which creates the RPC handlers for the node. These handlers are what are called by the node when it receives RPC requests. + +### neo-one-node-storage-cache + +Handles storage data caching for the node. + +### neo-one-node-storage-common + +Contains common functions used by node storage. + +### neo-one-node-storage-levelup + +Creates the storage and the storage APIs used by the node to store and access blockchain data. + +### neo-one-node-tools + +Primarily provides the entrypoint for restoring a NEO•ONE node from blockchain data, like in a chainfile. + +### neo-one-node-vm + +Contains the NEO•ONE implementation of the NeoVM, used in the NEO•ONE node and used for testing the compiler. + +### neo-one-http + +Contains very basic Koa HTTP server utils. + +### neo-one-http-context + +Contains very basic server utils, plus common functions and constants. + +## CLI + +### neo-one-cli + +This is the main entrypoint for the NEO•ONE CLI code. It handles all NEO•ONE CLI commands. + +### neo-one-cli-common + +Handles more CLI functionality, like configuration, setting up wallets, setting up a NEO•ONE Client, etc. + +### neo-one-cli-common-node + +Contains more CLI features, like configuration and network setup. + +## Compiler + +### neo-one-smart-contract + +Exports declaration files that define custom types used in a NEO•ONE smart contract. + +### neo-one-smart-contract-codegen + +Generates helpers for invoking smart contracts, and generates other code for creating dApps around smart contracts. + +### neo-one-smart-contract-compiler + +The largest package in NEO•ONE. Contains the entire smart contract compiler, which creates the actual compiled NeoVM bytecode. + +### neo-one-smart-contract-compiler-node + +Creates the environment for compiling smart contracts, which is then used in the CLI and other packages. + +### neo-one-smart-contract-lib + +Defines NEP17 tokens and ICOs. + +### neo-one-smart-contract-test + +Creates the environment for testing smart contracts. + +### neo-one-smart-contract-test-browser + +Creates the environment for testing smart contracts in the browser. + +### neo-one-smart-contract-test-common + +Runs smart contract unit tests. + +### neo-one-smart-contract-typescript-plugin + +Creates a plugin for the NEO•ONE smart contract compiler. + +## Website + +### neo-one-react + +Primarily creates and exports a `FromStream` React component for subscribing to `Observables` in React. + +### neo-one-react-common + +Creates additional React components that are used by the NEO•ONE website and exports everything from `neo-one-react-core`. + +### neo-one-react-core + +Creates all the base React components that are used by the NEO•ONE website and other React components. + +### neo-one-website + +Contains the entire NEO•ONE website. + +### neo-one-worker + +Contains helpers for creating and connecting web workers, especially for the NEO•ONE website. + +### neo-one-local-browser + +Handles a lot of the setup and execution of the courses on the NEO•ONE website, like loading files into a browser-implemented +DB, compiling smart contracts, deploying contracts, testing contracts, etc. + +### neo-one-local-browser-worker + +A web worker wrapper for `neo-one-local-browser`. + +### neo-one-local-singleton + +Contains functions that are used in the browser for the NEO•ONE courses. + +### neo-one-editor + +Contains the code for the code editor used in the NEO•ONE website. + +### neo-one-editor-server + +Contains the code for the code editor server used in the NEO•ONE website. + +## Build + +### neo-one-build-common + +Common build modules. + +### neo-one-build-tests + +Environment setup for running Jest unit and end-to-end tests. + +### neo-one-build-tools + +Contains all the build tools for checking, cleaning, formatting, preparing, and building NEO•ONE packages. + +### neo-one-build-tools-web + +Contains all the webpack compilers and build configurations, primarily for the NEO•ONE website. + +## Other + +### neo-one-logger + +Handles almost all the logging for NEO•ONE packages. + +### neo-one-logger-config + +Handles configuration for `neo-one-logger`. + +### neo-one-developer-tools + +Provides the interface for controlling a private development network. + +### neo-one-developer-tools-frame + +Creates the developer tools iframe for controlling a private network. + +### neo-one-ts-utils + +Primarily exports TypeScript compiler API helper functions for use in build tools, the compiler, and more. + +### neo-one-typescript-concatenator + +Handles the concatenation of multiple TypeScript files into one file for the TypeScript compiler. + +### neo-one-utils + +Contains various helper functions, utilities, and constants that are used throughout NEO•ONE. + +### neo-one-utils-node + +Contains various helper functions, utilities, and constants that are used primarily in the node. diff --git a/packages/neo-one-website/docs3/4-contributing/2-smart-contract-compiler.md b/packages/neo-one-website/docs3/4-contributing/2-smart-contract-compiler.md new file mode 100644 index 0000000000..170dac5dbf --- /dev/null +++ b/packages/neo-one-website/docs3/4-contributing/2-smart-contract-compiler.md @@ -0,0 +1,62 @@ +--- +slug: smart-contract-compiler +title: Smart Contract Compiler +--- + +## How Can I Add New Features or Fix Bugs in the Smart Contract Compiler? + +### Basics of the Smart Contract Compiler + +The NEO•ONE Smart Contract Compiler is by far the _largest_ NEO•ONE package. The compiler takes in (almost) regular +TypeScript code and compiles it to [NeoVM](https://docs.neo.org/docs/en-us/basic/technology/neovm.html) bytecode, which can +then be deployed to the Neo blockchain and run on the NeoVM. NEO•ONE uses the TypeScript compiler API to parse the TypeScript code +into a tree of "nodes" with information about each node. Our compiler then "visits" each node and begins to output specific +bytecode for the VM instructions that are needed in order to execute the logic that is specified by the TypeScript code. +The bytecode outputted by the compiler corresponds to human-readable opcodes that each correspond to an action that the +NeoVM will perform. These actions are the manipulation of data by the NeoVM that will ultimately translate to changes to the +state of the Neo blockchain. + +### Where to Look in the Code + +Now that you have a _very_ basic understanding of how the NEO•ONE compiler works, you can start digging into the `neo-one-smart-contract-compiler` +package. Most likely you'll be looking in `neo-one-smart-contract-compiler/compiler/` (where `` is one of `constants`, `declaration`, `expression`, `helper`, `scope`, `statement`) +for the specific syntax that is broken or where you want to add a feature. For example, if you want to change how we compile the `==` token, you would +look for `EqualsEqualsEqualsHelper.ts` in `neo-one-smart-contract-compiler/compiler/helper/relational/EqualsEqualsHelper.ts`. In there you'll see +how this helper will "emit" different opcodes, syscalls, and other helpers to manipulate the Evaluation Stack. The comment line above each emit shows a +representation of the Evaluation Stack _after_ that bytecode is evaluated. + +### Write Unit Tests for What You're Working On + +Once you have an understanding of what helpers or syntax compilers you need to change in order to make your compiler change, the best way to begin is to write +a unit test that you will run to test your change. You'll see that nearly every helper and syntax compiler has a corresponding set of unit tests in `neo-one-smart-contract-compiler/src/__tests__`. +For example, the `IfStatementCompiler.ts` has a set of unit tests in `IfStatementCompiler.test.ts`. In there you'll see that we typically use the built in `assertEqual` method to +test if values are what we expect them to be. You'll also see that we have helpers, like the `helpers.executeString()` helper, that make it easy to compile a string and test for certain behavior. + +Here is an example unit test you would write to test your changes: + +```ts +import { helpers } from '../../../__data__'; + +describe('MyNewCompiler', () => { + test.only('simple test', async () => { + await helpers.executeString(` + if (!true) { + throw 'Failure'; + } + + const x = '10'; + assertEqual(x, '10'); + `); + }); +}); +``` + +### Start Hacking + +Once you've created a unit test that either recreates the bug you're trying to fix, or tests for the expected behavior of your new feature, you can start to make changes +to the compiler's source code and run your unit test. If you want to add logging (ie. `console.log`) to the source code to get more information you can, just make sure +to change the console settings in `neo-one-build-tests/environments/test/jestSetup.js`. From there you should make sure to only run one unit test at a time +so that you're only getting logs from the compilation of that one unit test. This will make it easier to learn what the compiler is doing when compiling a specific string. +To run a specific unit test, rather than all unit tests, run `rush test -t `. + +And that's it! Once you have this workflow setup you can hack away at the compiler code and run the unit test to test your changes, get logs, etc. diff --git a/packages/neo-one-website/docs3/4-contributing/3-code-of-conduct.md b/packages/neo-one-website/docs3/4-contributing/3-code-of-conduct.md new file mode 100644 index 0000000000..2cbf969889 --- /dev/null +++ b/packages/neo-one-website/docs3/4-contributing/3-code-of-conduct.md @@ -0,0 +1,74 @@ +--- +slug: code-of-conduct +title: Code of Conduct +--- + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [contact@neo-one.io](mailto:contact@neo-one.io). All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html diff --git a/packages/neo-one-website/docs3/4-contributing/config.json b/packages/neo-one-website/docs3/4-contributing/config.json new file mode 100644 index 0000000000..0f789a51e2 --- /dev/null +++ b/packages/neo-one-website/docs3/4-contributing/config.json @@ -0,0 +1,4 @@ +{ + "title": "Contributing", + "numbered": false +} diff --git a/packages/neo-one-website/tutorial/tutorial.md b/packages/neo-one-website/tutorial/tutorial.md index a30b5b2475..67afd4ed70 100644 --- a/packages/neo-one-website/tutorial/tutorial.md +++ b/packages/neo-one-website/tutorial/tutorial.md @@ -57,7 +57,7 @@ Here's how to setup your local development environment: 2. Follow the [installation instructions for Create React App](https://reactjs.org/docs/create-a-new-react-app.html#create-react-app) to make a new project. -- Be sure to invoke Create React App with the `--typescript` flag in order to enable TypeScript support: `npx create-react-app token --typescript` +- Be sure to invoke Create React App with the `--template typescript` flag in order to enable TypeScript support: `npx create-react-app token --template typescript` 3. Install NEO•ONE using either [yarn](https://yarnpkg.com/) From fb26f47e24fa071139ca5e57c9b574206bcdf576 Mon Sep 17 00:00:00 2001 From: Spencer Corwin Date: Wed, 3 Feb 2021 20:31:15 -0800 Subject: [PATCH 2/2] feat(preview4): update compiler, client, and cli for preview4 --- ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ .../fixup-cli_2020-12-08-19-02.json | 2 +- ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ ...work-preview4-rebase_2021-02-04-04-40.json | 11 +++ packages/neo-one-cli/src/cmd/start/network.ts | 1 - .../neo-one-cli/src/compile/writeContract.ts | 14 ++-- .../neo-one-cli/src/deploy/runMigration.ts | 2 +- .../neo-one-client-common/src/models/types.ts | 2 +- .../neo-one-client-common/src/models/vm.ts | 13 +-- packages/neo-one-client-common/src/types.ts | 33 ++++---- packages/neo-one-client-core/src/args.ts | 10 ++- packages/neo-one-client-core/src/nep17.ts | 13 +-- .../src/provider/NEOONEDataProvider.ts | 2 +- .../src/models/manifest/ContractABIModel.ts | 8 +- .../models/manifest/ContractManifestModel.ts | 23 +++-- packages/neo-one-client-full-core/src/args.ts | 3 +- .../neo-one-client-full-core/src/types.ts | 3 +- .../src/user/LocalUserAccountProvider.ts | 52 +++++++++--- .../neo-one-node-blockchain/src/verify.ts | 2 +- .../neo-one-node-core/src/ContractState.ts | 2 +- packages/neo-one-node-core/src/Storage.ts | 6 +- .../src/TransactionVerificationContext.ts | 4 +- .../src/manifest/ContractABI.ts | 4 +- .../src/manifest/ContractManifest.ts | 11 ++- .../src/transaction/Transaction.ts | 22 +++-- packages/neo-one-node-core/src/vm.ts | 2 +- .../neo-one-node-native/src/NativeContract.ts | 2 +- packages/neo-one-node-native/src/Nep17.ts | 2 +- packages/neo-one-node-protocol/src/Node.ts | 2 +- .../src/createHandler.ts | 1 + .../src/__tests__/rocksDBStorage.test.ts | 2 +- .../src/convertChange.ts | 42 +++++----- .../src/levelUpStorage.ts | 23 ++--- .../neo-one-node-vm/lib/Dispatcher.csproj | 4 +- .../src/__tests__/storage.test.ts | 2 +- .../src/__tests__/blockchain.test.ts | 2 +- .../src/__data__/helpers/startNode.ts | 10 +-- .../builtins/contract/scriptBuilder.test.ts | 5 +- .../builtins/contract/ValueForWithScript.ts | 42 ++++++++++ .../compile/builtins/contract/blockchain.ts | 13 ++- .../src/compile/builtins/contract/contract.ts | 64 ++++++++------ .../contract/smartContract/destroy.ts | 12 ++- .../src/compile/compile.ts | 12 +-- .../src/compile/getSmartContractInfo.ts | 15 +--- .../compile/helper/contract/IsCallerHelper.ts | 11 ++- .../compile/helper/contract/UpgradeHelper.ts | 15 ++-- .../src/compile/sb/BaseScriptBuilder.ts | 2 +- .../src/contract/ContractInfoProcessor.ts | 9 +- .../ManifestSmartContractProcessor.ts | 83 ++++--------------- .../src/createNode.ts | 1 - 75 files changed, 633 insertions(+), 285 deletions(-) create mode 100644 common/changes/@neo-one/cli-common/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/cli/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/client-common/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/client-core/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/client-full-common/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/client-full-core/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/client-full/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/client-switch/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/client/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/node-bin/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/node-blockchain/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/node-consensus/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/node-core/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/node-native/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/node-neo-settings/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/node-protocol/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/node-rpc-handler/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/node-storage-common/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/node-storage-levelup/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/node-vm/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/node/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/smart-contract-codegen/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/smart-contract-compiler/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/smart-contract-lib/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/smart-contract-test-common/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/smart-contract-test/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/smart-contract/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 common/changes/@neo-one/utils/compiler-work-preview4-rebase_2021-02-04-04-40.json create mode 100644 packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/ValueForWithScript.ts diff --git a/common/changes/@neo-one/cli-common/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/cli-common/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..1a7c8f9750 --- /dev/null +++ b/common/changes/@neo-one/cli-common/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/cli-common", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/cli-common", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/cli/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/cli/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..974b3ea5d5 --- /dev/null +++ b/common/changes/@neo-one/cli/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/cli", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/cli", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client-common/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/client-common/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..c645dbf7d7 --- /dev/null +++ b/common/changes/@neo-one/client-common/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/client-common", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/client-common", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client-core/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/client-core/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..f1a6d49778 --- /dev/null +++ b/common/changes/@neo-one/client-core/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/client-core", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/client-core", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client-core/fixup-cli_2020-12-08-19-02.json b/common/changes/@neo-one/client-core/fixup-cli_2020-12-08-19-02.json index 3b3a7db585..83344f4064 100644 --- a/common/changes/@neo-one/client-core/fixup-cli_2020-12-08-19-02.json +++ b/common/changes/@neo-one/client-core/fixup-cli_2020-12-08-19-02.json @@ -8,4 +8,4 @@ ], "packageName": "@neo-one/client-core", "email": "danwbyrne@gmail.com" -} \ No newline at end of file +} diff --git a/common/changes/@neo-one/client-full-common/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/client-full-common/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..a04b6f5aba --- /dev/null +++ b/common/changes/@neo-one/client-full-common/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/client-full-common", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/client-full-common", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client-full-core/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/client-full-core/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..6c4c2e831e --- /dev/null +++ b/common/changes/@neo-one/client-full-core/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/client-full-core", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/client-full-core", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client-full/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/client-full/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..034616705a --- /dev/null +++ b/common/changes/@neo-one/client-full/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/client-full", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/client-full", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client-switch/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/client-switch/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..aa1398ed1c --- /dev/null +++ b/common/changes/@neo-one/client-switch/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/client-switch", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/client-switch", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/client/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/client/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..4512ad415f --- /dev/null +++ b/common/changes/@neo-one/client/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/client", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/client", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-bin/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/node-bin/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..79db4752ec --- /dev/null +++ b/common/changes/@neo-one/node-bin/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/node-bin", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/node-bin", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-blockchain/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/node-blockchain/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..074d69d8d0 --- /dev/null +++ b/common/changes/@neo-one/node-blockchain/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/node-blockchain", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/node-blockchain", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-consensus/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/node-consensus/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..0660401353 --- /dev/null +++ b/common/changes/@neo-one/node-consensus/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/node-consensus", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/node-consensus", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-core/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/node-core/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..7767477096 --- /dev/null +++ b/common/changes/@neo-one/node-core/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/node-core", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/node-core", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-native/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/node-native/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..0035008347 --- /dev/null +++ b/common/changes/@neo-one/node-native/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/node-native", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/node-native", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-neo-settings/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/node-neo-settings/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..47632895fe --- /dev/null +++ b/common/changes/@neo-one/node-neo-settings/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/node-neo-settings", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/node-neo-settings", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-protocol/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/node-protocol/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..a5a46defb1 --- /dev/null +++ b/common/changes/@neo-one/node-protocol/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/node-protocol", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/node-protocol", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-rpc-handler/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/node-rpc-handler/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..6d77ea9458 --- /dev/null +++ b/common/changes/@neo-one/node-rpc-handler/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/node-rpc-handler", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/node-rpc-handler", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-storage-common/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/node-storage-common/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..30efa862df --- /dev/null +++ b/common/changes/@neo-one/node-storage-common/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/node-storage-common", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/node-storage-common", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-storage-levelup/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/node-storage-levelup/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..43188000a3 --- /dev/null +++ b/common/changes/@neo-one/node-storage-levelup/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/node-storage-levelup", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/node-storage-levelup", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node-vm/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/node-vm/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..ac128a8696 --- /dev/null +++ b/common/changes/@neo-one/node-vm/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/node-vm", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/node-vm", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/node/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/node/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..b835c7e6fd --- /dev/null +++ b/common/changes/@neo-one/node/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/node", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/node", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/smart-contract-codegen/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/smart-contract-codegen/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..b6bef8c362 --- /dev/null +++ b/common/changes/@neo-one/smart-contract-codegen/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/smart-contract-codegen", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/smart-contract-codegen", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/smart-contract-compiler/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/smart-contract-compiler/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..1c3debc9b0 --- /dev/null +++ b/common/changes/@neo-one/smart-contract-compiler/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/smart-contract-compiler", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/smart-contract-compiler", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/smart-contract-lib/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/smart-contract-lib/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..695b61076b --- /dev/null +++ b/common/changes/@neo-one/smart-contract-lib/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/smart-contract-lib", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/smart-contract-lib", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/smart-contract-test-common/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/smart-contract-test-common/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..021750178b --- /dev/null +++ b/common/changes/@neo-one/smart-contract-test-common/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/smart-contract-test-common", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/smart-contract-test-common", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/smart-contract-test/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/smart-contract-test/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..2cdb6f72af --- /dev/null +++ b/common/changes/@neo-one/smart-contract-test/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/smart-contract-test", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/smart-contract-test", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/smart-contract/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/smart-contract/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..16b354329b --- /dev/null +++ b/common/changes/@neo-one/smart-contract/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/smart-contract", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/smart-contract", + "email": "spencercorwin@icloud.com" +} diff --git a/common/changes/@neo-one/utils/compiler-work-preview4-rebase_2021-02-04-04-40.json b/common/changes/@neo-one/utils/compiler-work-preview4-rebase_2021-02-04-04-40.json new file mode 100644 index 0000000000..28072b1669 --- /dev/null +++ b/common/changes/@neo-one/utils/compiler-work-preview4-rebase_2021-02-04-04-40.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@neo-one/utils", + "comment": "Update compiler, client, and CLI for Preview4", + "type": "patch" + } + ], + "packageName": "@neo-one/utils", + "email": "spencercorwin@icloud.com" +} \ No newline at end of file diff --git a/packages/neo-one-cli/src/cmd/start/network.ts b/packages/neo-one-cli/src/cmd/start/network.ts index cba8c97143..cd7ef213d8 100644 --- a/packages/neo-one-cli/src/cmd/start/network.ts +++ b/packages/neo-one-cli/src/cmd/start/network.ts @@ -26,7 +26,6 @@ export const handler = () => { blockchain: createPriv({ standbyValidators: [common.ecPointToString(publicKey)], extraCommitteeMembers: [], - // privateNet: true, }), node: { consensus: { diff --git a/packages/neo-one-cli/src/compile/writeContract.ts b/packages/neo-one-cli/src/compile/writeContract.ts index 578493f698..14f45b4287 100644 --- a/packages/neo-one-cli/src/compile/writeContract.ts +++ b/packages/neo-one-cli/src/compile/writeContract.ts @@ -32,7 +32,7 @@ export const writeContract = async ( { json: jsonFlag, avm: avmFlag, debug: debugFlag, opcodes: opcodesFlag }: CompileWriteOptions, ) => { await fs.ensureDir(outDir); - const outputPath = path.resolve(outDir, `${contractIn.contract.name}.contract.json`); + const outputPath = path.resolve(outDir, `${contractIn.contract.manifest.name}.contract.json`); const { sourceMap: sourceMapPromise, debugInfo, contract } = contractIn; @@ -40,7 +40,7 @@ export const writeContract = async ( // TODO: get this from compiler? Or change properties expected const metadata: NEOONEContractMetadata = { - name: contract.name, + name: contract.manifest.name, description: 'A NEO•ONE Smart Contract', codeVersion: '1.0', author: 'NEO•ONE', @@ -83,8 +83,8 @@ export const writeContract = async ( const jmpAddress = getJumpLength(disassembled[3].value); // TODO: abstract this index from compiler package. FIRST_JMP_IDX = 3; const endAddress = disassembled[disassembled.length - 1].pc; - const jmpMethod = getJmpMethodDefinition(contract.name); - const dispatcherMethod = getDispatcherMethodDefinition(contract.name, jmpAddress, endAddress); + const jmpMethod = getJmpMethodDefinition(contract.manifest.name); + const dispatcherMethod = getDispatcherMethodDefinition(contract.manifest.name, jmpAddress, endAddress); const getMethodRanges = (consumer: SourceMapConsumer, line: number) => consumer @@ -131,7 +131,7 @@ export const writeContract = async ( return { id: `${index + 2}`, - name: `${contract.name},${name}`, + name: `${contract.manifest.name},${name}`, range: `${range[0]}-${range[1]}`, params, return: returnType, @@ -149,14 +149,14 @@ export const writeContract = async ( methods: [jmpMethod, dispatcherMethod, ...methods], events: manifest.abi.events.map((event, index) => ({ id: `${lastID + index}`, - name: `${contract.name}-${event.name}`, + name: `${contract.manifest.name}-${event.name}`, params: event.parameters.map((param) => `${param.name},${param.type}`), })), }; if (avmFlag) { const zip = new JSZip(); - zip.file<'text'>(`${contract.name}.debug.json`, JSON.stringify(debugJSON, undefined, 2)); + zip.file<'text'>(`${contract.manifest.name}.debug.json`, JSON.stringify(debugJSON, undefined, 2)); await new Promise((resolve) => zip .generateNodeStream({ type: 'nodebuffer', streamFiles: true }) diff --git a/packages/neo-one-cli/src/deploy/runMigration.ts b/packages/neo-one-cli/src/deploy/runMigration.ts index 9b4b90792f..cd105ee0f8 100644 --- a/packages/neo-one-cli/src/deploy/runMigration.ts +++ b/packages/neo-one-cli/src/deploy/runMigration.ts @@ -32,7 +32,7 @@ export const runMigration = async ( print: Print, ) => { const nameToContract: NameToContract = _.fromPairs( - contractResults.map((contract) => [camel(contract.contract.name), contract]), + contractResults.map((contract) => [camel(contract.contract.manifest.name), contract]), ); let contracts: Contracts = _.fromPairs( Object.entries(nameToContract).map(([name, contract]) => [ diff --git a/packages/neo-one-client-common/src/models/types.ts b/packages/neo-one-client-common/src/models/types.ts index fcf3891506..d1def70f4e 100644 --- a/packages/neo-one-client-common/src/models/types.ts +++ b/packages/neo-one-client-common/src/models/types.ts @@ -358,7 +358,6 @@ export interface ContractEventDescriptorJSON { } export interface ContractABIJSON { - readonly hash: string; readonly methods: readonly ContractMethodDescriptorJSON[]; readonly events: readonly ContractEventDescriptorJSON[]; } @@ -379,6 +378,7 @@ export interface ContractPermissionJSON { } export interface ContractManifestJSON { + readonly name: string; readonly abi: ContractABIJSON; readonly groups: readonly ContractGroupJSON[]; readonly permissions: readonly ContractPermissionJSON[]; diff --git a/packages/neo-one-client-common/src/models/vm.ts b/packages/neo-one-client-common/src/models/vm.ts index 124497d988..629c19c128 100644 --- a/packages/neo-one-client-common/src/models/vm.ts +++ b/packages/neo-one-client-common/src/models/vm.ts @@ -291,18 +291,17 @@ export enum SysCallHashNum { 'System.Blockchain.GetTransaction' = 0xe6558d48, 'System.Blockchain.GetTransactionHeight' = 0x4a3288b1, 'System.Blockchain.GetTransactionFromBlock' = 0x7e56fd69, - 'System.Blockchain.GetContract' = 0xa9c54b41, 'System.Callback.Create' = 0xd6a52d2a, 'System.Callback.CreateFromMethod' = 0x7c507485, 'System.Callback.CreateFromSyscall' = 0xd46efa70, 'System.Callback.Invoke' = 0xd42b3dad, - 'System.Contract.Create' = 0xce352c85, - 'System.Contract.Update' = 0x31c6331d, - 'System.Contract.Destroy' = 0xc69f1df0, 'System.Contract.Call' = 0x627d5b52, 'System.Contract.CallEx' = 0xeef40cdb, + 'System.Contract.CallNative' = 0x1af77b67, 'System.Contract.IsStandard' = 0xd76b9d85, 'System.Contract.GetCallFlags' = 0x95da3a81, + 'System.Contract.NativeOnPersist' = 0x2edbbc93, + 'System.Contract.NativePostPersist' = 0x44a15d16, 'System.Contract.CreateStandardAccount' = 0xcf998702, 'Neo.Crypto.RIPEMD160' = 0x26d1d6d2, 'Neo.Crypto.SHA256' = 0xd7ac7411, @@ -321,8 +320,6 @@ export enum SysCallHashNum { 'System.Iterator.Concat' = 0xe5870a81, 'System.Json.Serialize' = 0x248d264b, 'System.Json.Deserialize' = 0xa79c470e, - 'Neo.Native.Deploy' = 0x123e7fe8, - 'Neo.Native.Call' = 0x6b67780b, 'System.Runtime.Platform' = 0xb279fcf6, 'System.Runtime.GetTrigger' = 0xe97d38a0, 'System.Runtime.GetTime' = 0xb7c38803, @@ -344,6 +341,10 @@ export enum SysCallHashNum { 'System.Storage.Put' = 0xe63f1884, 'System.Storage.PutEx' = 0x73e19b3a, 'System.Storage.Delete' = 0x2f58c5ed, + 'System.Binary.Base58Encode' = 0x3f57b067, + 'System.Binary.Base58Decode' = 0x6df79237, + 'System.Binary.Itoa' = 0x7be3ba7d, + 'System.Binary.Atoi' = 0x1c3840eb, } export type SysCallName = keyof typeof SysCall; diff --git a/packages/neo-one-client-common/src/types.ts b/packages/neo-one-client-common/src/types.ts index ea9f11b8a9..a733e7d0d2 100644 --- a/packages/neo-one-client-common/src/types.ts +++ b/packages/neo-one-client-common/src/types.ts @@ -701,6 +701,7 @@ export interface SmartContractNetworksDefinition { * Used to generate the smart contract APIs. */ export interface SmartContractDefinition { + // TODO: may have to put hash here? /** * Configuration for the smart contract by network. */ @@ -767,7 +768,7 @@ export interface TransactionOptions { * * If unspecified, the currently selected `UserAccount` is used as the `from` address. * - * DApp developers will typically want to leave this unspecified. + * dApp developers will typically want to leave this unspecified. */ from?: UserAccountID; /** @@ -1487,23 +1488,23 @@ export interface ContractMethodDescriptorClient { /** * Parameters of the method. */ - readonly parameters?: readonly ABIParameter[]; + readonly parameters?: readonly ABIParameter[]; // TODO: should be be optional or no? /** * Return type of the method. */ - readonly returnType: ABIReturn; + readonly returnType: ABIReturn; // TODO: should this be ContractParameterType? /** * Used to set the instruction pointer before executing the method. */ readonly offset: number; /** - * `true` if the function is constant or read-only. + * `true` if the function is "safe" to be called by any other contract */ - readonly constant?: boolean; + readonly safe: boolean; /** - * `true` if the function is "safe" to be called by any other contract + * `true` if the function is constant or read-only. */ - readonly safe?: boolean; // TODO: this might need to be required + readonly constant?: boolean; /** * `true` if the function is marked for receiving tokens. */ @@ -1544,7 +1545,7 @@ export interface ContractEventDescriptorClient { /** * Parameters of the event. */ - readonly parameters: readonly ABIParameter[]; + readonly parameters: readonly ABIParameter[]; // TODO: should this be ContractParameterDefinition? } /** @@ -1567,10 +1568,6 @@ export interface ContractEventDescriptor { * See the [Smart Contract APIs](https://neo-one.io/docs/smart-contract-apis) chapter of the main guide for more information. */ export interface ContractABIClient { - /** - * Script hash of the contract. - */ - readonly hash: UInt160Hex; /** * Specification of the smart contract methods. */ @@ -1587,10 +1584,6 @@ export interface ContractABIClient { * See the [Smart Contract APIs](https://neo-one.io/docs/smart-contract-apis) chapter of the main guide for more information. */ export interface ContractABI { - /** - * Script hash of the contract. - */ - readonly hash: UInt160Hex; /** * Specification of the smart contract methods. */ @@ -1657,9 +1650,9 @@ export interface ContractPermission { */ export interface ContractManifestClient { /** - * The `Contract`'s hash. + * The name of the contract. */ - readonly hash: UInt160Hex; + readonly name: string; /** * A group represents a set of mutually trusted contracts. A contract will trust and allow any contract in the same group to invoke it, and the user interface will not give any warnings. */ @@ -1693,6 +1686,10 @@ export interface ContractManifestClient { * it will be limited by its declared list of permissions. */ export interface ContractManifest { + /** + * The name of the contract. + */ + readonly name: string; /** * A group represents a set of mutually trusted contracts. A contract will trust and allow any contract in the same group to invoke it, and the user interface will not give any warnings. */ diff --git a/packages/neo-one-client-core/src/args.ts b/packages/neo-one-client-core/src/args.ts index b08297a569..53122ad1bf 100644 --- a/packages/neo-one-client-core/src/args.ts +++ b/packages/neo-one-client-core/src/args.ts @@ -610,6 +610,7 @@ const assertContractMethodDescriptorClient = (name: string, value?: unknown): Co ).map((parameter) => assertABIParameter('ContractMethodDescriptorClient.parameters', parameter)), returnType: assertProperty(value, 'ContractMethodDescriptorClient', 'returnType', assertABIReturn), constant: assertProperty(value, 'ContractMethodDescriptorClient', 'constant', assertNullableBoolean), + safe: assertProperty(value, 'ContractMethodDescriptorClient', 'safe', assertBoolean), offset: assertProperty(value, 'ContractMethodDescriptorClient', 'offset', assertNumber), }; }; @@ -664,7 +665,6 @@ export const assertContractABIClient = (name: string, value?: unknown): Contract } return { - hash: assertProperty(value, 'ContractABI', 'hash', assertUInt160Hex), methods: assertProperty(value, 'ContractABI', 'methods', assertArray).map((method) => assertContractMethodDescriptorClient('ContractABI.methods', method), ), @@ -680,7 +680,6 @@ export const assertContractABI = (name: string, value?: unknown): ContractABI => } return { - hash: assertProperty(value, 'ContractABI', 'hash', assertUInt160Hex), methods: assertProperty(value, 'ContractABI', 'methods', assertArray).map((method) => assertContractMethodDescriptor('ContractABI.methods', method), ), @@ -774,7 +773,7 @@ export const assertContractManifestClient = (name: string, value?: unknown): Con } return { - hash: assertProperty(value, 'ContractManifest', 'hash', assertUInt160Hex), + name: assertProperty(value, 'ContractManifest', 'name', assertString), groups: assertProperty(value, 'ContractManifest', 'groups', assertArray).map((group) => assertContractGroup('ContractManifest.groups', group), ), @@ -796,6 +795,7 @@ export const assertContractManifest = (name: string, value?: unknown): ContractM } return { + name: assertProperty(value, 'ContractManifest', 'name', assertString), groups: assertProperty(value, 'ContractManifest', 'groups', assertArray).map((group) => assertContractGroup('ContractManifest.groups', group), ), @@ -984,8 +984,12 @@ export const assertAttribute = (name: string, attribute?: unknown): Attribute => throw new InvalidArgumentError('Attribute', name, attribute); } + // TODO: check this works for both attributes return { type: assertProperty(attribute, 'Attribute', 'type', assertAttributeTypeArg), + id: assertProperty(attribute, 'Attribute', 'id', assertBigNumber), + code: assertProperty(attribute, 'Attribute', 'code', assertNumber), + result: assertProperty(attribute, 'Attribute', 'result', assertBuffer), }; }; diff --git a/packages/neo-one-client-core/src/nep17.ts b/packages/neo-one-client-core/src/nep17.ts index e6c0999dcf..f1a955b029 100644 --- a/packages/neo-one-client-core/src/nep17.ts +++ b/packages/neo-one-client-core/src/nep17.ts @@ -1,15 +1,12 @@ import { ABIParameter, AddressString, - common, ContractABIClient, ContractManifestClient, ContractMethodDescriptorClient, - crypto, Event, InvokeReceipt, NetworkType, - ScriptBuilder, SmartContractNetworksDefinition, SmartContractReadOptions, TransactionOptions, @@ -56,12 +53,7 @@ const decimalsFunction: ContractMethodDescriptorClient = { safe: true, }; -// TODO: check that the script/hash can/should be blank here. also check offsets -const blankScript = new ScriptBuilder().build(); -const blankHash = crypto.toScriptHash(blankScript); - export const abi = (decimals: number): ContractABIClient => ({ - hash: common.uInt160ToString(blankHash), methods: [ { name: 'name', @@ -147,9 +139,8 @@ export const abi = (decimals: number): ContractABIClient => ({ ], }); -// TODO: check that the script/hash can/should be blank here export const manifest = (decimals: number): ContractManifestClient => ({ - hash: common.uInt160ToString(blankHash), + name: '', groups: [], supportedStandards: [], abi: abi(decimals), @@ -167,7 +158,7 @@ export const getDecimals = async ( networks: networksDefinition, manifest: { ...manifest(0), - abi: { hash: manifest(0).hash, events: [], methods: [decimalsFunction] }, + abi: { events: [], methods: [decimalsFunction] }, }, }) .decimals({ network }); diff --git a/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts b/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts index 7f966781d0..57d2ec2024 100644 --- a/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts +++ b/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts @@ -397,6 +397,7 @@ export class NEOONEDataProvider implements DeveloperProvider { private convertContractManifest(manifest: ContractManifestJSON): ContractManifest { return { + name: manifest.name, groups: manifest.groups.map(this.convertContractGroup), supportedStandards: manifest.supportedstandards, abi: this.convertContractABI(manifest.abi), @@ -422,7 +423,6 @@ export class NEOONEDataProvider implements DeveloperProvider { private convertContractABI(abi: ContractABIJSON): ContractABI { return { - hash: abi.hash, methods: abi.methods.map(this.convertContractMethodDescriptor.bind(this)), events: abi.events.map(this.convertContractEventDescriptor.bind(this)), }; diff --git a/packages/neo-one-client-full-common/src/models/manifest/ContractABIModel.ts b/packages/neo-one-client-full-common/src/models/manifest/ContractABIModel.ts index 2bf5dfe20a..ca645bcccc 100644 --- a/packages/neo-one-client-full-common/src/models/manifest/ContractABIModel.ts +++ b/packages/neo-one-client-full-common/src/models/manifest/ContractABIModel.ts @@ -1,4 +1,4 @@ -import { ContractABIJSON, JSONHelper, SerializableJSON, UInt160 } from '@neo-one/client-common'; +import { ContractABIJSON, SerializableJSON } from '@neo-one/client-common'; import { ContractEventDescriptorModel } from './ContractEventDescriptorModel'; import { ContractMethodDescriptorModel } from './ContractMethodDescriptorModel'; @@ -6,7 +6,6 @@ export interface ContractABIModelAdd< TContractMethod extends ContractMethodDescriptorModel = ContractMethodDescriptorModel, TContractEvent extends ContractEventDescriptorModel = ContractEventDescriptorModel > { - readonly hash: UInt160; readonly methods: readonly TContractMethod[]; readonly events: readonly TContractEvent[]; } @@ -15,19 +14,16 @@ export class ContractABIModel< TContractMethod extends ContractMethodDescriptorModel = ContractMethodDescriptorModel, TContractEvent extends ContractEventDescriptorModel = ContractEventDescriptorModel > implements SerializableJSON { - public readonly hash: UInt160; public readonly methods: readonly TContractMethod[]; public readonly events: readonly TContractEvent[]; - public constructor({ hash, methods, events }: ContractABIModelAdd) { - this.hash = hash; + public constructor({ methods, events }: ContractABIModelAdd) { this.methods = methods; this.events = events; } public serializeJSON(): ContractABIJSON { return { - hash: JSONHelper.writeUInt160(this.hash), methods: this.methods.map((method) => method.serializeJSON()), events: this.events.map((event) => event.serializeJSON()), }; diff --git a/packages/neo-one-client-full-common/src/models/manifest/ContractManifestModel.ts b/packages/neo-one-client-full-common/src/models/manifest/ContractManifestModel.ts index a02225f1a5..1de4a70bfd 100644 --- a/packages/neo-one-client-full-common/src/models/manifest/ContractManifestModel.ts +++ b/packages/neo-one-client-full-common/src/models/manifest/ContractManifestModel.ts @@ -8,8 +8,6 @@ import { SerializableWire, SerializeWire, UInt160, - UInt160Hex, - utils, WildcardContainer, } from '@neo-one/client-common'; import { JSONObject } from '@neo-one/utils'; @@ -22,6 +20,7 @@ export interface ContractManifestModelAdd< TContractGroup extends ContractGroupModel = ContractGroupModel, TContractPermission extends ContractPermissionModel = ContractPermissionModel > { + readonly name: string; readonly groups: readonly TContractGroup[]; readonly supportedStandards: readonly string[]; readonly abi: TContractABI; @@ -36,6 +35,7 @@ export class ContractManifestModel< TContractPermission extends ContractPermissionModel = ContractPermissionModel > implements SerializableWire, SerializableJSON { public static readonly maxLength = common.MAX_MANIFEST_LENGTH; + public readonly name: string; public readonly groups: readonly TContractGroup[]; public readonly supportedStandards: readonly string[]; public readonly abi: TContractABI; @@ -43,10 +43,11 @@ export class ContractManifestModel< public readonly trusts: WildcardContainer; public readonly extra: JSONObject | undefined; public readonly serializeWire: SerializeWire = createSerializeWire(this.serializeWireBase.bind(this)); - private readonly hashInternal = utils.lazy(() => this.abi.hash); - private readonly hashHexInternal = utils.lazy(() => common.uInt160ToHex(this.hash)); + // TODO: fix this + public readonly serializeWireForNeo: SerializeWire = createSerializeWire(this.serializeWireBaseForNeo.bind(this)); public constructor({ + name, groups, supportedStandards, abi, @@ -54,6 +55,7 @@ export class ContractManifestModel< trusts, extra, }: ContractManifestModelAdd) { + this.name = name; this.groups = groups; this.supportedStandards = supportedStandards; this.abi = abi; @@ -62,16 +64,9 @@ export class ContractManifestModel< this.extra = extra; } - public get hash(): UInt160 { - return this.hashInternal(); - } - - public get hashHex(): UInt160Hex { - return this.hashHexInternal(); - } - public serializeJSON(): ContractManifestJSON { return { + name: this.name, groups: this.groups.map((group) => group.serializeJSON()), supportedstandards: this.supportedStandards, abi: this.abi.serializeJSON(), @@ -82,6 +77,10 @@ export class ContractManifestModel< } public serializeWireBase(writer: BinaryWriter): void { + writer.writeVarString(JSON.stringify(this.serializeJSON())); + } + + public serializeWireBaseForNeo(writer: BinaryWriter): void { // TODO: fix this. or bring up with Neo team writer.writeVarStringWithoutVar(JSON.stringify(this.serializeJSON())); } diff --git a/packages/neo-one-client-full-core/src/args.ts b/packages/neo-one-client-full-core/src/args.ts index 0946a4ddc5..08899a4e96 100644 --- a/packages/neo-one-client-full-core/src/args.ts +++ b/packages/neo-one-client-full-core/src/args.ts @@ -77,6 +77,7 @@ export const assertContractRegister = (name: string, register?: unknown): Contra return { script: args.assertProperty(register, 'ContractRegister', 'script', args.assertBuffer), manifest: args.assertProperty(register, 'ContractRegister', 'manifest', args.assertContractManifestClient), - name: args.assertProperty(register, 'ContractRegister', 'name', args.assertString), + compilerName: args.assertProperty(register, 'ContractRegister', 'compilerName', args.assertString), + compilerVersion: args.assertProperty(register, 'ContractRegister', 'compilerVersion', args.assertString), }; }; diff --git a/packages/neo-one-client-full-core/src/types.ts b/packages/neo-one-client-full-core/src/types.ts index 0a0a2e0c41..afa7bc6503 100644 --- a/packages/neo-one-client-full-core/src/types.ts +++ b/packages/neo-one-client-full-core/src/types.ts @@ -24,7 +24,8 @@ import { export interface ContractRegister { readonly script: BufferString; readonly manifest: ContractManifestClient; - readonly name: string; + readonly compilerName: string; + readonly compilerVersion: string; } export interface PublishReceipt extends TransactionReceipt { diff --git a/packages/neo-one-client-full-core/src/user/LocalUserAccountProvider.ts b/packages/neo-one-client-full-core/src/user/LocalUserAccountProvider.ts index 4a1141261c..19b4ebf246 100644 --- a/packages/neo-one-client-full-core/src/user/LocalUserAccountProvider.ts +++ b/packages/neo-one-client-full-core/src/user/LocalUserAccountProvider.ts @@ -1,6 +1,7 @@ import { ABIParameter, ABIReturn, + BinaryWriter, BufferString, common, ContractManifestClient, @@ -17,12 +18,15 @@ import { RawInvokeReceipt, ScriptBuilder, scriptHashToAddress, + SignerModel, SourceMaps, TransactionOptions, TransactionResult, UInt160, UserAccountID, + utils as clientUtils, Wildcard, + WitnessScopeModel, } from '@neo-one/client-common'; import { convertParams, @@ -89,9 +93,11 @@ const toContractParameterType = (parameter: ABIReturn | ABIParameter): ContractP } }; -export const contractRegisterToContractModel = (contractIn: ContractRegister): ContractStateModel => { +export const contractRegisterToContractModel = ( + contractIn: ContractRegister, + contractHash: UInt160, +): ContractStateModel => { const abi = new ContractABIModel({ - hash: common.stringToUInt160(contractIn.manifest.abi.hash), methods: contractIn.manifest.abi.methods.map( (methodIn) => new ContractMethodDescriptorModel({ @@ -145,6 +151,7 @@ export const contractRegisterToContractModel = (contractIn: ContractRegister): C return '*'; }; const manifest = new ContractManifestModel({ + name: contractIn.manifest.name, groups: contractIn.manifest.groups.map( (group) => new ContractGroupModel({ @@ -166,10 +173,10 @@ export const contractRegisterToContractModel = (contractIn: ContractRegister): C }); return new ContractStateModel({ - hash: '', - updateCounter: 1, + hash: contractHash, + updateCounter: 1, // TODO: what should this be? script: Buffer.from(contractIn.script, 'hex'), - id: Math.floor(Math.random() * 1000000), // TODO: fix + id: clientUtils.randomUShort(), manifest, }); }; @@ -273,10 +280,35 @@ export class LocalUserAccountProvider> { - const contract = contractRegisterToContractModel(contractIn); + const address = this.getCurrentUserAccount()?.id.address; + if (address === undefined) { + throw new Error('Expected address to be defined'); + } + // TODO: clean up this mess and clean up this transaction flow + const signer = new SignerModel({ + account: crypto.addressToScriptHash({ address, addressVersion: common.NEO_ADDRESS_VERSION }), + scopes: WitnessScopeModel.Global, + }); + + const contractHashUInt160 = crypto.getContractHash(signer.account, Buffer.from(contractIn.script, 'hex')); + const contractHash = common.uInt160ToString(contractHashUInt160); + const contract = contractRegisterToContractModel(contractIn, contractHashUInt160); + + const writer = new BinaryWriter(); + writer.writeUInt32LE(0x3346454e); // TODO: abstract this number + writer.writeFixedString(contractIn.compilerName, 32); + writer.writeFixedString(contractIn.compilerVersion, 32); + writer.writeVarBytesLE(Buffer.from(contractIn.script, 'hex')); + writer.writeBytes(crypto.sha256(crypto.sha256(writer.toBuffer())).slice(0, 4)); const sb = new ScriptBuilder(); - sb.emitSysCall('System.Contract.Create', contract.script, contract.manifest.serializeWire()); + sb.emitPush(contract.manifest.serializeWireForNeo()); // TODO: remove this later + sb.emitPush(writer.toBuffer()); + sb.emitPushInt(2); + sb.emitOp('PACK'); + sb.emitPushString('deploy'); + sb.emitPush(common.nativeHashes.Management); + sb.emitSysCall('System.Contract.Call'); const { from } = this.getTransactionOptions(options); emit(sb, from); @@ -293,10 +325,8 @@ export class LocalUserAccountProvider { private readonly sizeInternal = utils.lazy( () => IOHelper.sizeOfUInt32LE + - +IOHelper.sizeOfUInt16LE + + IOHelper.sizeOfUInt16LE + IOHelper.sizeOfUInt160 + IOHelper.sizeOfVarBytesLE(this.script) + this.manifest.size, diff --git a/packages/neo-one-node-core/src/Storage.ts b/packages/neo-one-node-core/src/Storage.ts index 8f8c1c5cb8..66d44baae0 100644 --- a/packages/neo-one-node-core/src/Storage.ts +++ b/packages/neo-one-node-core/src/Storage.ts @@ -103,19 +103,19 @@ export interface LatestReadStorage extends ReadStorage { export type AddChange = | { readonly type: 'block'; readonly key: BlockKey; readonly value: TrimmedBlock } | { readonly type: 'transaction'; readonly key: TransactionKey; readonly value: TransactionState } - | { readonly type: 'contract'; readonly key: ContractKey; readonly value: ContractState } + // | { readonly type: 'contract'; readonly key: ContractKey; readonly value: ContractState } | { readonly type: 'storage'; readonly key: StorageKey; readonly value: StorageItem } | { readonly type: 'headerHashList'; readonly key: HeaderKey; readonly value: HeaderHashList } | { readonly type: 'blockHashIndex'; readonly value: HashIndexState } | { readonly type: 'headerHashIndex'; readonly value: HashIndexState } - | { readonly type: 'contractID'; readonly value: ContractIDState } + // | { readonly type: 'contractID'; readonly value: ContractIDState } | { readonly type: 'nep17Balance'; readonly key: Nep17BalanceKey; readonly value: Nep17Balance } | { readonly type: 'nep17TransferSent'; readonly key: Nep17TransferKey; readonly value: Nep17Transfer } | { readonly type: 'nep17TransferReceived'; readonly key: Nep17TransferKey; readonly value: Nep17Transfer } | { readonly type: 'applicationLog'; readonly key: TransactionKey; readonly value: ApplicationLog }; export type DeleteChange = - | { readonly type: 'contract'; readonly key: ContractKey } + // | { readonly type: 'contract'; readonly key: ContractKey } | { readonly type: 'storage'; readonly key: StorageKey } | { readonly type: 'nep17Balance'; readonly key: Nep17BalanceKey }; diff --git a/packages/neo-one-node-core/src/TransactionVerificationContext.ts b/packages/neo-one-node-core/src/TransactionVerificationContext.ts index f68df32aa1..6789d86858 100644 --- a/packages/neo-one-node-core/src/TransactionVerificationContext.ts +++ b/packages/neo-one-node-core/src/TransactionVerificationContext.ts @@ -6,7 +6,7 @@ import { isOracleResponse, Transaction } from './transaction'; const assertSender = (sender: UInt160 | undefined) => { if (sender === undefined) { // TODO: implement error - throw new Error(`Sender must be defined`); + throw new Error('Sender must be defined'); } return sender; @@ -62,7 +62,7 @@ export class TransactionVerificationContext { const maybeFee = this.mutableSenderFee[key]; if (maybeFee === undefined) { // TODO: implement error - throw new Error('transaction not present in verification context to remove'); + throw new Error('Transaction not present in verification context to remove'); } const newFee = maybeFee.sub(tx.systemFee).sub(tx.networkFee); diff --git a/packages/neo-one-node-core/src/manifest/ContractABI.ts b/packages/neo-one-node-core/src/manifest/ContractABI.ts index 1f72a2b304..9c44a7946f 100644 --- a/packages/neo-one-node-core/src/manifest/ContractABI.ts +++ b/packages/neo-one-node-core/src/manifest/ContractABI.ts @@ -1,4 +1,4 @@ -import { ContractABIJSON, JSONHelper, utils } from '@neo-one/client-common'; +import { ContractABIJSON, utils } from '@neo-one/client-common'; import { ContractABIModel } from '@neo-one/client-full-common'; import _ from 'lodash'; import { ContractEventDescriptor } from './ContractEventDescriptor'; @@ -6,12 +6,10 @@ import { ContractMethodDescriptor } from './ContractMethodDescriptor'; export class ContractABI extends ContractABIModel { public static deserializeJSON(json: ContractABIJSON): ContractABI { - const hash = JSONHelper.readUInt160(json.hash); const methods = json.methods.map((method) => ContractMethodDescriptor.deserializeJSON(method)); const events = json.events.map((event) => ContractEventDescriptor.deserializeJSON(event)); return new this({ - hash, methods, events, }); diff --git a/packages/neo-one-node-core/src/manifest/ContractManifest.ts b/packages/neo-one-node-core/src/manifest/ContractManifest.ts index ce9b413e00..98b4f2e696 100644 --- a/packages/neo-one-node-core/src/manifest/ContractManifest.ts +++ b/packages/neo-one-node-core/src/manifest/ContractManifest.ts @@ -9,10 +9,18 @@ export class ContractManifest extends ContractManifestModel ContractGroup.deserializeJSON(group)); const supportedStandards = json.supportedstandards; const abi = ContractABI.deserializeJSON(json.abi); @@ -21,6 +29,7 @@ export class ContractManifest extends ContractManifestModel { const storage = await storages.tryGet( - this.createStorageKey(this.basePrefixes.totalSupply).addBuffer(account).toStorageKey(), + this.createStorageKey(this.basePrefixes.account).addBuffer(account).toStorageKey(), ); if (storage === undefined) { return new BN(0); diff --git a/packages/neo-one-node-protocol/src/Node.ts b/packages/neo-one-node-protocol/src/Node.ts index 326ecab1e8..5b306828fa 100644 --- a/packages/neo-one-node-protocol/src/Node.ts +++ b/packages/neo-one-node-protocol/src/Node.ts @@ -277,7 +277,7 @@ export class Node implements INode { const { externalPort = 0 } = options; this.externalPort = externalPort; this.nonce = Math.floor(Math.random() * utils.UINT_MAX_NUMBER); - this.userAgent = `NEO:neo-one-js:3.0.0-preview3`; + this.userAgent = `NEO:neo-one-js:3.0.0-preview4`; this.mutableMemPool = {}; this.getNewVerificationContext = () => diff --git a/packages/neo-one-node-rpc-handler/src/createHandler.ts b/packages/neo-one-node-rpc-handler/src/createHandler.ts index 8f302bb072..610e94b00d 100644 --- a/packages/neo-one-node-rpc-handler/src/createHandler.ts +++ b/packages/neo-one-node-rpc-handler/src/createHandler.ts @@ -785,6 +785,7 @@ export const createHandler = ({ verifyResult: resultJSON, }; } catch (error) { + console.log(error); throw new JSONRPCError(-110, `Relay transaction failed: ${error.message}`); } }, diff --git a/packages/neo-one-node-storage-levelup/src/__tests__/rocksDBStorage.test.ts b/packages/neo-one-node-storage-levelup/src/__tests__/rocksDBStorage.test.ts index 5bccba3b13..e01e967ca9 100644 --- a/packages/neo-one-node-storage-levelup/src/__tests__/rocksDBStorage.test.ts +++ b/packages/neo-one-node-storage-levelup/src/__tests__/rocksDBStorage.test.ts @@ -7,7 +7,7 @@ import { storage as levelUpStorage } from '../'; describe('levelUpStorage', () => { let storage: Storage; beforeEach(async () => { - const rocks = new RocksDB('/Users/danielbyrne/Desktop/test-location'); + const rocks = new RocksDB('/Users/spencercorwin/Desktop/test-location'); storage = levelUpStorage({ db: LevelUp(rocks), context: { messageMagic: 1953787457, validatorsCount: 7 } }); }); test('deleted items are undefined', async () => { diff --git a/packages/neo-one-node-storage-levelup/src/convertChange.ts b/packages/neo-one-node-storage-levelup/src/convertChange.ts index affc29c401..1bdc10d476 100644 --- a/packages/neo-one-node-storage-levelup/src/convertChange.ts +++ b/packages/neo-one-node-storage-levelup/src/convertChange.ts @@ -66,14 +66,14 @@ const convertAddChange = (change: AddChange): readonly PutBatch[] => { }, ]; - case 'contract': - return [ - { - type: 'put', - key: keys.createContractKey(change.key), - value: change.value.serializeWire(), - }, - ]; + // case 'contract': + // return [ + // { + // type: 'put', + // key: keys.createContractKey(change.key), + // value: change.value._serializeWire(), + // }, + // ]; case 'storage': return [ @@ -111,14 +111,14 @@ const convertAddChange = (change: AddChange): readonly PutBatch[] => { }, ]; - case 'contractID': - return [ - { - type: 'put', - key: keys.contractIDKey, - value: change.value.serializeWire(), - }, - ]; + // case 'contractID': + // return [ + // { + // type: 'put', + // key: keys.contractIDKey, + // value: change.value.serializeWire(), + // }, + // ]; default: utils.assertNever(change); @@ -128,11 +128,11 @@ const convertAddChange = (change: AddChange): readonly PutBatch[] => { const convertDeleteChange = (change: DeleteChange): DelBatch => { switch (change.type) { - case 'contract': - return { - type: 'del', - key: keys.createContractKey(change.key), - }; + // case 'contract': + // return { + // type: 'del', + // key: keys.createContractKey(change.key), + // }; case 'storage': return { diff --git a/packages/neo-one-node-storage-levelup/src/levelUpStorage.ts b/packages/neo-one-node-storage-levelup/src/levelUpStorage.ts index 3ad334f426..4f9275cc39 100644 --- a/packages/neo-one-node-storage-levelup/src/levelUpStorage.ts +++ b/packages/neo-one-node-storage-levelup/src/levelUpStorage.ts @@ -2,8 +2,7 @@ import { ApplicationLog, BinaryReader, BlockKey, - ContractIDState, - ContractState, + // ContractIDState, DeserializeWireContext, // InvocationData, HashIndexState, @@ -139,16 +138,6 @@ export const levelUpStorage = ({ db, context }: LevelUpStorageOptions): Storage }), }), - contracts: read.createReadStorage({ - db, - serializeKey: keys.createContractKey, - deserializeValue: (buffer) => - ContractState.deserializeWire({ - context, - buffer, - }), - }), - storages: read.createReadFindStorage({ db, getSearchRange: keys.getStorageSearchRange, @@ -187,11 +176,11 @@ export const levelUpStorage = ({ db, context }: LevelUpStorageOptions): Storage deserializeValue: (buffer) => HashIndexState.deserializeWire({ context, buffer }), }), - contractID: read.createReadMetadataStorage({ - db, - key: keys.headerHashIndexKey, - deserializeValue: (buffer) => ContractIDState.deserializeWire({ context, buffer }), - }), + // contractID: read.createReadMetadataStorage({ + // db, + // key: keys.headerHashIndexKey, + // deserializeValue: (buffer) => ContractIDState.deserializeWire({ context, buffer }), + // }), // consensusState: read.createReadMetadataStorage({ // db, diff --git a/packages/neo-one-node-vm/lib/Dispatcher.csproj b/packages/neo-one-node-vm/lib/Dispatcher.csproj index 04a1502e7b..7bcfc8d2dd 100644 --- a/packages/neo-one-node-vm/lib/Dispatcher.csproj +++ b/packages/neo-one-node-vm/lib/Dispatcher.csproj @@ -14,8 +14,8 @@ - - + + diff --git a/packages/neo-one-node-vm/src/__tests__/storage.test.ts b/packages/neo-one-node-vm/src/__tests__/storage.test.ts index abba6462c1..b73d717aab 100644 --- a/packages/neo-one-node-vm/src/__tests__/storage.test.ts +++ b/packages/neo-one-node-vm/src/__tests__/storage.test.ts @@ -1,4 +1,4 @@ -import { common, ScriptBuilder, TriggerType, UInt256, WitnessScopeModel, VMState } from '@neo-one/client-common'; +import { common, ScriptBuilder, TriggerType, UInt256, VMState, WitnessScopeModel } from '@neo-one/client-common'; import { assertArrayStackItem, Block, ConsensusData, Signer, Transaction, Witness } from '@neo-one/node-core'; import { BN } from 'bn.js'; import { Dispatcher } from '../Dispatcher'; diff --git a/packages/neo-one-node/src/__tests__/blockchain.test.ts b/packages/neo-one-node/src/__tests__/blockchain.test.ts index 6e2f995042..ddde2d43f6 100644 --- a/packages/neo-one-node/src/__tests__/blockchain.test.ts +++ b/packages/neo-one-node/src/__tests__/blockchain.test.ts @@ -12,7 +12,7 @@ import { getData } from '../__data__'; describe('Blockchain invocation / storage tests', () => { test('Can persist the first 3 blocks with disk storage', async () => { const blockchainSettings = createTest(); - const levelDBPath = '/Users/danielbyrne/Desktop/node-data'; + const levelDBPath = '/Users/spencercorwin/Desktop/node-data'; const db = LevelUp(RocksDB(levelDBPath)); const blockData = getData(blockchainSettings.messageMagic); diff --git a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/startNode.ts b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/startNode.ts index 79e5eb0fd2..48566a0983 100644 --- a/packages/neo-one-smart-contract-compiler/src/__data__/helpers/startNode.ts +++ b/packages/neo-one-smart-contract-compiler/src/__data__/helpers/startNode.ts @@ -115,11 +115,7 @@ const publish = async ( ): Promise => { throwOnDiagnosticErrorOrWarning(context.diagnostics, ignoreWarnings); - const result = await client.publish({ - script: contract.script, - manifest: contract.manifest, - name: contract.name, - }); + const result = await client.publish(contract); const [publishReceipt] = await Promise.all([ result.confirmed({ timeoutMS: 2500 }), @@ -166,7 +162,7 @@ export const startNode = async (outerOptions: StartNodeOptions = {}): Promise { test('Call with script', async () => { const node = await helpers.startNode(); @@ -27,7 +28,7 @@ describe('Calling contract', () => { `); const result = await node.client.__call('priv', contract.address, 'run', ['run', []]); - // console.log(result); + console.log(result); expect(result.state).toEqual('HALT'); @@ -38,7 +39,7 @@ describe('Calling contract', () => { maxNetworkFee: new BigNumber(-1), }); const final = await resultAgain.confirmed(); - // console.log(final); + console.log(final); expect(final.state).toEqual('HALT'); }); diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/ValueForWithScript.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/ValueForWithScript.ts new file mode 100644 index 0000000000..c35973b7f8 --- /dev/null +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/ValueForWithScript.ts @@ -0,0 +1,42 @@ +import { tsUtils } from '@neo-one/ts-utils'; +import ts from 'typescript'; +import { ScriptBuilder } from '../../sb'; +import { VisitOptions } from '../../types'; +import { BuiltinMemberCall } from '../BuiltinMemberCall'; +import { MemberLikeExpression } from '../types'; + +// tslint:disable-next-line export-name +export class ValueForWithScript extends BuiltinMemberCall { + public constructor( + private readonly script: (sb: ScriptBuilder, node: ts.Node, options: VisitOptions) => void, + private readonly wrap: (sb: ScriptBuilder, node: ts.Node, options: VisitOptions) => void, + ) { + super(); + } + public emitCall( + sb: ScriptBuilder, + _func: MemberLikeExpression, + node: ts.CallExpression, + optionsIn: VisitOptions, + ): void { + if (tsUtils.argumented.getArguments(node).length < 1) { + /* istanbul ignore next */ + return; + } + + const options = sb.pushValueOptions(optionsIn); + // [bufferVal] + sb.visit(tsUtils.argumented.getArguments(node)[0], options); + if (optionsIn.pushValue) { + // [buffer] + sb.emitHelper(node, options, sb.helpers.unwrapBuffer); + // [contract] + this.script(sb, node, options); + // [val] + this.wrap(sb, node, options); + } else { + // [] + sb.emitOp(node, 'DROP'); + } + } +} diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/blockchain.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/blockchain.ts index eddb6cf36f..5967b92c10 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/blockchain.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/blockchain.ts @@ -1,3 +1,4 @@ +import { common } from '@neo-one/client-common'; import { GlobalProperty, Types } from '../../constants'; import { ScriptBuilder } from '../../sb'; import { VisitOptions } from '../../types'; @@ -20,8 +21,16 @@ class BlockchainCurrentCallerContract extends BuiltinMemberValue { sb.emitHelper(node, options, sb.helpers.getGlobalProperty({ property: GlobalProperty.CallingScriptHash })); // [buffer, buffer] sb.emitOp(node, 'DUP'); - // [contract, buffer] - sb.emitSysCall(node, 'System.Blockchain.GetContract'); + // [1, buffer, buffer] + sb.emitPushInt(node, 1); + // [[buffer], buffer] + sb.emitOp(node, 'PACK'); + // ['getContract', [buffer], buffer] + sb.emitPushString(node, 'getContract'); + // [buffer, 'getContract', [buffer], buffer] + sb.emitPushBuffer(node, common.nativeHashes.Management); + // [conract, buffer] + sb.emitSysCall(node, 'System.Contract.Call'); sb.emitHelper( node, options, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/contract.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/contract.ts index 3446bf2127..b09fc3d5a8 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/contract.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/contract.ts @@ -1,8 +1,9 @@ +import { common } from '@neo-one/client-common'; import { Types } from '../../constants'; import { BuiltinInterface } from '../BuiltinInterface'; import { Builtins } from '../Builtins'; import { BuiltinInstanceIndexValue } from './BuiltinInstanceIndexValue'; -import { ValueFor } from './ValueFor'; +import { ValueForWithScript } from './ValueForWithScript'; import { ValueInstanceOf } from './ValueInstanceOf'; class ContractInterface extends BuiltinInterface {} @@ -20,28 +21,43 @@ export const add = (builtins: Builtins): void => { builtins.addContractMember( 'ContractConstructor', 'for', - new ValueFor('System.Blockchain.GetContract', (sb, node, options) => { - sb.emitHelper( - node, - options, - sb.helpers.if({ - condition: () => { - // [buffer, buffer] - sb.emitOp(node, 'DUP'); - // [buffer, buffer, buffer] - sb.emitPushBuffer(node, Buffer.from([])); - // [boolean, buffer] - sb.emitOp(node, 'EQUAL'); - }, - whenTrue: () => { - sb.emitOp(node, 'DROP'); - sb.emitHelper(node, options, sb.helpers.wrapUndefined); - }, - whenFalse: () => { - sb.emitHelper(node, options, sb.helpers.wrapContract); - }, - }), - ); - }), + // TODO: this can be better/cleaner. also needs to be tested + new ValueForWithScript( + (sb, node, _options) => { + // [1, buffer] + sb.emitPushInt(node, 1); + // [[buffer]] + sb.emitOp(node, 'PACK'); + // ['getContract', [buffer]] + sb.emitPushString(node, 'getContract'); + // [buffer, 'getContract', [buffer]] + sb.emitPushBuffer(node, common.nativeHashes.Management); + // [conract] + sb.emitSysCall(node, 'System.Contract.Call'); + }, + (sb, node, options) => { + sb.emitHelper( + node, + options, + sb.helpers.if({ + condition: () => { + // [buffer, buffer] + sb.emitOp(node, 'DUP'); + // [buffer, buffer, buffer] + sb.emitPushBuffer(node, Buffer.from([])); + // [boolean, buffer] + sb.emitOp(node, 'EQUAL'); + }, + whenTrue: () => { + sb.emitOp(node, 'DROP'); + sb.emitHelper(node, options, sb.helpers.wrapUndefined); + }, + whenFalse: () => { + sb.emitHelper(node, options, sb.helpers.wrapContract); + }, + }), + ); + }, + ), ); }; diff --git a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/destroy.ts b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/destroy.ts index 5996540fc2..62977a782a 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/destroy.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/builtins/contract/smartContract/destroy.ts @@ -1,3 +1,4 @@ +import { common } from '@neo-one/client-common'; import { tsUtils } from '@neo-one/ts-utils'; import ts from 'typescript'; import { ScriptBuilder } from '../../../sb'; @@ -23,7 +24,16 @@ export class SmartContractDestroy extends BuiltinInstanceMemberCall { sb.emitOp(node, 'DROP'); } - sb.emitSysCall(node, 'System.Contract.Destroy'); + // [1, buffer] + sb.emitPushInt(node, 1); + // [[buffer]] + sb.emitOp(node, 'PACK'); + // ['destroy', [buffer], buffer] + sb.emitPushString(node, 'destroy'); + // [buffer, 'destroy', [buffer]] + sb.emitPushBuffer(node, common.nativeHashes.Management); + // [conract] + sb.emitSysCall(node, 'System.Contract.Call'); if (optionsIn.pushValue) { // [val] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/compile.ts b/packages/neo-one-smart-contract-compiler/src/compile/compile.ts index 5d8eb73bd4..fbfd515928 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/compile.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/compile.ts @@ -1,4 +1,3 @@ -import { common, crypto } from '@neo-one/client-common'; import { tsUtils } from '@neo-one/ts-utils'; import { RawSourceMap } from 'source-map'; import ts from 'typescript'; @@ -75,7 +74,6 @@ export const compile = async ({ const finalResult = emittingScriptBuilder.getFinalResult(sourceMaps); const script = finalResult.code.toString('hex'); - const hash = common.uInt160ToString(crypto.toScriptHash(Buffer.from(script, 'hex'))); const methods = await processMethods({ context, @@ -87,21 +85,17 @@ export const compile = async ({ return { contract: { - name, script, manifest: { - hash, + name, ...manifest, - features: { - ...manifest.features, - ...finalResult.features, - }, abi: { - hash, ...manifest.abi, methods, }, }, + compilerName: 'neo-one', + compilerVersion: '3.1.0-preview4', }, context, debugInfo, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/getSmartContractInfo.ts b/packages/neo-one-smart-contract-compiler/src/compile/getSmartContractInfo.ts index 35b1cb7eb2..8b1acea8d7 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/getSmartContractInfo.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/getSmartContractInfo.ts @@ -131,17 +131,10 @@ export interface SmartContractInfoABI { export interface SmartContractInfoManifest { readonly groups: readonly ContractGroup[]; - readonly features: { - readonly storage: boolean; - readonly payable: boolean; - }; readonly supportedStandards: readonly string[]; readonly abi: SmartContractInfoABI; readonly permissions: readonly ContractPermission[]; readonly trusts: WildcardContainer; - readonly safeMethods: WildcardContainer; - readonly hasStorage: boolean; - readonly payable: boolean; } export interface SmartContractInfo { @@ -151,6 +144,7 @@ export interface SmartContractInfo { readonly manifest: SmartContractInfoManifest; } +// TODO: should name be in SmartContractInfoManifest? export const getSmartContractInfo = (context: Context, sourceFile: ts.SourceFile): SmartContractInfo => { const smartContract = getSmartContract(context, sourceFile); const contractInfo = smartContract === undefined ? undefined : getContractInfo(context, smartContract); @@ -172,10 +166,6 @@ export const getSmartContractInfo = (context: Context, sourceFile: ts.SourceFile contractInfo, manifest: { groups: [], - features: { - storage: true, - payable: true, - }, supportedStandards: [], abi: { methods: [], @@ -183,9 +173,6 @@ export const getSmartContractInfo = (context: Context, sourceFile: ts.SourceFile }, permissions: [], trusts: '*', - safeMethods: '*', - hasStorage: true, - payable: true, }, debugInfo: { entrypoint: '', diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/IsCallerHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/IsCallerHelper.ts index ccad88988a..2151aa8118 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/IsCallerHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/IsCallerHelper.ts @@ -1,3 +1,4 @@ +import { common } from '@neo-one/client-common'; import ts from 'typescript'; import { GlobalProperty } from '../../constants'; import { ScriptBuilder } from '../../sb'; @@ -32,8 +33,16 @@ export class IsCallerHelper extends Helper { whenFalse: () => { // [addressBuffer, addressBuffer] sb.emitOp(node, 'DUP'); + // [1, addressBuffer, addressBuffer] + sb.emitPushInt(node, 1); + // [[addressBuffer], addressBuffer] + sb.emitOp(node, 'PACK'); + // ['getContract', [addressBuffer], addressBuffer] + sb.emitPushString(node, 'getContract'); + // [buffer, 'getContract', [addressBuffer], addressBuffer] + sb.emitPushBuffer(node, common.nativeHashes.Management); // [maybeContract, addressBuffer] - sb.emitSysCall(node, 'System.Blockchain.GetContract'); + sb.emitSysCall(node, 'System.Contract.Call'); sb.emitHelper( node, options, diff --git a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/UpgradeHelper.ts b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/UpgradeHelper.ts index 9fe0aa8803..34f68f8210 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/UpgradeHelper.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/helper/contract/UpgradeHelper.ts @@ -1,3 +1,4 @@ +import { common } from '@neo-one/client-common'; import ts from 'typescript'; import { ScriptBuilder } from '../../sb'; import { VisitOptions } from '../../types'; @@ -42,12 +43,14 @@ export class UpgradeHelper extends Helper { sb.emitPushInt(node, 1); // [arg] sb.emitHelper(node, options, sb.helpers.getArgument); - // [length, ...args] - sb.emitOp(node, 'UNPACK'); - // [...args] - sb.emitOp(node, 'DROP'); - // [contract] - sb.emitSysCall(node, 'System.Contract.Update'); + // TODO: need to test this and make sure the "arg" is an array + // first arg is nefFile and second is manifest + // ['update', arg] + sb.emitPushString(node, 'update'); + // [buffer, 'update', arg] + sb.emitPushBuffer(node, common.nativeHashes.Management); + // [conract] + sb.emitSysCall(node, 'System.Contract.Call'); // [] sb.emitOp(node, 'DROP'); // [boolean] diff --git a/packages/neo-one-smart-contract-compiler/src/compile/sb/BaseScriptBuilder.ts b/packages/neo-one-smart-contract-compiler/src/compile/sb/BaseScriptBuilder.ts index 80570ab313..2284bea0b5 100644 --- a/packages/neo-one-smart-contract-compiler/src/compile/sb/BaseScriptBuilder.ts +++ b/packages/neo-one-smart-contract-compiler/src/compile/sb/BaseScriptBuilder.ts @@ -159,7 +159,7 @@ export abstract class BaseScriptBuilder implements ScriptB public getFinalResult(sourceMaps: { readonly [filePath: string]: RawSourceMap }): ScriptBuilderResult { this.withProgramCounter((programCounter) => { // Initialize static fields for scope tracking - this.emitOp(this.sourceFile, 'INITSSLOT', Buffer.from([0xff])); // TODO: currently only using a single slot, not all + this.emitOp(this.sourceFile, 'INITSSLOT', Buffer.from([0x01])); this.emitOp(this.sourceFile, 'NEWARRAY0'); this.emitOp(this.sourceFile, 'STSFLD0'); this.emitJmp(this.sourceFile, 'JMP_L', programCounter.getLast()); diff --git a/packages/neo-one-smart-contract-compiler/src/contract/ContractInfoProcessor.ts b/packages/neo-one-smart-contract-compiler/src/contract/ContractInfoProcessor.ts index dbcaabdea7..df961e27a4 100644 --- a/packages/neo-one-smart-contract-compiler/src/contract/ContractInfoProcessor.ts +++ b/packages/neo-one-smart-contract-compiler/src/contract/ContractInfoProcessor.ts @@ -28,6 +28,7 @@ export interface DeployPropInfo extends PropInfoBase { readonly isMixinDeploy: boolean; readonly decl?: ts.ConstructorDeclaration; readonly callSignature?: ts.Signature; + readonly isSafe: boolean; } export interface UpgradePropInfo extends PropInfoBase { @@ -109,7 +110,7 @@ export class ContractInfoProcessor { classDecl: this.smartContract, isPublic: true, approveUpgrade, - isSafe: true, // TODO: check + isSafe: false, } : undefined; @@ -131,6 +132,7 @@ export class ContractInfoProcessor { classDecl: this.smartContract, isPublic: true, isMixinDeploy: false, + isSafe: true, // TODO: check }, ]), }; @@ -224,6 +226,7 @@ export class ContractInfoProcessor { classDecl, decl: ctor, isPublic: true, + isSafe: true, // TODO: check callSignature, isMixinDeploy: maybeFunc !== undefined && this.context.analysis.isSmartContractMixinFunction(maybeFunc), }, @@ -273,6 +276,7 @@ export class ContractInfoProcessor { classDecl: this.smartContract, isPublic: true, isMixinDeploy: false, + isSafe: true, // TODO: check }, ]), }; @@ -462,6 +466,7 @@ export class ContractInfoProcessor { const isReadonly = tsUtils.modifier.isReadonly(decl); const isAbstract = tsUtils.modifier.isAbstract(decl); const initializer = tsUtils.initializer.getInitializer(decl); + const isSafe = this.hasSafe(decl); if (structuredStorageType !== undefined && (isPublic || isAbstract || !isReadonly || initializer === undefined)) { this.context.reportError( decl, @@ -493,7 +498,7 @@ export class ContractInfoProcessor { isReadonly, isAbstract, structuredStorageType, - isSafe: true, + isSafe: isReadonly || isSafe, }; } diff --git a/packages/neo-one-smart-contract-compiler/src/contract/ManifestSmartContractProcessor.ts b/packages/neo-one-smart-contract-compiler/src/contract/ManifestSmartContractProcessor.ts index eea1425847..118ca1671b 100644 --- a/packages/neo-one-smart-contract-compiler/src/contract/ManifestSmartContractProcessor.ts +++ b/packages/neo-one-smart-contract-compiler/src/contract/ManifestSmartContractProcessor.ts @@ -23,13 +23,7 @@ import { Context } from '../Context'; import { DiagnosticCode } from '../DiagnosticCode'; import { DiagnosticMessage } from '../DiagnosticMessage'; import { getSetterName, toABIReturn } from '../utils'; -import { - AccessorPropInfo, - ContractInfo, - DeployPropInfo, - FunctionPropInfo, - PropertyPropInfo, -} from './ContractInfoProcessor'; +import { ContractInfo, DeployPropInfo } from './ContractInfoProcessor'; const BOOLEAN_RETURN: ABIReturn = { type: 'Boolean' }; const VOID_RETURN: ABIReturn = { type: 'Void' }; @@ -42,23 +36,12 @@ export class ManifestSmartContractProcessor { ) {} public process(): SmartContractInfoManifest { - // TODO: can remove this later - const storage = this.processStorage(); - const payable = this.processPayable(); - return { groups: this.processGroups(), - features: { - storage, - payable, - }, supportedStandards: this.processSupportedStandards(), abi: this.processABI(), permissions: this.processPermissions(), trusts: this.processTrusts(), - safeMethods: this.processSafeMethods(), - hasStorage: storage, - payable, }; } @@ -89,43 +72,6 @@ export class ManifestSmartContractProcessor { return this.properties.trusts; } - private processPayable(): boolean { - const propInfos = this.contractInfo.propInfos.filter((propInfo) => propInfo.isPublic && propInfo.type !== 'deploy'); - - return propInfos.some((info) => info.type === 'function' && info.receive); - } - - // TODO: make sure this matches up with docs and with @safe decorator - // These methods are automatically safe: - // Marked with @safe or @constant - // Properties that are readonly or @safe - // Getters marked with @constant or @safe - // Not the deploy method - private processSafeMethods(): WildcardContainer { - const propInfos = this.contractInfo.propInfos.filter((propInfo) => propInfo.isPublic && propInfo.type !== 'deploy'); - - const safeFuncs = propInfos - .filter((info) => info.type === 'function' && (info.constant || info.isSafe)) - .map((info) => info.name); - const safeProps = propInfos - .filter((info) => info.type === 'property' && (info.isReadonly || info.isSafe)) - .map((info) => info.name); - const safeGetters = propInfos - .filter((info): info is AccessorPropInfo => info.type === 'accessor') - .map((info) => info.getter) - .filter(utils.notNull) - .filter((getter) => getter.constant || getter.isSafe) - .map((getter) => getter.name); - const safeSetters = propInfos - .filter((info): info is AccessorPropInfo => info.type === 'accessor') - .map((info) => info.setter) - .filter(utils.notNull) - .filter((setter) => setter.isSafe) - .map((setter) => setter.name); - - return safeFuncs.concat(safeProps, safeGetters, safeSetters); - } - private processSupportedStandards(): readonly string[] { return [this.isNep5Contract() ? 'NEP-5' : undefined].filter(utils.notNull); } @@ -153,20 +99,6 @@ export class ManifestSmartContractProcessor { return hasTotalSupply && hasBalanceOf && hasTransfer && hasDecimals && hasSymbol && hasName && hasTransferEvent; } - // TODO: can remove this later - private processStorage(): boolean { - const propInfos = this.contractInfo.propInfos.filter((propInfo) => propInfo.isPublic && propInfo.type !== 'deploy'); - - const funcProps = propInfos.filter((info): info is FunctionPropInfo => info.type === 'function'); - const hasNonConstant = funcProps.some((info) => !info.constant); - const propProps = propInfos.filter((info): info is PropertyPropInfo => info.type === 'property'); - const hasNonReadonly = propProps.some((info) => !info.isReadonly); - const accessorProps = propInfos.filter((info): info is AccessorPropInfo => info.type === 'accessor'); - const hasSetter = accessorProps.some((info) => info.setter !== undefined); - - return hasSetter || hasNonConstant || hasNonReadonly; - } - private processABI(): SmartContractInfoABI { return { // TODO: fix this later when changing how smart contracts are called @@ -201,6 +133,12 @@ export class ManifestSmartContractProcessor { ]; } + // TODO: make sure this matches up with docs and with @safe decorator + // These methods are automatically safe: + // Marked with @safe or @constant + // Properties that are readonly or @safe + // Getters marked with @constant or @safe + // Not the deploy method private processFunctions(): ReadonlyArray { const deployInfo = this.findDeployInfo(); const propInfos = this.contractInfo.propInfos @@ -219,6 +157,7 @@ export class ManifestSmartContractProcessor { ? [] : this.getParameters({ callSignature: propInfo.callSignature }), returnType: BOOLEAN_RETURN, + safe: propInfo.isSafe, }, ]; case 'upgrade': @@ -230,6 +169,7 @@ export class ManifestSmartContractProcessor { { name: 'manifest', type: 'Buffer' }, ], returnType: VOID_RETURN, + safe: propInfo.isSafe, }, ]; case 'function': @@ -241,6 +181,7 @@ export class ManifestSmartContractProcessor { }), returnType: this.toABIReturn(propInfo.decl, propInfo.returnType), constant: propInfo.constant, + safe: propInfo.isSafe, }, ]; case 'property': @@ -250,6 +191,7 @@ export class ManifestSmartContractProcessor { parameters: [], returnType: this.toABIReturn(propInfo.decl, propInfo.propertyType), constant: true, + safe: propInfo.isSafe, }, propInfo.isReadonly ? undefined @@ -261,6 +203,7 @@ export class ManifestSmartContractProcessor { }), ].filter(utils.notNull), returnType: VOID_RETURN, + safe: propInfo.isSafe, }, ].filter(utils.notNull); case 'accessor': @@ -272,6 +215,7 @@ export class ManifestSmartContractProcessor { parameters: [], constant: propInfo.getter.constant, returnType: this.toABIReturn(propInfo.getter.decl, propInfo.propertyType), + safe: propInfo.getter.isSafe, }, propInfo.setter === undefined ? undefined @@ -287,6 +231,7 @@ export class ManifestSmartContractProcessor { ), ].filter(utils.notNull), returnType: VOID_RETURN, + safe: propInfo.setter.isSafe, }, ].filter(utils.notNull); default: diff --git a/packages/neo-one-smart-contract-test/src/createNode.ts b/packages/neo-one-smart-contract-test/src/createNode.ts index b8ca9d95e8..d88eb7b605 100644 --- a/packages/neo-one-smart-contract-test/src/createNode.ts +++ b/packages/neo-one-smart-contract-test/src/createNode.ts @@ -15,7 +15,6 @@ export const createNode = async () => { const node = new FullNode({ options: { blockchain: createPriv({ - // privateNet: true, // TODO: fix here standbyValidators: [constants.PRIVATE_NET_PUBLIC_KEY], extraCommitteeMembers: [], }),