# Ruby Swap Example
ABIs can be found [here](https://github.com/RubyExchange/contracts/tree/master/deployments/europa)
## Functions
[Ruby Swap](https://github.com/RubyExchange/contracts/blob/562e5564a572883cb36352dea3ac51e4e4b8f5a0/contracts/ruby_router/RubyRouter.sol#L68)
[Ruby Swap - getAmountsOut](https://github.com/RubyExchange/contracts/blob/562e5564a572883cb36352dea3ac51e4e4b8f5a0/contracts/amm/libraries/UniswapV2Library.sol#L102)
> This is example code showcasing how to setup swaps on Ruby.Exchange.
> Always double check addresses and ABIs
## Code Example
```typescript=
import { ethers, network } from "hardhat";
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/dist/src/signers";
import { BigNumber } from "ethers";
// Intentionally use deployed jsons rather than ethers/hardhat-deploy/typescript primitives
// so that this code can be more easily shared
import ERC20_ABI from "../../abi/@openzeppelin/contracts/token/ERC20/ERC20.sol/ERC20.json";
const RUBY_ROUTER_ADDR = require(`../../deployments/${network.name}/RubyRouter.json`).address;
const UNI_ROUTER_ADDR = require(`../../deployments/${network.name}/UniswapV2Router02.json`).address;
const NFT_ADMIN_ADDR = require(`../../deployments/${network.name}/RubyNFTAdmin.json`).address;
const STABLE_SWAP_ADDR = require(`../../deployments/${network.name}/RubyUSD4Pool.json`).address;
const USDP_ADDR = require(`../../deployments/${network.name}/RubyUSDP.json`).address;
const USDT_ADDR = require(`../../deployments/${network.name}/RubyUSDT.json`).address;
const RUBY_ADDR = require(`../../deployments/${network.name}/RubyToken.json`).address;
const ETHC_ADDR = "0xD2Aaa00700000000000000000000000000000000";
const RUBY_ROUTER_ABI = require(`../../deployments/${network.name}/RubyRouter.json`).abi;
const UNI_ROUTER_ABI = require(`../../deployments/${network.name}/UniswapV2Router02.json`).abi;
const NFT_ADMIN_ABI = require(`../../deployments/${network.name}/RubyNFTAdmin.json`).abi;
const STABLE_SWAP_ABI = require(`../../deployments/${network.name}/RubyUSD4Pool.json`).abi;
enum SwapType {
AMM,
STABLE_POOL,
};
enum AMMSwapType {
EXACT_TOKENS_FOR_TOKENS,
TOKENS_FOR_EXACT_TOKENS,
};
const approveERC20 = async (token: any, spenderAddr: string, amount: BigNumber) => {
const symbol = await token.symbol();
const decimals = await token.decimals();
console.log(`Aproving ${spenderAddr} to spend ${ethers.utils.formatUnits(amount, decimals)}${symbol}`);
const res = await token.approve(spenderAddr, amount);
await res.wait(1);
console.log("...approved");
};
const swapERC20ToUSDP = async (dryRun: boolean, erc20Addr: string, amountStr: string, signer: SignerWithAddress) => {
const account = signer;
let symbol;
let decimals;
let balance;
const tokenIn = new ethers.Contract(erc20Addr, ERC20_ABI, account); // with signer for approval
const tokenOut = new ethers.Contract(USDP_ADDR, ERC20_ABI, ethers.provider);
symbol = await tokenIn.symbol();
decimals = await tokenIn.decimals();
balance = await tokenIn.balanceOf(account.address);
const tokenInAmount = ethers.utils.parseUnits(amountStr, decimals);
console.log(`Current ${amountStr}${symbol} -> USDP (Starting ${symbol} balance: ${ethers.utils.formatUnits(balance, decimals)})`);
const nftAdmin = new ethers.Contract(NFT_ADMIN_ADDR, NFT_ADMIN_ABI, ethers.provider);
const ammRouter = new ethers.Contract(UNI_ROUTER_ADDR, UNI_ROUTER_ABI, ethers.provider);
const rubyRouter = new ethers.Contract(RUBY_ROUTER_ADDR, RUBY_ROUTER_ABI, account);
const feeMultiplier = await nftAdmin.calculateAmmSwapFeeDeduction(account.address);
const amountsOut = await ammRouter.getAmountsOut(tokenInAmount, [tokenIn.address, tokenOut.address], feeMultiplier);
const tokenOutAmount = amountsOut[amountsOut.length - 1];
symbol = await tokenOut.symbol();
decimals = await tokenOut.decimals();
balance = await tokenOut.balanceOf(account.address);
console.log(`Should recieve ${ethers.utils.formatUnits(tokenOutAmount, decimals)}${symbol} (Current ${symbol} balance: ${ethers.utils.formatUnits(balance, decimals)})`)
const blockNumber = await ethers.provider.getBlockNumber();
const blockData = await ethers.provider.getBlock(blockNumber);
const deadline = ethers.BigNumber.from(blockData.timestamp + 23600);
const swapDetails = {
ammSwaps: [
{
swapType: AMMSwapType.EXACT_TOKENS_FOR_TOKENS,
amountIn: tokenInAmount,
amountOut: tokenOutAmount,
path: [tokenIn.address, tokenOut.address],
to: rubyRouter.address,
deadline: deadline,
},
],
stableSwaps: [],
order: [SwapType.AMM],
};
if (dryRun) {
console.log("Not swapping (dry run)")
} else {
await approveERC20(tokenIn, rubyRouter.address, tokenInAmount);
console.log("Swapping")
const tx = await rubyRouter.swap(swapDetails);
console.log("...swapped")
}
symbol = await tokenIn.symbol();
decimals = await tokenIn.decimals();
balance = await tokenIn.balanceOf(account.address);
console.log(`Final ${symbol} balance: ${ethers.utils.formatUnits(balance, decimals)})`);
symbol = await tokenOut.symbol();
decimals = await tokenOut.decimals();
balance = await tokenOut.balanceOf(account.address);
console.log(`Final ${symbol} balance: ${ethers.utils.formatUnits(balance, decimals)})`);
}
const swapERC20ToUSDT = async (dryRun: boolean, erc20Addr: string, amountStr: string, signer: SignerWithAddress) => {
const account = signer;
let symbol;
let decimals;
let balance;
const tokenIn = new ethers.Contract(erc20Addr, ERC20_ABI, account); // with signer for approval
symbol = await tokenIn.symbol();
decimals = await tokenIn.decimals();
balance = await tokenIn.balanceOf(account.address);
const tokenInAmount = ethers.utils.parseUnits(amountStr, decimals);
console.log(`Current ${amountStr}${symbol} -> USDT (Starting ${symbol} balance: ${ethers.utils.formatUnits(balance, decimals)})`);
const stableTokenIn = new ethers.Contract(USDP_ADDR, ERC20_ABI, ethers.provider);
const stableTokenOut = new ethers.Contract(USDT_ADDR, ERC20_ABI, ethers.provider);
const nftAdmin = new ethers.Contract(NFT_ADMIN_ADDR, NFT_ADMIN_ABI, ethers.provider);
const ammRouter = new ethers.Contract(UNI_ROUTER_ADDR, UNI_ROUTER_ABI, ethers.provider);
const rubyStablePool = new ethers.Contract(STABLE_SWAP_ADDR, STABLE_SWAP_ABI, ethers.provider);
const rubyRouter = new ethers.Contract(RUBY_ROUTER_ADDR, RUBY_ROUTER_ABI, account);
const feeMultiplier = await nftAdmin.calculateAmmSwapFeeDeduction(account.address);
const amountsOut = await ammRouter.getAmountsOut(tokenInAmount, [tokenIn.address, stableTokenIn.address], feeMultiplier);
const stableTokenInAmount = amountsOut[amountsOut.length - 1];
const stableTokenInIndex = await rubyStablePool.getTokenIndex(stableTokenIn.address); // USDP
const stableTokenOutIndex = await rubyStablePool.getTokenIndex(stableTokenOut.address); // USDT
const stableTokenOutAmount = await rubyStablePool.calculateSwap(
stableTokenInIndex,
stableTokenOutIndex,
stableTokenInAmount,
);
symbol = await stableTokenOut.symbol();
decimals = await stableTokenOut.decimals();
balance = await stableTokenOut.balanceOf(account.address);
console.log(`Should recieve ${ethers.utils.formatUnits(stableTokenOutAmount, decimals)}${symbol} (Current ${symbol} balance: ${ethers.utils.formatUnits(balance, decimals)})`)
const blockNumber = await ethers.provider.getBlockNumber();
const blockData = await ethers.provider.getBlock(blockNumber);
const deadline = ethers.BigNumber.from(blockData.timestamp + 23600);
const swapDetails = {
ammSwaps: [
{
swapType: AMMSwapType.EXACT_TOKENS_FOR_TOKENS,
amountIn: tokenInAmount,
amountOut: stableTokenInAmount,
path: [tokenIn.address, stableTokenIn.address],
to: rubyRouter.address,
deadline: deadline,
},
],
stableSwaps: [
{
stablePool: rubyStablePool.address,
tokenIndexFrom: stableTokenInIndex,
tokenIndexTo: stableTokenOutIndex,
dx: stableTokenInAmount,
minDy: stableTokenOutAmount,
deadline: deadline,
},
],
order: [SwapType.AMM, SwapType.STABLE_POOL],
};
if (dryRun) {
console.log("Not swapping (dry run)")
} else {
await approveERC20(tokenIn, rubyRouter.address, tokenInAmount);
console.log("Swapping")
const tx = await rubyRouter.swap(swapDetails);
console.log("...swapped")
}
symbol = await tokenIn.symbol();
decimals = await tokenIn.decimals();
balance = await tokenIn.balanceOf(account.address);
console.log(`Final ${symbol} balance: ${ethers.utils.formatUnits(balance, decimals)})`);
symbol = await stableTokenOut.symbol();
decimals = await stableTokenOut.decimals();
balance = await stableTokenOut.balanceOf(account.address);
console.log(`Final ${symbol} balance: ${ethers.utils.formatUnits(balance, decimals)})`);
};
const main = async () => {
const signer: SignerWithAddress = (await ethers.getSigners())[0];
if (network.name == 'localhost' || network.name == 'hardhat' || network.name == 'rinkeby' || network.name == 'mainnet' || network.name == 'goerli') {
throw new Error("Only supported on sChains (with ETHC)")
}
console.log(`Swapping from ${signer.address} on ${network.name}`);
await swapERC20ToUSDT(true, // true to simulate and not swap
ETHC_ADDR, "0.001", signer);
await swapERC20ToUSDT(true, // true to simulate and not swap
RUBY_ADDR, "1", signer);
await swapERC20ToUSDP(true, // true to simulate and not swap
RUBY_ADDR, "1", signer);
};
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
```