Skip to content

Commit

Permalink
fix: amount to receive (#196)
Browse files Browse the repository at this point in the history
<!--- Provide a general summary of your changes in the Title above -->

## Description

Fixes displayed amount to receive due to double subtraction over the
already subtracted value

<!--- Describe your changes in detail -->

## Related Issue Or Context

<!--- If suggesting a new feature or change, please discuss it in an
issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps
to reproduce -->
<!--- Otherwise, describe context and motivation for change here -->

Closes: #192 

## How Has This Been Tested? Testing details.

<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran
to -->
<!--- see how your change affects other areas of the code, etc. -->

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes
that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->

- [ ] I have commented my code, particularly in hard-to-understand
areas.
- [ ] I have ensured that all acceptance criteria (or expected behavior)
from issue are met
- [ ] I have updated the documentation locally and in sygma-docs.
- [ ] I have added tests to cover my changes.
- [ ] I have ensured that all the checks are passing and green, I've
signed the CLA bot

---------

Co-authored-by: Saad Ahmed Siddiqui <[email protected]>
Co-authored-by: Anton Lykhoyda <[email protected]>
Co-authored-by: Filip Štoković <[email protected]>
  • Loading branch information
4 people authored Jun 11, 2024
1 parent be23500 commit 8c2cdad
Show file tree
Hide file tree
Showing 12 changed files with 371 additions and 189 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ import { customElement, property, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { when } from 'lit/directives/when.js';
import { networkIconsMap } from '../../assets';
import { DEFAULT_ETH_DECIMALS } from '../../constants';
import { DEFAULT_ETH_DECIMALS, INPUT_DEBOUNCE_TIME } from '../../constants';
import {
BALANCE_UPDATE_KEY,
TokenBalanceController
} from '../../controllers/wallet-manager/token-balance';
import { tokenBalanceToNumber } from '../../utils/token';
import type { DropdownOption } from '../common/dropdown/dropdown';
import { BaseComponent } from '../common/base-component';
import { debounce } from '../../utils';
import { styles } from './styles';

@customElement('sygma-resource-amount-selector')
Expand Down Expand Up @@ -67,9 +68,7 @@ export class ResourceAmountSelector extends BaseComponent {
}
};

_onInputAmountChangeHandler = (event: Event): void => {
let { value } = event.target as HTMLInputElement;

_onInputAmountChangeHandler = (value: string): void => {
if (value === '') {
value = '0';
}
Expand All @@ -88,6 +87,11 @@ export class ResourceAmountSelector extends BaseComponent {
}
};

debouncedHandler = debounce(
this._onInputAmountChangeHandler,
INPUT_DEBOUNCE_TIME
);

requestUpdate(
name?: PropertyKey,
oldValue?: unknown,
Expand Down Expand Up @@ -200,7 +204,10 @@ export class ResourceAmountSelector extends BaseComponent {
type="number"
class="amountSelectorInput"
placeholder="0.000"
@input=${this._onInputAmountChangeHandler}
@input=${(event: Event) => {
this.debouncedHandler((event.target as HTMLInputElement).value);
}}
.disabled=${this.disabled}
.value=${this.amount}
/>
<section class="selectorSection">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import '../../../context/wallet';
import { choose } from 'lit/directives/choose.js';
import { when } from 'lit/directives/when.js';
import type { Eip1193Provider } from 'packages/widget/src/interfaces';
import type { PropertyValues } from '@lit/reactive-element';
import {
Expand All @@ -22,7 +21,6 @@ import '../../network-selector';
import { BaseComponent } from '../../common';
import { Directions } from '../../network-selector/network-selector';
import { WalletController } from '../../../controllers';
import { tokenBalanceToNumber } from '../../../utils/token';
import { styles } from './styles';

@customElement('sygma-fungible-transfer')
Expand Down Expand Up @@ -103,29 +101,6 @@ export class FungibleTokenTransfer extends BaseComponent {
}
};

renderAmountOnDestination(): HTMLTemplateResult | null {
if (
this.transferController.selectedResource &&
this.transferController.pendingTransferTransaction !== undefined
) {
const { decimals, symbol } = this.transferController.selectedResource;
return html`
<div class="amountOnDestination">
<span> Amount to receive: </span>
<span>
${tokenBalanceToNumber(
this.transferController.resourceAmount,
decimals!,
4
)}
${symbol}
</span>
</div>
`;
}
return null;
}

renderTransferStatus(): HTMLTemplateResult {
return html` <section>
<sygma-transfer-status
Expand Down Expand Up @@ -181,7 +156,8 @@ export class FungibleTokenTransfer extends BaseComponent {
<sygma-resource-amount-selector
.sourceDomainConfig=${this.transferController.sourceDomainConfig}
.disabled=${!this.transferController.sourceNetwork ||
!this.transferController.destinationNetwork}
!this.transferController.destinationNetwork ||
this.transferController.isBuildingTransactions}
.resources=${this.transferController.supportedResources}
.onResourceSelected=${this.transferController.onResourceSelected}
>
Expand All @@ -196,10 +172,8 @@ export class FungibleTokenTransfer extends BaseComponent {
</sygma-address-input>
</section>
<section>
${when(this.transferController.destinationAddress, () =>
this.renderAmountOnDestination()
)}
<sygma-fungible-transfer-detail
.amountToReceive=${this.transferController.resourceAmountToDisplay}
.estimatedGasFee=${this.transferController.estimatedGas}
.selectedResource=${this.transferController.selectedResource}
.fee=${this.transferController.fee}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ export class FungibleTransferDetail extends BaseComponent {
@property({ type: Object })
selectedResource?: Resource;

@property({ type: Object })
amountToReceive!: BigNumber;

@property({ type: Object })
sourceDomainConfig?: BaseConfig<Network>;

Expand Down Expand Up @@ -101,6 +104,20 @@ export class FungibleTransferDetail extends BaseComponent {
render(): HTMLTemplateResult {
return html`
<section class="transferDetail">
${when(
this.fee !== null,
() =>
html` <div class="transferDetailContainer">
<div class="transferDetailContainerLabel">Amount to receive:</div>
<div class="transferDetailContainerValue">
${tokenBalanceToNumber(
this.amountToReceive,
this.selectedResource?.decimals as number
)}
${this.selectedResource?.symbol}
</div>
</div>`
)}
${when(
this.fee !== null,
() =>
Expand Down
2 changes: 2 additions & 0 deletions packages/widget/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ export const SUBSTRATE_RPCS: {
2035: 'wss://phala.api.onfinality.io/public-ws'
}
};

export const INPUT_DEBOUNCE_TIME = 600;
114 changes: 68 additions & 46 deletions packages/widget/src/controllers/transfers/evm/build.ts
Original file line number Diff line number Diff line change
@@ -1,89 +1,111 @@
import {
EVMAssetTransfer,
FeeHandlerType,
type PercentageFee
FeeHandlerType
} from '@buildwithsygma/sygma-sdk-core';
import type {
Domain,
Environment,
EvmFee,
PercentageFee
} from '@buildwithsygma/sygma-sdk-core';
import { Web3Provider } from '@ethersproject/providers';
import type { UnsignedTransaction, BigNumber } from 'ethers';
import { constants, utils } from 'ethers';
import { type FungibleTokenTransferController } from '../fungible-token-transfer';
import type { EvmWallet } from 'packages/widget/src/context';

type BuildEvmFungibleTransactionsArtifacts = {
pendingEvmApprovalTransactions: UnsignedTransaction[];
pendingTransferTransaction: UnsignedTransaction;
fee: EvmFee;
resourceAmount: BigNumber;
};

/**
* @dev If we did proper validation this shouldn't throw.
* Not sure how to handle if it throws :shrug:
*/
export async function buildEvmFungibleTransactions(
this: FungibleTokenTransferController
): Promise<void> {
//we already check that but this prevents those typescript errors
const provider = this.walletContext.value?.evmWallet?.provider;
const providerChaiId = this.walletContext.value?.evmWallet?.providerChainId;
const address = this.walletContext.value?.evmWallet?.address;
if (
!this.sourceNetwork ||
!this.destinationNetwork ||
!this.resourceAmount ||
!this.selectedResource ||
!this.destinationAddress ||
!provider ||
!address ||
providerChaiId !== this.sourceNetwork.chainId
) {
this.estimatedGas = undefined;
this.resetFee();
return;
}

export async function buildEvmFungibleTransactions({
evmWallet: { address, provider, providerChainId },
chainId,
destinationAddress,
resourceId,
resourceAmount,
env,
pendingEvmApprovalTransactions,
pendingTransferTransaction,
fee
}: {
evmWallet: EvmWallet;
chainId: number;
destinationAddress: string;
resourceId: string;
resourceAmount: BigNumber;
env: Environment;
pendingEvmApprovalTransactions: UnsignedTransaction[];
pendingTransferTransaction: UnsignedTransaction;
sourceNetwork: Domain | null;
fee: EvmFee;
}): Promise<BuildEvmFungibleTransactionsArtifacts> {
const evmTransfer = new EVMAssetTransfer();
await evmTransfer.init(new Web3Provider(provider, providerChaiId), this.env);
await evmTransfer.init(new Web3Provider(provider, providerChainId), env);

// Hack to make fungible transfer behave like it does on substrate side
// where fee is deducted from user inputted amount rather than added on top
const originalTransfer = await evmTransfer.createFungibleTransfer(
address,
this.destinationNetwork.chainId,
this.destinationAddress,
this.selectedResource.resourceId,
this.resourceAmount.toString()
chainId,
destinationAddress,
resourceId,
resourceAmount.toString()
);
const originalFee = await evmTransfer.getFee(originalTransfer);
// NOTE: for percentage fee, if both are equal, it means we can calculate the amount with fee avoiding second subtraction
const calculateAmountWithFee = originalFee.type === FeeHandlerType.PERCENTAGE;

//in case of percentage fee handler, we are calculating what amount + fee will result int user inputed amount
//in case of fixed(basic) fee handler, fee is taken from native token
if (originalFee.type === FeeHandlerType.PERCENTAGE) {
if (calculateAmountWithFee) {
const { lowerBound, upperBound, percentage } = originalFee as PercentageFee;
const userInputAmount = this.resourceAmount;
const userInputAmount = resourceAmount;
//calculate amount without fee (percentage)
const feelessAmount = userInputAmount
.mul(constants.WeiPerEther)
.div(utils.parseEther(String(1 + percentage)));

const calculatedFee = userInputAmount.sub(feelessAmount);
this.resourceAmount = feelessAmount;
resourceAmount = feelessAmount;
//if calculated percentage fee is less than lower fee bound, substract lower bound from user input. If lower bound is 0, bound is ignored
if (calculatedFee.lt(lowerBound) && lowerBound.gt(0)) {
this.resourceAmount = userInputAmount.sub(lowerBound);
resourceAmount = userInputAmount.sub(lowerBound);
}
//if calculated percentage fee is more than upper fee bound, substract upper bound from user input. If upper bound is 0, bound is ignored
if (calculatedFee.gt(upperBound) && upperBound.gt(0)) {
this.resourceAmount = userInputAmount.sub(upperBound);
resourceAmount = userInputAmount.sub(upperBound);
}
}

const transfer = await evmTransfer.createFungibleTransfer(
address,
this.destinationNetwork.chainId,
this.destinationAddress,
this.selectedResource.resourceId,
this.resourceAmount.toString()
chainId,
destinationAddress,
resourceId,
resourceAmount.toString()
);
this.fee = await evmTransfer.getFee(transfer);
this.pendingEvmApprovalTransactions = await evmTransfer.buildApprovals(
fee = await evmTransfer.getFee(transfer);

pendingEvmApprovalTransactions = await evmTransfer.buildApprovals(
transfer,
this.fee
fee
);
this.pendingTransferTransaction = await evmTransfer.buildTransferTransaction(

pendingTransferTransaction = await evmTransfer.buildTransferTransaction(
transfer,
this.fee
fee
);
await this.estimateGas();
this.host.requestUpdate();
return {
pendingEvmApprovalTransactions,
pendingTransferTransaction,
fee,
resourceAmount
};
}
23 changes: 22 additions & 1 deletion packages/widget/src/controllers/transfers/evm/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import {
Web3Provider,
type TransactionRequest
} from '@ethersproject/providers';
import type { PopulatedTransaction } from 'ethers';
import type { Eip1193Provider } from '../../../interfaces';
import { estimateEvmTransactionsGasCost } from '../../../utils/gas';
import {
FungibleTransferState,
type FungibleTokenTransferController
Expand All @@ -19,6 +22,7 @@ export async function executeNextEvmTransaction(
if (this.getTransferState() === FungibleTransferState.PENDING_APPROVALS) {
this.waitingUserConfirmation = true;
this.host.requestUpdate();
const transactions: PopulatedTransaction[] = [];
try {
const tx = await signer.sendTransaction(
this.pendingEvmApprovalTransactions[0] as TransactionRequest
Expand All @@ -28,14 +32,31 @@ export async function executeNextEvmTransaction(
this.host.requestUpdate();
await tx.wait();
this.pendingEvmApprovalTransactions.shift();

transactions.push(
...(this.pendingEvmApprovalTransactions as PopulatedTransaction[]),
this.pendingTransferTransaction as PopulatedTransaction
);

this.estimatedGas = await estimateEvmTransactionsGasCost(
this.sourceNetwork?.chainId as number,
this.walletContext.value?.evmWallet?.provider as Eip1193Provider,
this.walletContext.value?.evmWallet?.address as string,
transactions
);
} catch (e) {
console.log(e);
this.errorMessage = 'Approval transaction reverted or rejected';
} finally {
this.waitingUserConfirmation = false;
this.waitingTxExecution = false;
this.host.requestUpdate();
await this.estimateGas();
await estimateEvmTransactionsGasCost(
this.sourceNetwork?.chainId as number,
this.walletContext.value?.evmWallet?.provider as Eip1193Provider,
this.walletContext.value?.evmWallet?.address as string,
transactions
);
}
return;
}
Expand Down
Loading

0 comments on commit 8c2cdad

Please sign in to comment.