Skip to content

Commit

Permalink
Merge pull request #20 from GigaHierz/improvement/LILA-5458-Implement…
Browse files Browse the repository at this point in the history
…-new-Celo-compatible-version-of-OffsetHelper

P1: [LILA-5458] Implement new Celo-compatible version of OffsetHelper
  • Loading branch information
GigaHierz authored Sep 21, 2023
2 parents ee9a025 + f411e27 commit f98e5ef
Show file tree
Hide file tree
Showing 31 changed files with 5,823 additions and 1,416 deletions.
4 changes: 2 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
POLYGON_URL=https://matic-mainnet.chainstacklabs.com
RPC_ENDPOINT=https://forno.celo.org
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
POLYGONSCAN_KEY=abc123abc123abc123abc123abc123abc123abc
BLOCK_EXPLORER_API_KEY=B591PTIWMCIK4AJHVHZ8PYYA9E72EAA7UG
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ jobs:
- name: Test contract
run: yarn test
env:
POLYGON_URL: ${{ secrets.POLYGON_URL }}
RPC_ENDPOINT: ${{ secrets.RPC_ENDPOINT }}

- name: Test solidity-docgen builds
run: yarn doc

- name: Deploy contract
run: yarn hardhat deploy --network hardhat
env:
POLYGON_URL: ${{ secrets.POLYGON_URL }}
RPC_ENDPOINT: ${{ secrets.RPC_ENDPOINT }}
827 changes: 484 additions & 343 deletions contracts/OffsetHelper.sol

Large diffs are not rendered by default.

17 changes: 10 additions & 7 deletions contracts/OffsetHelperStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@

pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract OffsetHelperStorage is OwnableUpgradeable {
contract OffsetHelperStorage is Ownable {
// token symbol => token address
mapping(string => address) public eligibleTokenAddresses;
address public contractRegistryAddress =
0x263fA1c180889b3a3f46330F32a4a23287E99FC9;
address public sushiRouterAddress =
0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506;
mapping(address => address[]) public eligibleSwapPaths;
mapping(string => address[]) public eligibleSwapPathsBySymbol;

address[] public poolAddresses;
string[] public tokenSymbolsForPaths;
address[][] public paths;
address public dexRouterAddress;

// user => (token => amount)
mapping(address => mapping(address => uint256)) public balances;
}
92 changes: 56 additions & 36 deletions contracts/test/Swapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,47 @@ import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
contract Swapper {
using SafeERC20 for IERC20;

address public sushiRouterAddress =
0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506;
mapping(string => address) public tokenAddresses;

constructor(string[] memory _tokenSymbols, address[] memory _tokenAddresses)
{
mapping(address => address[]) public eligibleSwapPaths;
address public swapToken;
address public dexRouterAddress;

constructor(
address[][] memory _paths,
address _swapToken,
address _dexRouterAddress
) {
dexRouterAddress = _dexRouterAddress;
swapToken = _swapToken;
uint256 i = 0;
while (i < _tokenSymbols.length) {
tokenAddresses[_tokenSymbols[i]] = _tokenAddresses[i];
i += 1;
uint256 eligibleSwapPathsLen = _paths.length;
while (i < eligibleSwapPathsLen) {
eligibleSwapPaths[_paths[i][0]] = _paths[i];
i++;
}
}

function calculateNeededETHAmount(address _toToken, uint256 _amount)
public
view
returns (uint256)
{
IUniswapV2Router02 routerSushi = IUniswapV2Router02(sushiRouterAddress);
function calculateNeededETHAmount(
address _toToken,
uint256 _amount
) public view returns (uint256) {
IUniswapV2Router02 dexRouter = IUniswapV2Router02(dexRouterAddress);

address[] memory path = generatePath(
tokenAddresses["WMATIC"],
_toToken
);
address[] memory path = generatePath(swapToken, _toToken);
uint256 len = path.length;

uint256[] memory amounts = routerSushi.getAmountsIn(_amount, path);
uint256[] memory amounts = dexRouter.getAmountsIn(_amount, path);
// sanity check arrays
require(len == amounts.length, "Arrays unequal");
require(_amount == amounts[len - 1], "Output amount mismatch");
return amounts[0];
}

function swap(address _toToken, uint256 _amount) public payable {
IUniswapV2Router02 routerSushi = IUniswapV2Router02(sushiRouterAddress);
IUniswapV2Router02 dexRouter = IUniswapV2Router02(dexRouterAddress);

address[] memory path = generatePath(
tokenAddresses["WMATIC"],
_toToken
);
address[] memory path = generatePath(swapToken, _toToken);

uint256[] memory amounts = routerSushi.swapETHForExactTokens{
uint256[] memory amounts = dexRouter.swapETHForExactTokens{
value: msg.value
}(_amount, path, address(this), block.timestamp);

Expand All @@ -60,23 +63,40 @@ contract Swapper {
}
}

function generatePath(address _fromToken, address _toToken)
internal
view
returns (address[] memory)
{
if (_toToken == tokenAddresses["USDC"]) {
address[] memory path = new address[](2);
function generatePath(
address _fromToken,
address _toToken
) internal view returns (address[] memory path) {
uint256 len = eligibleSwapPaths[_fromToken].length;
if (len == 1 || eligibleSwapPaths[_fromToken][1] == _toToken) {
path = new address[](2);
path[0] = _fromToken;
path[1] = _toToken;
return path;
} else {
address[] memory path = new address[](3);
}
if (len == 2 || eligibleSwapPaths[_fromToken][2] == _toToken) {
path = new address[](3);
path[0] = _fromToken;
path[1] = tokenAddresses["USDC"];
path[1] = eligibleSwapPaths[_fromToken][1];
path[2] = _toToken;
return path;
}
if (len == 3 || eligibleSwapPaths[_fromToken][3] == _toToken) {
path = new address[](3);
path[0] = _fromToken;
path[1] = eligibleSwapPaths[_fromToken][1];
path[2] = eligibleSwapPaths[_fromToken][2];
path[3] = _toToken;
return path;
} else {
path = new address[](4);
path[0] = _fromToken;
path[1] = eligibleSwapPaths[_fromToken][1];
path[2] = eligibleSwapPaths[_fromToken][2];
path[3] = eligibleSwapPaths[_fromToken][3];
path[4] = _toToken;
return path;
}
}

fallback() external payable {}
Expand Down
32 changes: 28 additions & 4 deletions deploy/00_deploy_offsetHelper.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { DeployFunction } from "hardhat-deploy/types";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import addresses, { mumbaiAddresses } from "../utils/addresses";
import paths from "../utils/paths";
import { poolAddresses, routerAddresses } from "../utils/addresses";

const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const addressesToUse =
hre.network.name == "mumbai" ? mumbaiAddresses : addresses;
const pathsToUse =
paths[hre.network.name === "hardhat" ? "alfajores" : hre.network.name];
const poolAddressesToUse =
poolAddresses[
hre.network.name === "hardhat" ? "alfajores" : hre.network.name
];
const routerAddress =
routerAddresses[
hre.network.name === "hardhat" ? "alfajores" : hre.network.name
];

const { deployments, getNamedAccounts } = hre;
const { deploy } = deployments;
Expand All @@ -16,9 +25,24 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {

await deploy("OffsetHelper", {
from: deployer,
args: [Object.keys(addressesToUse), Object.values(addressesToUse)],
args: [
Object.values(poolAddressesToUse),
Object.keys(pathsToUse),
Object.values(pathsToUse),
routerAddress,
],
log: true,
autoMine: true, // speed up deployment on local network (ganache, hardhat), no effect on live networks
});
// await deploy("Swapper", {
// from: deployer,
// args: [
// Object.values(pathsToUse),
// "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270", // WMATIC
// routerAddress,
// ],
// log: true,
// autoMine: true, // speed up deployment on local network (ganache, hardhat), no effect on live networks
// });
};
export default func;
1 change: 1 addition & 0 deletions deployments/alfajores/.chainId
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
44787
Loading

0 comments on commit f98e5ef

Please sign in to comment.