Skip to content

Commit

Permalink
Merge branch 'main' into fix/destination-address-format
Browse files Browse the repository at this point in the history
  • Loading branch information
wainola committed Jun 11, 2024
2 parents f102647 + 8c2cdad commit d6832cf
Show file tree
Hide file tree
Showing 16 changed files with 414 additions and 219 deletions.
4 changes: 2 additions & 2 deletions packages/widget/src/components/common/dropdown/dropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export class Dropdown extends BaseComponent {
this.selectedOption,
() =>
html`${this.selectedOption!.icon || networkIconsMap.default}
<span part="optionName" class="optionName">
<span part="optionName" class="optionName optionNameEllipsis">
${capitalize(this.selectedOption!.name)}
</span>`,
() =>
Expand All @@ -156,7 +156,7 @@ export class Dropdown extends BaseComponent {
() => customOptionHtml,
() => html`
${icon || ''}
<span class="optionName">${capitalize(name)}</span>
<span class="optionName optionNameEllipsis">${capitalize(name)}</span>
`
);
}
Expand Down
3 changes: 3 additions & 0 deletions packages/widget/src/components/common/dropdown/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const styles = css`
}
.dropdownTrigger {
white-space: nowrap;
height: 100%;
width: 100%;
display: flex;
Expand Down Expand Up @@ -95,6 +96,8 @@ export const styles = css`
.optionName {
margin-left: 0.5rem;
overflow: hidden;
text-overflow: ellipsis;
}
.dropdownLabel {
Expand Down
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,11 +204,15 @@ 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">
<dropdown-component
.placeholder=${'Select token'}
?disabled=${this.disabled}
.onOptionSelected=${this._onResourceSelectedHandler}
.options=${this._normalizeOptions()}
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,28 +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!
)}
${symbol}
</span>
</div>
`;
}
return null;
}

renderTransferStatus(): HTMLTemplateResult {
return html` <section>
<sygma-transfer-status
Expand Down Expand Up @@ -180,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 @@ -195,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
4 changes: 3 additions & 1 deletion packages/widget/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const DEFAULT_ETH_DECIMALS = 18;
export const MAINNET_EXPLORER_URL = 'https://scan.buildwithsygma.com/transfer/';
export const TESTNET_EXPLORER_URL =
'https://scan.test.buildwithsygma.com/transfer/';
export const CHAIN_ID_URL = 'https://chainid.network/chains_mini.json';
export const CHAIN_ID_URL = 'https://chainid.network/chains.json';

type WsUrl = `ws://${string}` | `wss://${string}`;
export const SUBSTRATE_RPCS: {
Expand All @@ -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
};
}
Loading

0 comments on commit d6832cf

Please sign in to comment.