This package serves as a library that can be published to npm and imported into widget/package
to provide the necessary logic to perform swaps from Native Currency to any other token provided it is supported by the dex in questions.
- Uniswap (v2 & v3)
Import layer2 into widget/package using
yarn link
.
inside layer2
root folder:
yarn install
yarn link
yarn start
inside widget/package
:
yarn link layer2
yarn start:l2
download directly from Github until v1 is published to NPM.
inside widget/package
:
yarn add @Exohood Fiat to Crypto/layer2#main
- Wrap your application with the Layer2Provider.
import { L2Provider } from 'layer2';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<L2Provider>
<App />
</L2Provider>
</React.StrictMode>
);
The L2Provider is nothing but a wrapper for @usedapp/core's UseDApp documentation
- Get a Quote
If a user does not have their wallet ocnnected we can still fetch quote data. (
<QuoteResult>
returned bygetQuote()
does not containcalldata
necessary to perform a swap, only quote data for display purposes).
const { getQuote } from "layer2";
const newQuote = await getQuote(
tokenIn,
tokenOut,
amount,
false,
apiKey,
abortSignal
);
// Returns
// >>
interface QuoteDetails {
blockNumber: string;
amount: string;
amountDecimals: string;
quote: string;
quoteDecimals: string;
quoteGasAdjusted: string;
quoteGasAdjustedDecimals: string;
gasUseEstimateQuote: string;
gasUseEstimateQuoteDecimals: string;
gasUseEstimate: string;
gasUseEstimateUSD: string;
gasPriceWei: string;
route: any[][];
routeString: string;
quoteId: string;
}
- Get Swap Params
If a user has connected their wallet, we have all the data needed by the quote api to return to us the
calldata
necessary to perform a swap.
const { getSwapParams, useSendTransaction, useLayer2, formatEther } from "layer2";
const App = ()=> {
const { sendTransaction, state } = useSendTransaction();
const { account } = useLayer2()
const balance = useEtherBalance(account);
const res = await getSwapParams(
Number(formatEther(balance)),
tokenIn,
tokenOut,
amount,
account, // or specify custom receiver address
false,
{
1, // 1%
200, // 200 seconds
},
apiKey
);
// Returns
// >>
interface SwapParams {
data: string; // route.methodParameters.calldata,
to: string; // V3_SWAP_ROUTER_ADDRESS,
value: BigNumber; // BigNumber.from(route.methodParameters.value),
gasPrice: BigNumber; // this we can choose not to pass to user's wallet, the wallet make a more recent estimate anyway
}
// Take what we need from the response and submit the transaction
const {data, to, value } = res;
sendTransaction({
data: data,
to: to,
value: value,
from: receiverAddress,
});
// we can also track the current status of the transaction in the UI.
return (
<div>
{state.status === "Mining" && (<p>Transaction pending...</p>)}
{state.status === "Success" && (<p>Success!! 🚀</p>)}
</div>
)
- EnsContext
Since many users might connect a wallet that has either an ens name or an ens avatar registered to it, we would like to show this to the user. The items returned by the context are only relevant to the wallet currently connected to the dApp.
Usage
import {shortenIfAddress, useEns, useLayer2} from "layer2"
const App = ()=> {
const { ensName, ensAvatar } = useEns(); // >> <string | null>
const { account } = useLayer2();
return (
<p>Your wallet: {ensName ?? shortenIfAddress(account)} </p>
{ensAvatar && <img src={ensAvatar} alt="avatar image" />}
)
// Your wallet: vitalik.eth or 0xC54...5a48
// 🤖 or [nothing]
}
- Inidividual ENS hooks
There are hooks that resolve for ens that we might want to use for wallets other that the one connected to the dAPP.
- useEnsName
Usage
const address = '0xC54070dA79E7E3e2c95D3a91fe98A42000e65a48';
const name = useEnsName(address); // >> <string | null>
- useEnsAddress
Usage
const name = 'vitalik.eth';
const address = useEnsAddress(name); // >> <string | null>
- useEnsAvatar
Usage
const name = 'vitalik.eth';
const address = '0xC54070dA79E7E3e2c95D3a91fe98A42000e65a48';
const address = useEnsAvatar([name, address]); // >> <string | null>
// this hook wil attempt to resolve each item in the array until it finds something
- addTokenToMetamask
Usage
const token = {
name: "Dai Stablecoin",
address: "0x6B175474E89094C44Da98b954EedeAC495271d0F",
symbol: "DAI",
decimals: 18,
chainId: 1,
logoURI: "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x6B175474E89094C44Da98b954EedeAC495271d0F/logo.png"
}
const { addToken, success } useAddTokenToMetamask(token);
return (
<>
<button onClick={addToken}>
add DAI to wallet
</button>
{success && <p>Success!! 🥳</p>}
</>
)
- uriToHttp
Since many assets in the web3 ecosystem are stored on ipfs/ arweave or other distributed storage solutions, we would like to convert any URLs using such protocols to one using https so that we may reliably retrieve said asset from all browsers. (not everyone has ipfs support set up in their browser)
Usage
import { uriToHttp } from 'layer2';
const httpsArray = uriToHttp(
'ipfs://QmNa8mQkrNKp1WEEeGjFezDmDeodkWRevGFN8JCV7b4Xir'
);
console.log(httpsArray[0]);
// https://cloudflare-ipfs.com/ipfs/QmNa8mQkrNKp1WEEeGjFezDmDeodkWRevGFN8JCV7b4Xir/
Stack
Coverage
Coverage is collected from the following files:
- src/core/core.tsx
- src/core/utils.ts
All [Quote API](https://github.com/Exohood Fiat to Crypto/routing-api) routes are mocked using mock service worker inside test/mocks/handlers.ts
.
There are, however some caveats to this:
-
"Happy paths" are accurately mocked. ie. the mock servcie worker will behave exactly like the actual API if conditions for success are met.
-
"Unhappy paths" are not accurately mocked as this would require implementing all the API logic again in this repo just for the sake of testing. Furthermore, this would be pretty pointless anyway since the purpose of these tests are not to test how the API responds, but instead are meant to test how this SDK handles those responses.
To run the tests locally, fromt eh root folder, run:
yarn test