public async Task Test_Fees()
        {
            var(abi, tvc) = TestClient.Package("GiverV2", 2);
            var keys = await _client.Crypto.GenerateRandomSignKeysAsync();

            var address = await _client.DeployWithGiverAsync(new ParamsOfEncodeMessage
            {
                Abi       = abi,
                DeploySet = new DeploySet
                {
                    Tvc = tvc
                },
                CallSet = new CallSet
                {
                    FunctionName = "constructor"
                },
                Signer = new Signer.Keys
                {
                    KeysProperty = keys
                }
            });

            var @params = new ParamsOfEncodeMessage
            {
                Abi     = abi,
                Address = address,
                CallSet = new CallSet
                {
                    FunctionName = "sendTransaction",
                    Input        = new
                    {
                        dest   = address,
                        value  = 100000000u,
                        bounce = false
                    }.ToJson()
                },
                Signer = new Signer.Keys
                {
                    KeysProperty = keys
                }
            };

            var account = (await _client.FetchAccountAsync(address))["boc"]?.ToString();
            var message = await _client.Abi.EncodeMessageAsync(@params);

            var localResult = await _client.Tvm.RunExecutorAsync(new ParamsOfRunExecutor
            {
                Account = new AccountForExecutor.Account
                {
                    Boc = account
                },
                Message = message.Message
            });

            var runResult = await _client.Processing.ProcessMessageAsync(new ParamsOfProcessMessage
            {
                MessageEncodeParams = @params,
                SendEvents          = false
            });

            Assert.Equal(localResult.Fees.GasFee, runResult.Fees.GasFee);
            Assert.Equal(localResult.Fees.OutMsgsFwdFee, runResult.Fees.OutMsgsFwdFee);
            Assert.Equal(localResult.Fees.InMsgFwdFee, runResult.Fees.InMsgFwdFee);
            Assert.Equal(localResult.Fees.TotalOutput, runResult.Fees.TotalOutput);
            Assert.Equal(localResult.Fees.TotalOutput, new BigInteger(100000000u));
            Assert.Equal(localResult.Fees.TotalAccountFees - localResult.Fees.StorageFee,
                         localResult.Fees.TotalAccountFees - localResult.Fees.StorageFee);
            Assert.True(runResult.Fees.StorageFee >= localResult.Fees.StorageFee);
            Assert.True(runResult.Fees.OutMsgsFwdFee > 0);
            Assert.True(runResult.Fees.InMsgFwdFee > 0);
            Assert.True(runResult.Fees.TotalAccountFees > 0);
        }
        public async Task Should_Suspend_Resume()
        {
            var keys = await _client.Crypto.GenerateRandomSignKeysAsync();

            var(abi, tvc) = TestClient.Package("Hello");

            var deployParams = new ParamsOfEncodeMessage
            {
                Abi       = abi,
                DeploySet = new DeploySet
                {
                    Tvc = tvc
                },
                Signer = new Signer.Keys
                {
                    KeysProperty = keys
                },
                CallSet = new CallSet
                {
                    FunctionName = "constructor"
                }
            };

            var msg = await _client.Abi.EncodeMessageAsync(deployParams);

            var address        = msg.Address;
            var transactionIds = new List <string>();
            var notifications  = new List <ClientError>();

            var subscriptionClient = TestClient.Create(_logger);

            var handle = await subscriptionClient.Net.SubscribeCollectionAsync(new ParamsOfSubscribeCollection
            {
                Collection = "transactions",
                Filter     = new
                {
                    account_addr = new { eq = address },
                    status       = new { eq = 3 } // Finalized
                }.ToJson(),
                Result = "id account_addr"
            }, (json, result) =>
            {
                switch (result)
                {
                case 100:     // OK
                    transactionIds.Add((string)json.SelectToken("result.id"));
                    break;

                case 101:     // Error
                    var clientError = new TonSerializer(_logger).Deserialize <ClientError>(json);
                    notifications.Add(clientError);
                    break;

                default:
                    throw new NotSupportedException($"Response code ${result} not supported");
                }

                return(Task.CompletedTask);
            });

            // send grams to create first transaction
            await _client.GetGramsFromGiverAsync(msg.Address);

            await Task.Delay(TimeSpan.FromSeconds(1));

            // check that transaction is received
            Assert.Single(transactionIds);

            // and no error notifications
            Assert.Empty(notifications);

            // suspend subscription
            await subscriptionClient.Net.SuspendAsync();

            // deploy to create second transaction
            await _client.Processing.ProcessMessageAsync(new ParamsOfProcessMessage
            {
                MessageEncodeParams = deployParams,
                SendEvents          = false
            });

            // create second subscription while network is suspended
            var handle2 = await subscriptionClient.Net.SubscribeCollectionAsync(new ParamsOfSubscribeCollection
            {
                Collection = "transactions",
                Filter     = new
                {
                    account_addr = new { eq = msg.Address },
                    status       = new { eq = 3 } // Finalized
                }.ToJson(),
                Result = "id account_addr"
            }, (json, result) =>
            {
                switch (result)
                {
                case 100:     // OK
                    transactionIds.Add((string)json.SelectToken("result.id"));
                    break;

                case 101:     // Error
                    var clientError = new TonSerializer(_logger).Deserialize <ClientError>(json);
                    notifications.Add(clientError);
                    break;

                default:
                    throw new NotSupportedException($"Response code ${result} not supported");
                }

                return(Task.CompletedTask);
            });

            await Task.Delay(TimeSpan.FromMilliseconds(500));

            // check that second transaction is not received when subscription suspended
            Assert.Single(transactionIds);
            Assert.Equal(2, notifications.Count);
            Assert.All(notifications, n =>
                       Assert.Equal((uint)NetErrorCode.NetworkModuleSuspended, n.Code));

            // resume subscription
            await subscriptionClient.Net.ResumeAsync();

            // run contract function to create new transaction
            await subscriptionClient.Processing.ProcessMessageAsync(new ParamsOfProcessMessage
            {
                MessageEncodeParams = new ParamsOfEncodeMessage
                {
                    Abi    = abi,
                    Signer = new Signer.Keys
                    {
                        KeysProperty = keys
                    },
                    Address = msg.Address,
                    CallSet = new CallSet
                    {
                        FunctionName = "touch"
                    }
                },
                SendEvents = false
            });

            // give some time for subscription to receive all data
            await Task.Delay(TimeSpan.FromSeconds(10));

            // check that third transaction is now received after resume
            Assert.Equal(3, transactionIds.Count);
            Assert.Equal(2, transactionIds.Distinct().Count());

            // and both subscriptions received notification about resume
            Assert.Equal(4, notifications.Count);
            Assert.Equal(2, notifications.Count(n => n.Code == (uint)NetErrorCode.NetworkModuleSuspended));
            Assert.Equal(2, notifications.Count(n => n.Code == (uint)NetErrorCode.NetworkModuleResumed));

            await subscriptionClient.Net.UnsubscribeAsync(handle);

            await subscriptionClient.Net.UnsubscribeAsync(handle2);
        }
Exemplo n.º 3
0
        public async Task SubscribeForTransactionsWithAddresses()
        {
            KeyPair keys = await _tonClient.Crypto.GenerateRandomSignKeys();

            ITonClient subscriptionClient = _fixture.CreateClient(_outputHelper, true);

            var deployParams = new ParamsOfEncodeMessage
            {
                Abi       = TestsEnv.Packages.Hello.Abi,
                DeploySet = new DeploySet {
                    Tvc = TestsEnv.Packages.Hello.Tvc
                },
                Signer = new Signer.Keys {
                    KeysAccessor = keys
                },
                CallSet = new CallSet {
                    FunctionName = "constructor"
                }
            };

            ResultOfEncodeMessage msg = await _tonClient.Abi.EncodeMessage(deployParams);

            var transactions = new List <string>();
            var errorCodes   = new List <uint>();
            var @lock        = new object();

            var address = msg.Address;

            var callback = new Action <JsonElement, uint>((serdeJson, responseType) =>
            {
                switch ((SubscriptionResponseType)responseType)
                {
                case SubscriptionResponseType.Ok:
                    JsonElement resultOk = serdeJson.GetProperty("result");
                    resultOk.Get <string>("account_addr").Should().Be(address);
                    lock (@lock)
                    {
                        transactions.Add(resultOk.Get <string>("id"));
                    }

                    break;

                case SubscriptionResponseType.Error:
                    var error = serdeJson.ToObject <ClientError>();
                    _outputHelper.WriteLine($">> {error}");
                    lock (@lock)
                    {
                        errorCodes.Add(error.Code);
                    }

                    break;

                default:
                    throw new TonClientException($"Unknown SubscriptionResponseType: {responseType}");
                }
            });

            //act
            ResultOfSubscribeCollection handle1 = await subscriptionClient.Net.SubscribeCollection(new ParamsOfSubscribeCollection
            {
                Collection = "transactions",
                Filter     = new
                {
                    account_addr = new { eq = address },
                    status       = new { eq = (int)TransactionProcessingStatus.Finalized }
                }.ToJsonElement(),
                Result = "id account_addr"
            }, callback);

            // send grams to create first transaction
            await _tonClient.SendGramsFromLocalGiver(address);

            // give some time for subscription to receive all data
            await Task.Delay(TimeSpan.FromSeconds(1));

            var transactionCount1 = transactions.Count;

            // suspend subscription
            await subscriptionClient.Net.Suspend();

            await Task.Delay(TimeSpan.FromSeconds(1));

            // deploy to create second transaction
            await _tonClient.Processing.ProcessMessage(new ParamsOfProcessMessage
            {
                MessageEncodeParams = deployParams,
                SendEvents          = false
            });

            //act
            ResultOfSubscribeCollection handle2 = await subscriptionClient.Net.SubscribeCollection(new ParamsOfSubscribeCollection
            {
                Collection = "transactions",
                Filter     = new
                {
                    account_addr = new { eq = address },
                    status       = new { eq = (int)TransactionProcessingStatus.Finalized }
                }.ToJsonElement(),
                Result = "id account_addr"
            }, callback);

            await Task.Delay(TimeSpan.FromSeconds(1));

            // check that second transaction is not received when subscription suspended
            var transactionCount2 = transactions.Count;

            // resume subscription
            await subscriptionClient.Net.Resume();

            await Task.Delay(TimeSpan.FromSeconds(1));

            // run contract function to create third transaction
            await _tonClient.Processing.ProcessMessage(new ParamsOfProcessMessage
            {
                MessageEncodeParams = new ParamsOfEncodeMessage
                {
                    Abi    = TestsEnv.Packages.Hello.Abi,
                    Signer = new Signer.Keys {
                        KeysAccessor = keys
                    },
                    Address = address,
                    CallSet = new CallSet {
                        FunctionName = "touch"
                    }
                },
                SendEvents = false
            });

            // give some time for subscription to receive all data
            await Task.Delay(TimeSpan.FromSeconds(1));

            await subscriptionClient.Net.Unsubscribe(new ResultOfSubscribeCollection
            {
                Handle = handle1.Handle
            });

            await subscriptionClient.Net.Unsubscribe(new ResultOfSubscribeCollection
            {
                Handle = handle2.Handle
            });

            //check count before suspending
            transactionCount1.Should().Be(1);

            //check count before resume
            transactionCount2.Should().Be(1);

            // check that third transaction is now received after resume
            transactions.Count.Should().Be(3);
            transactions[0].Should().NotBe(transactions[2]);

            // check errors
            errorCodes.Count.Should().Be(4);
            errorCodes.Take(2).Should().AllBeEquivalentTo((uint)NetErrorCode.NetworkModuleSuspended);
            errorCodes.TakeLast(2).Should().AllBeEquivalentTo((uint)NetErrorCode.NetworkModuleResumed);
        }
Exemplo n.º 4
0
 /// <summary>
 /// <para>Encodes an ABI-compatible message</para>
 /// <para>Allows to encode deploy and function call messages,</para>
 /// <para>both signed and unsigned.</para>
 /// <para>Use cases include messages of any possible type:</para>
 /// <para>- deploy with initial function call (i.e. `constructor` or any other function that is used for some kind</para>
 /// <para>of initialization);</para>
 /// <para>- deploy without initial function call;</para>
 /// <para>- signed/unsigned + data for signing.</para>
 /// <para>`Signer` defines how the message should or shouldn't be signed:</para>
 /// <para>`Signer::None` creates an unsigned message. This may be needed in case of some public methods,</para>
 /// <para>that do not require authorization by pubkey.</para>
 /// <para>`Signer::External` takes public key and returns `data_to_sign` for later signing.</para>
 /// <para>Use `attach_signature` method with the result signature to get the signed message.</para>
 /// <para>`Signer::Keys` creates a signed message with provided key pair.</para>
 /// <para>[SOON] `Signer::SigningBox` Allows using a special interface to implement signing</para>
 /// <para>without private key disclosure to SDK. For instance, in case of using a cold wallet or HSM,</para>
 /// <para>when application calls some API to sign data.</para>
 /// <para>There is an optional public key can be provided in deploy set in order to substitute one</para>
 /// <para>in TVM file.</para>
 /// <para>Public key resolving priority:</para>
 /// <para>1. Public key from deploy set.</para>
 /// <para>2. Public key, specified in TVM file.</para>
 /// <para>3. Public key, provided by signer.</para>
 /// </summary>
 public async Task <ResultOfEncodeMessage> EncodeMessage(ParamsOfEncodeMessage @params, CancellationToken cancellationToken = default)
 {
     return(await _tonClientAdapter.Request <ParamsOfEncodeMessage, ResultOfEncodeMessage>("abi.encode_message", @params, cancellationToken));
 }
Exemplo n.º 5
0
        public async Task Consume(ConsumeContext <FreeTonDeploy> context)
        {
            var cancellationToken = context.CancellationToken;
            var phrase            = context.Message.Phrase;
            var keyPair           = await _tonClient.Crypto.MnemonicDeriveSignKeys(new ParamsOfMnemonicDeriveSignKeys { Phrase = phrase },
                                                                                   cancellationToken);

            var contract = await _tonPackageManager.LoadPackage(SafeMultisigWallet);

            var paramsOfEncodedMessage = new ParamsOfEncodeMessage {
                Abi       = contract.Abi,
                DeploySet = new DeploySet {
                    Tvc         = contract.Tvc,
                    InitialData = new { }.ToJsonElement()
                },
                CallSet = new CallSet {
                    FunctionName = "constructor",
                    Input        = new { owners = new[] { $"0x{keyPair.Public}" }, reqConfirms = 0 }.ToJsonElement()
                },
                Signer = new Signer.Keys {
                    KeysAccessor = keyPair
                },
                ProcessingTryIndex = 1
            };

            var encodeMessage = await _tonClient.Abi.EncodeMessage(paramsOfEncodedMessage, cancellationToken);

            var address = encodeMessage.Address;

            var result = await _tonClient.Net.QueryCollection(new ParamsOfQueryCollection {
                Collection = "accounts",
                Filter     = new { id = new { eq = address } }.ToJsonElement(),
                Result     = "acc_type balance"
            }, cancellationToken);

            if (result.Result.Length == 0)
            {
                await context.RespondAsync(new FreeTonDeployResult {
                    Success = false,
                    Balance = 0,
                    Error   = $"You need to transfer at least 0.5 tokens for deploy to {address}",
                    Address = address,
                    KeyPair = keyPair
                });

                return;
            }

            var account = result.Result[0];
            var balance = new BigInteger(Convert.ToUInt64(account.Get <string>("balance"), 16)).ToDecimalBalance();
            var accType = account.Get <int>("acc_type");

            switch (accType)
            {
            case 0 when balance < (decimal)0.5:
                await context.RespondAsync(new FreeTonDeployResult {
                    Success = false,
                    Error   = $"You need to transfer at least 0.5 tokens for deploy to {address}",
                    Balance = balance,
                    Address = address,
                    KeyPair = keyPair
                });

                return;

            case 1:
                await context.RespondAsync(new FreeTonDeployResult {
                    Success = true,
                    Balance = balance,
                    Address = address,
                    KeyPair = keyPair
                });

                return;
            }

            await _tonClient.Processing.ProcessMessage(new ParamsOfProcessMessage {
                SendEvents          = false,
                MessageEncodeParams = paramsOfEncodedMessage
            }, cancellationToken : cancellationToken);

            var accBalance = await _tonClient.Net.QueryCollection(new ParamsOfQueryCollection {
                Collection = "accounts",
                Filter     = new { id = new { eq = address } }.ToJsonElement(),
                Result     = "balance"
            }, cancellationToken);

            balance = new BigInteger(Convert.ToUInt64(accBalance.Result[0].Get <string>("balance"), 16)).ToDecimalBalance();
            await context.RespondAsync(new FreeTonDeployResult {
                Success = true,
                Balance = balance,
                Address = address,
                KeyPair = keyPair
            });
        }