public async Task CanGetContractBalanceFromCall() { await using var fx = await PayableContract.CreateAsync(_network); var record = await fx.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fx.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(400), FunctionName = "get_balance" }, ctx => ctx.Memo = "Call Contract"); Assert.NotNull(record); Assert.Equal(ResponseCode.Success, record.Status); Assert.False(record.Hash.IsEmpty); Assert.NotNull(record.Concensus); Assert.Equal("Call Contract", record.Memo); Assert.InRange(record.Fee, 0UL, ulong.MaxValue); Assert.Empty(record.CallResult.Error); Assert.True(record.CallResult.Bloom.IsEmpty); Assert.InRange(record.CallResult.Gas, 0UL, 30_000UL); Assert.Empty(record.CallResult.Events); Assert.Empty(record.CallResult.CreatedContracts); Assert.Equal(fx.ContractParams.InitialBalance, record.CallResult.Result.As <long>()); // Ensure matches API vesion. var apiBalance = await fx.Client.GetContractBalanceAsync(fx.ContractRecord.Contract); Assert.Equal((ulong)fx.ContractParams.InitialBalance, apiBalance); }
public async Task CanGetContractBalanceFromLocalCall() { await using var fx = await PayableContract.CreateAsync(_network); var result = await fx.Client.QueryContractAsync(new QueryContractParams { Contract = fx.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(400), FunctionName = "get_balance", }); Assert.NotNull(result); Assert.Empty(result.Error); Assert.True(result.Bloom.IsEmpty); Assert.InRange(result.Gas, 0UL, 30_000UL); Assert.Empty(result.Events); Assert.Equal(fx.ContractParams.InitialBalance, result.Result.As <long>()); Assert.Empty(result.CreatedContracts); // Ensure matches API vesion. var apiBalance = await fx.Client.GetContractBalanceAsync(fx.ContractRecord.Contract); Assert.Equal((ulong)fx.ContractParams.InitialBalance, apiBalance); // Ensure matches Info version var info = await fx.Client.GetContractInfoAsync(fx.ContractRecord.Contract); Assert.Equal((ulong)fx.ContractParams.InitialBalance, info.Balance); }
public async Task CanCallContractMethodSendingFunds() { await using var fx = await PayableContract.CreateAsync(_network); await using var fx2 = await TestAccount.CreateAsync(_network); var infoBefore = await fx2.Client.GetAccountInfoAsync(fx2.Record.Address); var record = await fx.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fx.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(600), FunctionName = "send_to", FunctionArgs = new[] { fx2.Record.Address } }); Assert.NotNull(record); Assert.Equal(ResponseCode.Success, record.Status); Assert.False(record.Hash.IsEmpty); Assert.NotNull(record.Concensus); Assert.Empty(record.Memo); Assert.InRange(record.Fee, 0UL, ulong.MaxValue); Assert.Empty(record.CallResult.Error); Assert.True(record.CallResult.Bloom.IsEmpty); Assert.InRange(record.CallResult.Gas, 0UL, 30_000UL); Assert.Empty(record.CallResult.Events); Assert.Empty(record.CallResult.CreatedContracts); var infoAfter = await fx2.Client.GetAccountInfoAsync(fx2.Record.Address); Assert.Equal((ulong)fx.ContractParams.InitialBalance, infoAfter.Balance - infoBefore.Balance); }
public async Task CanGetEventPayableContractBytecode() { await using var fx = await PayableContract.CreateAsync(_network); var bytecode = await fx.Client.GetContractBytecodeAsync(fx.ContractRecord.Contract); Assert.False(bytecode.IsEmpty); }
public async Task CanGetBalancesForContractAsync() { await using var fx = await PayableContract.CreateAsync(_network); var balances = await fx.Client.GetContractBalancesAsync(fx.ContractRecord.Contract); Assert.Equal((ulong)fx.ContractParams.InitialBalance, balances.Crypto); Assert.Empty(balances.Tokens); }
public async Task MissingPayerAccountDosNotThrowException() { await using var fx = await PayableContract.CreateAsync(_network); await using var client = new Client(ctx => { ctx.Gateway = _network.Gateway; }); var balance = await client.GetContractBalanceAsync(fx.ContractRecord.Contract); Assert.Equal((ulong)fx.ContractParams.InitialBalance, balance); }
public async Task CanGetContractBalanceFromCall() { await using var fx = await PayableContract.CreateAsync(_network); var record = await fx.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fx.ContractRecord.Contract, Gas = 300_000, FunctionName = "get_balance" });
public async Task TransferFundsToPayableContractWithExternalPayableRaisesContractBalanceVersion070Regression() { // Version 0.6.0 allowed for transfer of crypto to an account using the // crypto API calls if the contract had a default payable method. This // has changed with version 0.7.0. We are marking this as a regression for // now in the case that this change is reverted in a subsequent revision. // We will need to revisit this in the future to decide how to test this // behavior. var testFailException = (await Assert.ThrowsAsync <TransactionException>(TransferFundsToPayableContractWithExternalPayableRaisesContractBalance)); Assert.StartsWith("Unable to execute transfers, status: InvalidAccountId", testFailException.Message); //[Fact(DisplayName = "Payable Contract: Transfer Funds to External Payable Default Function Raises Contract's Account Balance")] async Task TransferFundsToPayableContractWithExternalPayableRaisesContractBalance() { await using var fx = await PayableContract.CreateAsync(_network); ulong initialBalance = (ulong)fx.ContractParams.InitialBalance; var apiBalanceBefore = await fx.Client.GetContractBalanceAsync(fx.ContractRecord.Contract); var infoBalanceBefore = (await fx.Client.GetContractInfoAsync(fx.ContractRecord.Contract)).Balance; var callBalanceBefore = (ulong)(await fx.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fx.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(400), FunctionName = "get_balance" })).CallResult.Result.As <long>(); Assert.Equal(initialBalance, apiBalanceBefore); Assert.Equal(initialBalance, infoBalanceBefore); Assert.Equal(initialBalance, callBalanceBefore); var extraFunds = Generator.Integer(500, 1000); var record = await fx.Client.TransferAsync(_network.Payer, fx.ContractRecord.Contract, extraFunds); Assert.Equal(ResponseCode.Success, record.Status); ulong finalBalance = (ulong)fx.ContractParams.InitialBalance + (ulong)extraFunds; var apiBalanceAfter = await fx.Client.GetContractBalanceAsync(fx.ContractRecord.Contract); var infoBalanceAfter = (await fx.Client.GetContractInfoAsync(fx.ContractRecord.Contract)).Balance; var callBalanceAfter = (ulong)(await fx.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fx.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(400), FunctionName = "get_balance" })).CallResult.Result.As <long>(); Assert.Equal(finalBalance, apiBalanceAfter); Assert.Equal(finalBalance, infoBalanceAfter); Assert.Equal(finalBalance, callBalanceAfter); } }
public async Task CanGetTinybarBalanceForContractAsync() { await using var fx = await PayableContract.CreateAsync(_network); var balance = await fx.Client.GetContractBalanceAsync(fx.ContractRecord.Contract); Assert.Equal((ulong)fx.ContractParams.InitialBalance, balance); var info = await fx.Client.GetContractInfoAsync(fx.ContractRecord.Contract); Assert.Equal(balance, info.Balance); }
public async Task CanCreateAPayableContract() { await using var fx = await PayableContract.CreateAsync(_network); Assert.NotNull(fx.ContractRecord); Assert.NotNull(fx.ContractRecord.Contract); Assert.Equal(ResponseCode.Success, fx.ContractRecord.Status); Assert.NotEmpty(fx.ContractRecord.Hash.ToArray()); Assert.NotNull(fx.ContractRecord.Concensus); Assert.NotNull(fx.ContractRecord.Memo); Assert.InRange(fx.ContractRecord.Fee, 0UL, ulong.MaxValue); }
public async Task RetrievingAccountBalanceDoesNotCreateReceipt() { await using var fx = await PayableContract.CreateAsync(_network); await using var client = _network.NewClient(); var txId = client.CreateNewTxId(); var balance = await client.GetContractBalanceAsync(fx.ContractRecord.Contract, ctx => ctx.Transaction = txId); var tex = await Assert.ThrowsAsync <TransactionException>(async() => { var receipt = await client.GetReceiptAsync(txId); }); Assert.Equal(txId, tex.TxId); Assert.Equal(ResponseCode.ReceiptNotFound, tex.Status); Assert.StartsWith("Network failed to return a transaction receipt", tex.Message); }
public static async Task <PayableContract> CreateAsync(NetworkCredentials networkCredentials, Action <PayableContract> customize = null) { var fx = new PayableContract(); networkCredentials.Output?.WriteLine("STARTING SETUP: Creating Payable Contract Instance"); (fx.PublicKey, fx.PrivateKey) = Generator.KeyPair(); fx.Network = networkCredentials; fx.FileParams = new CreateFileParams { Expiration = DateTime.UtcNow.AddSeconds(7890000), Endorsements = new Endorsement[] { networkCredentials.PublicKey }, Contents = Encoding.UTF8.GetBytes(PAYABLE_CONTRACT_BYTECODE) }; fx.Client = networkCredentials.NewClient(); fx.FileRecord = await fx.Client.RetryKnownNetworkIssues(async client => { return(await fx.Client.CreateFileWithRecordAsync(fx.FileParams, ctx => { ctx.Memo = "Payable Contract Create: Uploading Contract File " + Generator.Code(10); })); }); Assert.Equal(ResponseCode.Success, fx.FileRecord.Status); fx.ContractParams = new CreateContractParams { File = fx.FileRecord.File, Administrator = fx.PublicKey, Signatory = fx.PrivateKey, Gas = 300000, InitialBalance = 1_000_000, RenewPeriod = TimeSpan.FromSeconds(7890000), Memo = "Payable Contract " + Generator.Code(10) }; customize?.Invoke(fx); fx.ContractRecord = await fx.Client.RetryKnownNetworkIssues(async client => { return(await fx.Client.CreateContractWithRecordAsync(fx.ContractParams, ctx => { ctx.Memo = "Payable Contract Create: Instantiating Payable Instance " + Generator.Code(10); })); }); Assert.Equal(ResponseCode.Success, fx.FileRecord.Status); fx.Network.Output?.WriteLine("SETUP COMPLETED: Payable Contract Instance Created"); return(fx); }
public async Task SendFundsToInvalidAccountRaisesError() { await using var fx = await PayableContract.CreateAsync(_network); var tex = await Assert.ThrowsAsync <TransactionException>(async() => { await fx.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fx.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(3000), FunctionName = "send_to", FunctionArgs = new[] { new Address(0, 0, long.MaxValue) } }); }); Assert.Equal(ResponseCode.InvalidSolidityAddress, tex.Status); Assert.StartsWith("Contract call failed, status: InvalidSolidityAddress", tex.Message); }
public async Task SendFundsToPayableContractWithExternalPayableRaisesContractBalance() { await using var fx = await PayableContract.CreateAsync(_network); ulong initialBalance = (ulong)fx.ContractParams.InitialBalance; var apiBalanceBefore = await fx.Client.GetContractBalanceAsync(fx.ContractRecord.Contract); var infoBalanceBefore = (await fx.Client.GetContractInfoAsync(fx.ContractRecord.Contract)).Balance; var callBalanceBefore = (ulong)(await fx.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fx.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(400), FunctionName = "get_balance" })).CallResult.Result.As <long>(); Assert.Equal(initialBalance, apiBalanceBefore); Assert.Equal(initialBalance, infoBalanceBefore); Assert.Equal(initialBalance, callBalanceBefore); var extraFunds = Generator.Integer(500, 1000); var record = await fx.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fx.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(400), PayableAmount = extraFunds }); Assert.Equal(ResponseCode.Success, record.Status); ulong finalBalance = (ulong)fx.ContractParams.InitialBalance + (ulong)extraFunds; var apiBalanceAfter = await fx.Client.GetContractBalanceAsync(fx.ContractRecord.Contract); var infoBalanceAfter = (await fx.Client.GetContractInfoAsync(fx.ContractRecord.Contract)).Balance; var callBalanceAfter = (ulong)(await fx.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fx.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(400), FunctionName = "get_balance" })).CallResult.Result.As <long>(); Assert.Equal(finalBalance, apiBalanceAfter); Assert.Equal(finalBalance, infoBalanceAfter); Assert.Equal(finalBalance, callBalanceAfter); }
public async Task CanSendFundsToPayableContractWithExternalPayable() { await using var fx = await PayableContract.CreateAsync(_network); var extraFunds = Generator.Integer(500, 1000); var record = await fx.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fx.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(400), PayableAmount = extraFunds }); Assert.Equal(ResponseCode.Success, record.Status); await using var fx2 = await TestAccount.CreateAsync(_network); var infoBefore = await fx2.Client.GetAccountInfoAsync(fx2.Record.Address); record = await fx.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fx.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(600), FunctionName = "send_to", FunctionArgs = new[] { fx2.Record.Address } }, ctx => ctx.Memo = "Call Contract"); Assert.NotNull(record); Assert.Equal(ResponseCode.Success, record.Status); Assert.False(record.Hash.IsEmpty); Assert.NotNull(record.Concensus); Assert.Equal("Call Contract", record.Memo); Assert.InRange(record.Fee, 0UL, ulong.MaxValue); Assert.Empty(record.CallResult.Error); Assert.True(record.CallResult.Bloom.IsEmpty); Assert.InRange(record.CallResult.Gas, 0UL, 30_000UL); Assert.Empty(record.CallResult.Events); Assert.Empty(record.CallResult.CreatedContracts); var infoAfter = await fx2.Client.GetAccountInfoAsync(fx2.Record.Address); Assert.Equal((ulong)(fx.ContractParams.InitialBalance + extraFunds), infoAfter.Balance - infoBefore.Balance); }
public async Task AttemptsToMisplaceHbarsThruPayableContractShouldFail() { // Setup the Simple Payable Contract and An account for "send to". await using var fxAccount1 = await TestAccount.CreateAsync(_network); await using var fxAccount2 = await TestAccount.CreateAsync(_network); await using var fxContract = await PayableContract.CreateAsync(_network); // Get the Info for the account state and then delete the account. var info1Before = await fxAccount1.Client.GetAccountInfoAsync(fxAccount1.Record.Address); var info2Before = await fxAccount2.Client.GetAccountInfoAsync(fxAccount2.Record.Address); var delete1Receipt = await fxAccount1.Client.DeleteAccountAsync(fxAccount1.Record.Address, fxAccount1.Network.Payer, fxAccount1.PrivateKey); Assert.Equal(ResponseCode.Success, delete1Receipt.Status); // Double check the balance on the contract, confirm it has hbars var contractBalanceBefore = await fxContract.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fxContract.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(600), FunctionName = "get_balance" }); Assert.NotNull(contractBalanceBefore); Assert.InRange(fxContract.ContractParams.InitialBalance, 1, int.MaxValue); Assert.Equal(fxContract.ContractParams.InitialBalance, contractBalanceBefore.CallResult.Result.As <long>()); // Ensure matches API vesion. var apiBalance = await fxContract.Client.GetContractBalanceAsync(fxContract.ContractRecord.Contract); Assert.Equal((ulong)fxContract.ContractParams.InitialBalance, apiBalance); // Call the contract, sending to the address of the now deleted account // Call the contract, sending to the address of the now deleted account var tex = await Assert.ThrowsAsync <TransactionException>(async() => { await fxContract.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fxContract.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(600), FunctionName = "send_to", FunctionArgs = new[] { fxAccount1.Record.Address } }); }); Assert.Equal(ResponseCode.InvalidSolidityAddress, tex.Status); Assert.StartsWith("Contract call failed, status: InvalidSolidityAddress", tex.Message); // Confirm that the balance on the contract did not change. var contractBalanceAfter = await fxContract.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fxContract.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(400), FunctionName = "get_balance" }); Assert.NotNull(contractBalanceAfter); Assert.Equal(fxContract.ContractParams.InitialBalance, contractBalanceAfter.CallResult.Result.As <long>()); // Ensure matches API vesion. apiBalance = await fxContract.Client.GetContractBalanceAsync(fxContract.ContractRecord.Contract); Assert.Equal((ulong)fxContract.ContractParams.InitialBalance, apiBalance); // Try to get info on the deleted account, but this will fail because the // account is already deleted. var pex = await Assert.ThrowsAsync <PrecheckException>(async() => { // So if this throws an error, why did the above call not fail? await fxAccount1.Client.GetAccountInfoAsync(fxAccount1.Record.Address); }); // Delete the Contract, returning any hidden hbars to account number 2 var deleteContractRecord = await fxContract.Client.DeleteContractAsync(fxContract.ContractRecord.Contract, fxAccount2.Record.Address, fxContract.PrivateKey); Assert.Equal(ResponseCode.Success, deleteContractRecord.Status); // Check the balance of account number 2, the hBars should be there? var info2After = await fxAccount2.Client.GetAccountInfoAsync(fxAccount2.Record.Address); Assert.Equal((ulong)fxContract.ContractParams.InitialBalance + info2Before.Balance, info2After.Balance); // NOPE! }
public async Task SendFundsToDeletedAccountRaisesError() { // Setup the Simple Payable Contract and An account for "send to". await using var fxContract = await PayableContract.CreateAsync(_network); await using var fxAccount = await TestAccount.CreateAsync(_network); // Get the Info for the account state and then delete the account. var infoBefore = await fxAccount.Client.GetAccountInfoAsync(fxAccount.Record.Address); var deleteReceipt = await fxAccount.Client.DeleteAccountAsync(fxAccount.Record.Address, fxAccount.Network.Payer, fxAccount.PrivateKey); Assert.Equal(ResponseCode.Success, deleteReceipt.Status); // Double check the balance on the contract, confirm it has hbars var contractBalanceBefore = await fxContract.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fxContract.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(600), FunctionName = "get_balance" }); Assert.NotNull(contractBalanceBefore); Assert.InRange(fxContract.ContractParams.InitialBalance, 1, int.MaxValue); Assert.Equal(fxContract.ContractParams.InitialBalance, contractBalanceBefore.CallResult.Result.As <long>()); // Ensure matches API vesion. var apiBalance = await fxContract.Client.GetContractBalanceAsync(fxContract.ContractRecord.Contract); Assert.Equal((ulong)fxContract.ContractParams.InitialBalance, apiBalance); // Ensure matches Info version var info = await fxContract.Client.GetContractInfoAsync(fxContract.ContractRecord.Contract); Assert.Equal((ulong)fxContract.ContractParams.InitialBalance, info.Balance); // Call the contract, sending to the address of the now deleted account var tex = await Assert.ThrowsAsync <TransactionException>(async() => { await fxContract.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fxContract.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(600), FunctionName = "send_to", FunctionArgs = new[] { fxAccount.Record.Address } }); }); Assert.Equal(ResponseCode.InvalidSolidityAddress, tex.Status); Assert.StartsWith("Contract call failed, status: InvalidSolidityAddress", tex.Message); // Confirm that the balance on the contract remained unchanged. var contractBalanceAfter = await fxContract.Client.CallContractWithRecordAsync(new CallContractParams { Contract = fxContract.ContractRecord.Contract, Gas = await _network.TinybarsFromGas(400), FunctionName = "get_balance" }); Assert.NotNull(contractBalanceAfter); Assert.Equal(fxContract.ContractParams.InitialBalance, contractBalanceAfter.CallResult.Result.As <long>()); // Ensure matches API vesion. apiBalance = await fxContract.Client.GetContractBalanceAsync(fxContract.ContractRecord.Contract); Assert.Equal((ulong)fxContract.ContractParams.InitialBalance, apiBalance); // Ensure matches Info version info = await fxContract.Client.GetContractInfoAsync(fxContract.ContractRecord.Contract); Assert.Equal((ulong)fxContract.ContractParams.InitialBalance, info.Balance); }