Skip to content

Commit

Permalink
Add fee calculations on each send (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
dangershony authored Oct 24, 2023
1 parent 98d31bb commit 03a0801
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 64 deletions.
48 changes: 40 additions & 8 deletions src/Angor/Client/Pages/Create.razor
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
@using Blockcore.NBitcoin
@using Blockcore.NBitcoin.DataEncoders

@inherits BaseComponent

@inject HttpClient Http
@inject IDerivationOperations _derivationOperations
@inject IWalletStorage _walletStorage;
Expand Down Expand Up @@ -118,6 +120,13 @@

<hr>

<div class="mb-3">
<label for="feeRange" class="form-label">Feerate for @feeData.SelectedFeeEstimation.Confirmations blocks is @feeData.SelectedFeeEstimation.FeeRate sats</label>
<input type="range" class="form-range" id="feeRange" @bind="feeData.FeePosition" @oninput="FeeRangeChanged" min="@feeData.FeeMin" max="@feeData.FeeMax">
</div>

<hr>

<h6 class="mt-3 mb-2">Stages</h6>
@foreach (var stage in project.Stages)
{
Expand Down Expand Up @@ -145,14 +154,15 @@

@code {

private NotificationComponent notificationComponent;

private bool sendConfirmModal;
private bool hasWallet;
private bool showCreateModal;

Transaction unsignedTransaction;
Transaction signedTransaction;

private FeeData feeData = new();

private ProjectInfo project = new ProjectInfo
{
StartDate = DateTime.UtcNow,
Expand Down Expand Up @@ -219,14 +229,16 @@

var operationResult = await notificationComponent.LongOperation(async () =>
{
var network = _NetworkConfiguration.GetNetwork();
var accountInfo = storage.GetAccountInfo(network.Name);

var feeEstimation = await _WalletOperations.GetFeeEstimationAsync();
var fetchFees = await _WalletOperations.GetFeeEstimationAsync();
feeData.FeeEstimations.Fees.Clear();
feeData.FeeEstimations.Fees.AddRange(fetchFees);
feeData.SelectedFeeEstimation = feeData.FeeEstimations.Fees.First();

var transaction = _founderTransactionActions.CreateNewProjectTransaction(project.FounderKey, _derivationOperations.AngorKeyToScript(project.ProjectIdentifier), 10000);
unsignedTransaction = _founderTransactionActions.CreateNewProjectTransaction(project.FounderKey, _derivationOperations.AngorKeyToScript(project.ProjectIdentifier), 10000);

signedTransaction = _WalletOperations.AddInputsAndSignTransaction(accountInfo.GetNextChangeReceiveAddress(), transaction, _walletStorage.GetWallet(), accountInfo, feeEstimation.First());
signedTransaction = _WalletOperations.AddInputsAndSignTransaction(accountInfo.GetNextChangeReceiveAddress(), unsignedTransaction, _walletStorage.GetWallet(), accountInfo, feeData.SelectedFeeEstimation);

project.TransactionId = signedTransaction.GetHash().ToString();

Expand All @@ -244,14 +256,34 @@
}
}

private void FeeRangeChanged(ChangeEventArgs e)
{
var selected = e.Value?.ToString();

if (selected != null)
{
if (int.TryParse(selected, out int res))
{
if (res <= feeData.FeeEstimations.Fees.Count)
{
feeData.SelectedFeeEstimation = feeData.FeeEstimations.Fees.OrderBy(fee => fee.Confirmations).ToList()[res - 1];

var accountInfo = storage.GetAccountInfo(network.Name);

signedTransaction = _WalletOperations.AddInputsAndSignTransaction(accountInfo.GetNextChangeReceiveAddress(), unsignedTransaction, _walletStorage.GetWallet(), accountInfo, feeData.SelectedFeeEstimation);

StateHasChanged();
}
}
}
}

private async Task Send()
{
var operationResult = await notificationComponent.LongOperation(async () =>
{
showCreateModal = false;

var network = _NetworkConfiguration.GetNetwork();

var response = await _WalletOperations.PublishTransactionAsync(network, signedTransaction);

if (!response.Success)
Expand Down
88 changes: 57 additions & 31 deletions src/Angor/Client/Pages/Invest.razor
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@

<p class="mb-1"><strong>Miner fee:</strong> [Your fee here]</p>
<p class="mb-1"><strong>Angor fee:</strong> 1000 sats</p>

<hr>

<div class="mb-3">
<label for="feeRange" class="form-label">Feerate for @feeData.SelectedFeeEstimation.Confirmations blocks is @feeData.SelectedFeeEstimation.FeeRate sats</label>
<input type="range" class="form-range" id="feeRange" @bind="feeData.FeePosition" @oninput="FeeRangeChanged" min="@feeData.FeeMin" max="@feeData.FeeMax">
</div>

<hr>

Expand Down Expand Up @@ -164,7 +171,13 @@
private ProjectInfo project;
private bool showCreateModal;
Transaction signedTransaction;
Transaction unSignedTransaction;
//InvestorContext context;
SignatureInfo recoverySigs;

private FeeData feeData = new();


protected override async Task OnInitializedAsync()
{
Expand Down Expand Up @@ -275,46 +288,23 @@

var operationResult = await notificationComponent.LongOperation(async () =>
{
var network = _NetworkConfiguration.GetNetwork();
var accountInfo = storage.GetAccountInfo(network.Name);

var feeEstimation = await _WalletOperations.GetFeeEstimationAsync();
var fetchFees = await _WalletOperations.GetFeeEstimationAsync();
feeData.FeeEstimations.Fees.Clear();
feeData.FeeEstimations.Fees.AddRange(fetchFees);
feeData.SelectedFeeEstimation = feeData.FeeEstimations.Fees.First();

var investorKey = _derivationOperations.DeriveInvestorKey(_walletStorage.GetWallet(), project.FounderKey);

InvestorContext context = new InvestorContext
{
ProjectInfo = project,
ChangeAddress = accountInfo.GetNextChangeReceiveAddress(),
InvestorKey = investorKey,
};


if (Investment.IsSeeder)
{
var seederHash = _derivationOperations.DeriveSeederSecretHash(_walletStorage.GetWallet(), project.FounderKey);

context.InvestorSecretHash = seederHash;
}

var transaction = _InvestorTransactionActions.CreateInvestmentTransaction(context.ProjectInfo, context.InvestorKey, Money.Coins(Investment.InvestmentAmount).Satoshi);

signedTransaction = _WalletOperations.AddInputsAndSignTransaction(context.ChangeAddress, transaction, _walletStorage.GetWallet(), accountInfo, feeEstimation.First());
unSignedTransaction = _InvestorTransactionActions.CreateInvestmentTransaction(project, investorKey, Money.Coins(Investment.InvestmentAmount).Satoshi);

// remove signatures when requesting founder to sign
var strippedInvestmentTransaction = network.CreateTransaction(signedTransaction.ToHex());
strippedInvestmentTransaction.Inputs.ForEach(f => f.WitScript = Blockcore.Consensus.TransactionInfo.WitScript.Empty);

recoverySigs = await _SignService.GetInvestmentSigsAsync(new SignRecoveryRequest
{
ProjectIdentifier = project.ProjectIdentifier,
InvestmentTransaction = strippedInvestmentTransaction.ToHex(network.Consensus.ConsensusFactory)
});

// validate the signatures
_InvestorTransactionActions.CheckInvestorRecoverySignatures(context.ProjectInfo, signedTransaction, recoverySigs);

// link the trx to the signatures
recoverySigs.TransactionId = signedTransaction.GetHash().ToString();
signedTransaction = _WalletOperations.AddInputsAndSignTransaction(accountInfo.GetNextChangeReceiveAddress(), unSignedTransaction, _walletStorage.GetWallet(), accountInfo, feeData.SelectedFeeEstimation);

return new OperationResult { Success = true };

Expand All @@ -330,13 +320,49 @@
}
}

private void FeeRangeChanged(ChangeEventArgs e)
{
var selected = e.Value?.ToString();

if (selected != null)
{
if (int.TryParse(selected, out int res))
{
if (res <= feeData.FeeEstimations.Fees.Count)
{
feeData.SelectedFeeEstimation = feeData.FeeEstimations.Fees.OrderBy(fee => fee.Confirmations).ToList()[res - 1];

var accountInfo = storage.GetAccountInfo(network.Name);

signedTransaction = _WalletOperations.AddInputsAndSignTransaction(accountInfo.GetNextChangeReceiveAddress(), unSignedTransaction, _walletStorage.GetWallet(), accountInfo, feeData.SelectedFeeEstimation);

StateHasChanged();
}
}
}
}

private async Task Send()
{
var operationResult = await notificationComponent.LongOperation(async () =>
{
showCreateModal = false;

// remove signatures when requesting founder to sign
var strippedInvestmentTransaction = network.CreateTransaction(signedTransaction.ToHex());
strippedInvestmentTransaction.Inputs.ForEach(f => f.WitScript = Blockcore.Consensus.TransactionInfo.WitScript.Empty);

recoverySigs = await _SignService.GetInvestmentSigsAsync(new SignRecoveryRequest
{
ProjectIdentifier = project.ProjectIdentifier,
InvestmentTransaction = strippedInvestmentTransaction.ToHex(network.Consensus.ConsensusFactory)
});

// validate the signatures
_InvestorTransactionActions.CheckInvestorRecoverySignatures(project, signedTransaction, recoverySigs);

var network = _NetworkConfiguration.GetNetwork();
// link the trx to the signatures
recoverySigs.TransactionId = signedTransaction.GetHash().ToString();

storage.AddOrUpdateSignatures(recoverySigs);

Expand Down
Loading

0 comments on commit 03a0801

Please sign in to comment.