const NETWORK_NEAR = "NEAR"; const NETWORK_ETH = "ETH"; const NETWORK_ZKSYNC = "ZKSYNC"; const NETWORK_AURORA = "AURORA"; const expandToken = (value, decimals) => { return new Big(value).mul(new Big(10).pow(decimals)); }; const getEVMAccountId = () => { if (ethers !== undefined) { return Ethers.send("eth_requestAccounts", [])[0] ?? ""; } return ""; }; const refReferralId = props.refReferralId ?? "ukraine"; const forceNetwork = NETWORK_AURORA || props.forceNetwork; const onDexDataLoad = (data) => { console.log("onDexDataLoad", data); State.update({ ...data, inputAsset: undefined, outputAsset: undefined, sender: getEVMAccountId(), }); }; State.init({ loadComplete: false, inputAssetModalHidden: true, outputAssetModalHidden: true, inputAssetAmount: 1, outputAssetAmount: 0, slippagetolerance: "0.5", reloadPools: false, estimate: {}, loadRes: (value) => { if (value.estimate === "NaN") value.estimate = 0; State.update({ estimate: value, outputAssetAmount: value === null ? "" : value.estimate, }); }, }); const css = fetch( "https://gist.githubusercontent.com/zavodil/5786d09502b0fbd042a920d804259130/raw/8dfc1154f6a9ebc5274463f60521385cc3728a19/swap.css" ).body; if (!css) return ""; if (!state.theme) { State.update({ theme: styled.div` ${css} `, }); } const Theme = state.theme; const currentAccountId = getEVMAccountId() !== "" ? getEVMAccountId() : context.accountId; const rearrangeAssets = () => { State.update({ inputAssetTokenId: state.outputAssetTokenId, outputAssetTokenId: state.inputAssetTokenId, inputAsset: undefined, outputAsset: undefined, inputAssetAmount: state.outputAssetAmount, outputAssetAmount: state.inputAssetAmount, approvalNeeded: undefined, }); }; const assetContainer = ( isInputAsset, assetData, amountName, assetNameOnClick ) => { if (!assetData) return; const useSpacer = !!isInputAsset; const assetContainerClass = useSpacer ? "asset-container-top" : "asset-container-bottom"; return ( <> <div class={`${assetContainerClass} asset-container`}> <div class="swap-currency-input"> <div class="swap-currency-input-block"> <div class="swap-currency-input-top"> <input class="input-asset-amount" nputmode="decimal" autocomplete="off" autocorrect="off" type="text" pattern="^[0-9]*[.,]?[0-9]*$" placeholder="0" minlength="1" maxlength="79" spellcheck="false" value={state[amountName]} /> <button class="input-asset-token" onClick={assetNameOnClick}> <span class="input-asset-token-menu"> <div class="input-asset-token-name"> <div class="input-asset-token-icon"> <img alt={`${assetData.metadata.name} logo`} src={assetData.metadata.icon} class="input-asset-token-icon-img" /> </div> <span class="input-asset-token-ticker"> {assetData.metadata.symbol} </span> </div> <svg width="12" height="7" viewBox="0 0 12 7" fill="none" xmlns="http://www.w3.org/2000/svg" class="input-asset-token-expand" > <path d="M0.97168 1L6.20532 6L11.439 1" stroke="#AEAEAE" ></path> </svg> </span> </button> </div> <div class="input-asset-details-container"> <div class="input-asset-details-row"> <div class="input-asset-details-price-container"> <div class="input-asset-details-price"> <div>${assetData.price}</div> </div> </div> <div class="input-asset-details-balance-container"> <div class="input-asset-details-balance-text"> Balance: {assetData.balance_hr} </div> {isInputAsset && Number(state.inputAssetAmount) !== Number(assetData.balance_hr_full) && ( <button class="input-asset-details-balance-button" onClick={() => State.update({ [amountName]: assetData.balance_hr_full ?? 0, }) } > Max </button> )} </div> </div> </div> {false && <div class="swap-currency-input-bottom"></div>} </div> </div> </div> {useSpacer ? spacerContainer : <></>} </> ); }; const spacerContainer = ( <div class="spacer-container"> <div class="spacer-block" onClick={rearrangeAssets}> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#0D111C" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <line x1="12" y1="5" x2="12" y2="19"></line> <polyline points="19 12 12 19 5 12"></polyline> </svg> </div> </div> ); const getRefTokenObject = (tokenId, assetData) => { return { id: tokenId, decimals: assetData.metadata.decimals, symbol: assetData.metadata.symbol, }; }; const tokenInApprovaleNeededCheck = () => { if (state.approvalNeeded === undefined) { if ( getEVMAccountId() && state.erc20Abi !== undefined && state.routerContract !== undefined && [NETWORK_ETH, NETWORK_ZKSYNC, NETWORK_AURORA].includes(state.network) ) { const ifaceErc20 = new ethers.utils.Interface(state.erc20Abi); const encodedTokenAllowancesData = ifaceErc20.encodeFunctionData( "allowance", [getEVMAccountId(), state.routerContract] ); return Ethers.provider() .call({ to: state.inputAssetTokenId, data: encodedTokenAllowancesData, }) .then((encodedTokenAllowanceHex) => { const tokenAllowance = ifaceErc20.decodeFunctionResult( "allowance", encodedTokenAllowanceHex ); if (tokenAllowance) { State.update({ approvalNeeded: new Big(tokenAllowance).toFixed() == "0", }); } }); } else { State.update({ approvalNeeded: false }); } } }; if ( state.network === NETWORK_ZKSYNC || state.network == NETWORK_ETH || state.network == NETWORK_AURORA ) { tokenInApprovaleNeededCheck(); } const canSwap = state.network && Number(state.inputAsset.balance_hr_full) >= Number(state.inputAssetAmount) && Number(state.inputAssetAmount ?? 0) > 0; const onCallTxComple = (tx) => { console.log("transactionHash", tx); State.update({ outputAsset: undefined, }); }; if (forceNetwork && state.network && forceNetwork !== state.network) { return ( <Theme> <div class="swap-main-container pt-5"> To proceed, kindly switch to {forceNetwork}. {!state.sender && ( <div class="swap-button-container"> <Web3Connect className="swap-button-enabled swap-button-text p-2" connectLabel="Connect with Web3" /> </div> )} <Widget src="tribos.near/widget/dex-data" props={{ onLoad: onDexDataLoad, NETWORK_NEAR, NETWORK_ETH, NETWORK_ZKSYNC, NETWORK_AURORA, }} /> </div> </Theme> ); } // return ( // <Theme> // <Widget // src="tribos.near/widget/dex-data" // props={{ // onLoad: onDexDataLoad, // NETWORK_NEAR, // NETWORK_ETH, // NETWORK_ZKSYNC, // NETWORK_AURORA, // }} // /> // {state.network && state.inputAsset && state.inputAssetTokenId && ( // <Widget // src="tribos.near/widget/AssetListModal" // props={{ // hidden: state.inputAssetModalHidden ?? true, // network: state.network, // assets: state.assets, // coinGeckoTokenIds: state.coinGeckoTokenIds, // selectedAssets: [state.inputAssetTokenId], // onClick: (tokenId) => { // State.update({ // inputAssetModalHidden: true, // inputAssetTokenId: tokenId, // inputAsset: null, // approvalNeeded: undefined, // }); // }, // onClose: () => State.update({ inputAssetModalHidden: true }), // }} // /> // )} // {state.network && state.outputAsset && state.outputAssetTokenId && ( // <Widget // src="tribos.near/widget/AssetListModal" // props={{ // hidden: state.outputAssetModalHidden ?? true, // assets: state.assets, // coinGeckoTokenIds: state.coinGeckoTokenIds, // network: state.network, // selectedAssets: [state.outputAssetTokenId], // onClick: (tokenId) => { // State.update({ // outputAssetModalHidden: true, // outputAssetTokenId: tokenId, // outputAsset: null, // }); // }, // onClose: () => State.update({ outputAssetModalHidden: true }), // }} // /> // )} // {!state.inputAsset && state.network && state.inputAssetTokenId && ( // <Widget // src="tribos.near/widget/TokenData" // props={{ // tokenId: state.inputAssetTokenId, // coinGeckoTokenId: state?.coinGeckoTokenIds?.[state.inputAssetTokenId], // network: state.network, // onLoad: (inputAsset) => { // console.log("TokenData onLoad inputAsset", inputAsset); // inputAsset.metadata.symbol = // inputAsset.metadata.symbol.toUpperCase(); // State.update({ inputAsset }); // }, // }} // /> // )} // {!state.outputAsset && state.network && state.outputAssetTokenId && ( // <Widget // src="tribos.near/widget/TokenData" // props={{ // tokenId: state.outputAssetTokenId, // coinGeckoTokenId: // state?.coinGeckoTokenIds?.[state.outputAssetTokenId], // network: state.network, // onLoad: (outputAsset) => { // console.log("TokenData onLoad outputAsset", outputAsset); // outputAsset.metadata.symbol = // outputAsset.metadata.symbol.toUpperCase(); // State.update({ outputAsset }); // }, // }} // /> // )} // {state.network === NETWORK_NEAR && // state.inputAsset && // state.outputAsset && ( // <Widget // src="weige.near/widget/ref-swap-getEstimate" // props={{ // loadRes: state.loadRes, // tokenIn: getRefTokenObject( // state.inputAssetTokenId, // state.inputAsset // ), // tokenOut: getRefTokenObject( // state.outputAssetTokenId, // state.outputAsset // ), // amountIn: state.inputAssetAmount ?? 0, // reloadPools: state.reloadPools, // setReloadPools: (value) => // State.update({ // reloadPools: value, // }), // }} // /> // )} // {state.network === NETWORK_ETH && // state.inputAssetTokenId && // state.outputAssetTokenId && // state.inputAssetTokenId !== state.outputAssetTokenId && // state.inputAssetAmount && // state.inputAsset && // state.inputAsset.metadata?.decimals && // state.outputAsset && // state.outputAsset.metadata?.decimals && ( // <> // <Widget // src="zavodil.near/widget/uni-v3-getEstimate" // props={{ // loadRes: state.loadRes, // tokenIn: state.inputAssetTokenId, // tokenOut: state.outputAssetTokenId, // tokenOutDecimals: state.outputAsset.metadata.decimals, // amountIn: expandToken( // state.inputAssetAmount, // state.inputAsset.metadata.decimals // ).toFixed(0), // reloadPools: state.reloadPools, // setReloadPools: (value) => // State.update({ // reloadPools: value, // }), // }} // /> // </> // )} // {(state.network === NETWORK_ZKSYNC || state.network == NETWORK_AURORA) && // state.inputAsset && // state.outputAsset && // state.inputAssetAmount && // state.outputAsset.price && // state.inputAsset.price && // state.loadRes({ // estimate: ( // (parseFloat(state.inputAssetAmount) * // parseFloat(state.inputAsset.price)) / // parseFloat(state.outputAsset.price) // ).toFixed(18), // })} // <div class="swap-root"> // <div class="swap-main-container"> // <div class="swap-main-column"> // <div class="swap-page"> // {state.network && state.dexName && ( // <span class="ps-2" style={{ color: "#7780a0" }}> // {state.dexName} ({state.network}) // </span> // )} // <div class="top-container"> // {assetContainer( // true, // state.inputAsset, // "inputAssetAmount", // () => { // State.update({ inputAssetModalHidden: false }); // } // )} // </div> // <div class="bottom-container"> // <div> // {assetContainer( // fasle, // state.outputAsset, // "outputAssetAmount", // () => { // State.update({ outputAssetModalHidden: false }); // } // )} // {!!state.outputAssetAmount && // state.inputAssetTokenId !== state.outputAssetTokenId && ( // <div class="swap-price-container"> // <div class="swap-price-block"> // <div class="swap-price-grid"> // <div class="swap-price-row"> // <div class="swap-price-details-container"> // <span> // <div class="swap-price-details-icon"> // <div> // <svg // xmlns="http://www.w3.org/2000/svg" // width="24" // height="24" // viewBox="0 0 24 24" // fill="none" // stroke="#98A1C0" // stroke-width="2" // stroke-linecap="round" // stroke-linejoin="round" // class="swap-price-details-svg" // > // <circle cx="12" cy="12" r="10"></circle> // <line // x1="12" // y1="16" // x2="12" // y2="12" // ></line> // <line // x1="12" // y1="8" // x2="12.01" // y2="8" // ></line> // </svg> // </div> // </div> // </span> // <div class="swap-price-details-text"> // <button class="swap-price-details-text-button"> // <div class="swap-price-details-rate"> // {Number(state.inputAssetAmount) === 0 || // Number(state.outputAssetAmount) === 0 // ? " " // : `1 ${ // state.inputAsset.metadata.symbol // } ≈ ${new Big( // state.outputAssetAmount ?? 0 // ) // .div(state.inputAssetAmount ?? 1) // .toFixed(4, 0)} // ${state.outputAsset.metadata.symbol}`} // </div> // <div class="swap-price-details-price"> // {Number(state.inputAssetAmount) === 0 || // Number(state?.outputAsset?.price) === 0 // ? "" // : `($${new Big( // state.outputAssetAmount ?? 0 // ) // .div(state.inputAssetAmount ?? 1) // .times(state?.outputAsset?.price ?? 1) // .toFixed(4)})`} // </div> // </button> // </div> // </div> // </div> // </div> // </div> // </div> // )} // </div> // <div class="swap-button-container"> // {state.approvalNeeded === true && ( // <button // class={"swap-button-enabled"} // onClick={() => { // state.callTokenApproval(state, () => { // onCallTxComple(); // tokenInApprovaleNeededCheck(); // }); // }} // > // <div class="swap-button-text"> // Approve {state.inputAsset.metadata.symbol} // </div> // </button> // )} // {state.approvalNeeded !== true && ( // <button // class={canSwap ? "swap-button-enabled" : "swap-button"} // onClick={() => { // if (canSwap) { // if (state.network === NETWORK_NEAR) { // state.callTx(state, onCallTxComple); // } else if (state.network === NETWORK_ZKSYNC) { // state.callTx(state, onCallTxComple); // } else if (state.network === NETWORK_ETH) { // state.callTx(state, onCallTxComple); // } else if (state.network === NETWORK_AURORA) { // state.callTx(state, onCallTxComple); // } // } // }} // > // <div class="swap-button-text">Swap</div> // </button> // )} // </div> // </div> // </div> // </div> // <div class="pt-3 text-secondary opacity-25 text-center"> // {currentAccountId && <p>Current account: {currentAccountId}</p>} // </div> // </div> // </div> // </Theme> // );