public void Test_InvalidMinter()
        {
            var tx = new TransactionReceipt();

            var context  = new InvocationContext(_mintCntrlAdd, _stateManager.LastApprovedSnapshot, tx);
            var contract = new NativeTokenContract(context);

            var keyPair = new EcdsaKeyPair("0x4433d156e8c53bf5b50af07aa95a29436f29a94e0ccc5d58df8e57bdc8583c32"
                                           .HexToBytes().ToPrivateKey());
            var address = keyPair.PublicKey.GetAddress();

            // set the allowedSupply
            {
                var input = ContractEncoder.Encode(Lrc20Interface.MethodSetAllowedSupply, Money.Parse("10000"));
                var call  = _contractRegisterer.DecodeContract(context, ContractRegisterer.NativeTokenContract, input);
                Assert.IsNotNull(call);
                var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000);
                Assert.AreEqual(ExecutionStatus.Ok, contract.SetAllowedSupply(Money.Parse("10000").ToUInt256(), frame));
            }

            // mint tokens to address
            {
                var input = ContractEncoder.Encode(Lrc20Interface.MethodMint, address, Money.Parse("100").ToUInt256());
                var call  = _contractRegisterer.DecodeContract(context, ContractRegisterer.NativeTokenContract, input);
                Assert.IsNotNull(call);
                var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000);
                Assert.AreEqual(ExecutionStatus.ExecutionHalted, contract.Mint(address, Money.Parse("100").ToUInt256(), frame));
                Assert.AreEqual(Money.Parse("0"), context.Snapshot.Balances.GetBalance(address));
            }
        }
        public void Test_SetMinter()
        {
            var tx = new TransactionReceipt();

            var context  = new InvocationContext(_mintCntrlAdd, _stateManager.LastApprovedSnapshot, tx);
            var contract = new NativeTokenContract(context);

            // set the minter
            {
                var input = ContractEncoder.Encode(Lrc20Interface.MethodSetMinter, _minterAdd);
                var call  = _contractRegisterer.DecodeContract(context, ContractRegisterer.NativeTokenContract, input);
                Assert.IsNotNull(call);
                var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000);
                Assert.AreEqual(ExecutionStatus.Ok, contract.SetMinter(_minterAdd, frame));
                var decoder = new ContractDecoder(frame.ReturnValue);
                var res     = decoder.Decode("uint160")[0] as UInt160 ?? throw new Exception("Invalid return value format");
                Assert.AreEqual(_minterAdd, res);
            }

            // get the minter
            {
                var input = ContractEncoder.Encode(Lrc20Interface.MethodGetMinter);
                var call  = _contractRegisterer.DecodeContract(context, ContractRegisterer.NativeTokenContract, input);
                Assert.IsNotNull(call);
                var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000);
                Assert.AreEqual(ExecutionStatus.Ok, contract.GetMinter(frame));
                var decoder = new ContractDecoder(frame.ReturnValue);
                var res     = decoder.Decode("uint160")[0] as UInt160 ?? throw new Exception("Invalid return value format");
                Assert.AreEqual(_minterAdd, res);
            }
        }
        public void Test_InvalidMintController()
        {
            var tx       = new TransactionReceipt();
            var context  = new InvocationContext(_mintCntrlAdd, _stateManager.LastApprovedSnapshot, tx);
            var contract = new NativeTokenContract(context);

            // set minter
            {
                var input = ContractEncoder.Encode(Lrc20Interface.MethodSetMinter, _minterAdd);
                var call  = _contractRegisterer.DecodeContract(context, ContractRegisterer.NativeTokenContract, input);
                Assert.IsNotNull(call);
                var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000);
                Assert.AreEqual(ExecutionStatus.Ok, contract.SetMinter(_minterAdd, frame));
                var decoder = new ContractDecoder(frame.ReturnValue);
                var res     = decoder.Decode("uint160")[0] as UInt160 ?? throw new Exception("Invalid return value format");
                Assert.AreEqual(_minterAdd, res);
            }


            // set the allowedSupply
            {
                context  = new InvocationContext(_stateManager.LastApprovedSnapshot.Balances.GetMinter(), _stateManager.LastApprovedSnapshot, tx);
                contract = new NativeTokenContract(context);

                var input = ContractEncoder.Encode(Lrc20Interface.MethodSetAllowedSupply, Money.Parse("10000"));
                var call  = _contractRegisterer.DecodeContract(context, ContractRegisterer.NativeTokenContract, input);
                Assert.IsNotNull(call);
                var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000);
                Assert.AreEqual(ExecutionStatus.ExecutionHalted, contract.SetAllowedSupply(Money.Parse("10000").ToUInt256(), frame));
            }

            // verify allowedSupply
            {
                var input = ContractEncoder.Encode(Lrc20Interface.MethodGetAllowedSupply);
                var call  = _contractRegisterer.DecodeContract(context, ContractRegisterer.NativeTokenContract, input);
                Assert.IsNotNull(call);
                var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000);
                Assert.AreEqual(ExecutionStatus.Ok, contract.GetAllowedSupply(frame));
                var decoder = new ContractDecoder(frame.ReturnValue);
                var res     = decoder.Decode("uint256")[0] as UInt256 ?? throw new Exception("Invalid return value format");
                Assert.AreEqual(Money.Parse("0"), res.ToMoney());
            }
        }
        public void Test_SetMinterInvalidMintCtlr()
        {
            var keyPair = new EcdsaKeyPair("0x4433d156e8c53bf5b50af07aa95a29436f29a94e0ccc5d58df8e57bdc8583c32"
                                           .HexToBytes().ToPrivateKey());
            var address = keyPair.PublicKey.GetAddress();

            var tx = new TransactionReceipt();

            var context  = new InvocationContext(address, _stateManager.LastApprovedSnapshot, tx);
            var contract = new NativeTokenContract(context);

            // set the minter
            {
                var input = ContractEncoder.Encode(Lrc20Interface.MethodSetMinter, _minterAdd);
                var call  = _contractRegisterer.DecodeContract(context, ContractRegisterer.NativeTokenContract, input);
                Assert.IsNotNull(call);
                var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000);
                Assert.AreEqual(ExecutionStatus.ExecutionHalted, contract.SetMinter(_minterAdd, frame));
            }
        }
        public void Test_NativeTokenMinting()
        {
            var tx = new TransactionReceipt();

            var context  = new InvocationContext(_mintCntrlAdd, _stateManager.LastApprovedSnapshot, tx);
            var contract = new NativeTokenContract(context);

            var keyPair = new EcdsaKeyPair("0x4433d156e8c53bf5b50af07aa95a29436f29a94e0ccc5d58df8e57bdc8583c32"
                                           .HexToBytes().ToPrivateKey());
            var address = keyPair.PublicKey.GetAddress();

            // set the wallet to mint the tokens
            {
                context.Snapshot.Balances.SetBalance(address, Money.Parse("1000"));

                var input = ContractEncoder.Encode(Lrc20Interface.MethodBalanceOf, address);
                var call  = _contractRegisterer.DecodeContract(context, ContractRegisterer.NativeTokenContract, input);
                Assert.IsNotNull(call);
                var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000);
                Assert.AreEqual(ExecutionStatus.Ok, contract.BalanceOf(address, frame));
                var decoder = new ContractDecoder(frame.ReturnValue);
                var res     = decoder.Decode("uint256")[0] as UInt256 ?? throw new Exception("Invalid return value format");
                Assert.AreEqual(Money.Parse("1000"), res.ToMoney());
            }

            // check the allowedSupply
            {
                var input = ContractEncoder.Encode(Lrc20Interface.MethodGetAllowedSupply);
                var call  = _contractRegisterer.DecodeContract(context, ContractRegisterer.NativeTokenContract, input);
                Assert.IsNotNull(call);
                var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000);
                Assert.AreEqual(ExecutionStatus.Ok, contract.GetAllowedSupply(frame));
                var decoder = new ContractDecoder(frame.ReturnValue);
                var res     = decoder.Decode("uint256")[0] as UInt256 ?? throw new Exception("Invalid return value format");
                Assert.AreEqual(Money.Parse("0"), res.ToMoney());
            }

            // set the allowedSupply
            {
                var input = ContractEncoder.Encode(Lrc20Interface.MethodSetAllowedSupply, Money.Parse("10000"));
                var call  = _contractRegisterer.DecodeContract(context, ContractRegisterer.NativeTokenContract, input);
                Assert.IsNotNull(call);
                var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000);
                Assert.AreEqual(ExecutionStatus.Ok, contract.SetAllowedSupply(Money.Parse("10000").ToUInt256(), frame));
                var decoder = new ContractDecoder(frame.ReturnValue);
                var res     = decoder.Decode("uint256")[0] as UInt256 ?? throw new Exception("Invalid return value format");
                Assert.AreEqual(Money.Parse("10000"), res.ToMoney());
            }

            // set minter
            {
                var input = ContractEncoder.Encode(Lrc20Interface.MethodSetMinter, _minterAdd);
                var call  = _contractRegisterer.DecodeContract(context, ContractRegisterer.NativeTokenContract, input);
                Assert.IsNotNull(call);
                var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000);
                Assert.AreEqual(ExecutionStatus.Ok, contract.SetMinter(_minterAdd, frame));
                var decoder = new ContractDecoder(frame.ReturnValue);
                var res     = decoder.Decode("uint160")[0] as UInt160 ?? throw new Exception("Invalid return value format");
                Assert.AreEqual(_minterAdd, res);
            }

            // mint tokens to address
            {
                context.Sender = context.Snapshot.Balances.GetMinter();

                var input = ContractEncoder.Encode(Lrc20Interface.MethodMint, address, Money.Parse("100"));
                var call  = _contractRegisterer.DecodeContract(context, ContractRegisterer.NativeTokenContract, input);
                Assert.IsNotNull(call);
                var frame = new SystemContractExecutionFrame(call !, context, input, 100_000_000);
                Assert.AreEqual(ExecutionStatus.Ok, contract.Mint(address, Money.Parse("100").ToUInt256(), frame));
                var decoder = new ContractDecoder(frame.ReturnValue);
                var res     = decoder.Decode("uint256")[0] as UInt256 ?? throw new Exception("Invalid return value format");
                Assert.AreEqual(Money.Parse("1100"), res.ToMoney());
            }
        }