Commit 074a5657 authored by XFT's avatar XFT
Browse files

.

parent a4bc252b
Pipeline #27 failed with stages
in 0 seconds
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "./Shifter.sol";
import "./Interfaces/ElasticIERC20.sol";
import "./Interfaces/SafeEERC20.sol";
import "./Interfaces/IOracle.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract XFTanon is Shifter, Pausable, Ownable {
using SafeEERC20 for ElasticIERC20;
ElasticIERC20 public immutable xft;
ElasticIERC20 public immutable token;
IOracle public oracle;
uint256 public tokenPrice;
address public xftPool;
address public tokenPool;
address public weth9;
address public chainlinkFeed;
uint256 public flexFeeThreshold;
bool public oracleActive = true;
event SetOracle(address oracle);
event SimpleShift(uint256 amount, address recipient, uint256 output);
event SetFlexFeeThreshold(uint256 _threshold);
event SetChainlinkFeed(address _chainlink);
event SetPool(address _pool);
constructor(
IVerifier _verifier,
IHasher _hasher,
IStorage _storage,
uint256 _denomination,
uint256 _ethDenomination,
uint32 _merkleTreeHeight,
ElasticIERC20 _xft,
ElasticIERC20 _token,
IOracle _oracle,
address _xftPool,
address _tokenPool,
address _weth9,
address _chainlinkFeed,
uint256 _flexFeeThreshold
) Shifter(_verifier, _hasher, _storage, _denomination, _ethDenomination, _merkleTreeHeight) {
if (_tokenPool == address(0x0) || _xftPool == address(0x0)) oracleActive = false;
oracle = _oracle;
xft = _xft;
token = _token;
xftPool = _xftPool;
tokenPool = _tokenPool;
weth9 = _weth9;
chainlinkFeed = _chainlinkFeed;
flexFeeThreshold = _flexFeeThreshold;
}
function pause() external onlyOwner {
_pause();
}
function setOracle(IOracle _oracle) external onlyOwner whenNotPaused {
oracle = _oracle;
emit SetOracle(address(_oracle));
}
function setChainlinkFeed(address _chainlink) external onlyOwner whenNotPaused {
chainlinkFeed = _chainlink;
emit SetChainlinkFeed(_chainlink);
}
function setXFTPool(address _xftPool) external onlyOwner whenNotPaused {
xftPool = _xftPool;
emit SetPool(_xftPool);
}
function setTokenPool(address _tokenPool) external onlyOwner whenNotPaused {
tokenPool = _tokenPool;
emit SetPool(_tokenPool);
}
function setFlexFeeThreshold(uint256 _threshold) external onlyOwner whenNotPaused {
flexFeeThreshold = _threshold;
emit SetFlexFeeThreshold(flexFeeThreshold);
}
function simpleShift(uint256 _amount, address _recipient) public whenNotPaused {
require(token.balanceOf(msg.sender) >= _amount, "Insufficient balance");
uint256 _output = oracle.getCostSimpleShift(_amount, chainlinkFeed, xftPool, tokenPool);
token.burn(msg.sender, _amount);
xft.mint(_recipient, _output);
emit SimpleShift(_amount, _recipient, _output);
}
function getDenomination() external view returns (uint256) {
return denomination;
}
function getCost(uint256 _amount) public view returns (uint256) {
if (!oracleActive) return _amount;
return oracle.getCost(_amount, chainlinkFeed, xftPool);
}
function _processDeposit() internal override whenNotPaused {
uint256 depositCost = getCost(denomination);
require(xft.balanceOf(msg.sender) >= depositCost, "Insufficient Balance");
xft.burn(msg.sender, depositCost);
}
function _processWithdraw (
address payable _recipient,
address payable _relayer,
uint256 _fee, // Fee is in USD
uint256 _refund
) internal override {
require(msg.value == _refund, "Incorrect refund amount received by the contract");
token.mint(_recipient, denomination - _fee);
if (_fee > 0) {
token.mint(_relayer, _fee);
}
if (_refund + ethDenomination > 0) {
(bool success, ) = _recipient.call{ value: _refund + ethDenomination }("");
if (!success) {
// let's return back to the relayer
_relayer.transfer(_refund + ethDenomination);
}
}
}
}
// Copyright 2017 Christian Reitwiessner
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
// 2019 OKIMS
pragma solidity ^0.7.0;
library Pairing {
uint256 constant PRIME_Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[0] * z + X[1]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
/*
* @return The negation of p, i.e. p.plus(p.negate()) should be zero.
*/
function negate(G1Point memory p) internal pure returns (G1Point memory) {
// The prime q in the base field F_q for G1
if (p.X == 0 && p.Y == 0) {
return G1Point(0, 0);
} else {
return G1Point(p.X, PRIME_Q - (p.Y % PRIME_Q));
}
}
/*
* @return r the sum of two points of G1
*/
function plus(
G1Point memory p1,
G1Point memory p2
) internal view returns (G1Point memory r) {
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
// Use "invalid" to make gas estimation work
switch success case 0 { invalid() }
}
require(success, "pairing-add-failed");
}
/*
* @return r the product of a point on G1 and a scalar, i.e.
* p == p.scalar_mul(1) and p.plus(p) == p.scalar_mul(2) for all
* points p.
*/
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
// Use "invalid" to make gas estimation work
switch success case 0 { invalid() }
}
require(success, "pairing-mul-failed");
}
/* @return The result of computing the pairing check
* e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
* For example,
* pairing([P1(), P1().negate()], [P2(), P2()]) should return true.
*/
function pairing(
G1Point memory a1,
G2Point memory a2,
G1Point memory b1,
G2Point memory b2,
G1Point memory c1,
G2Point memory c2,
G1Point memory d1,
G2Point memory d2
) internal view returns (bool) {
G1Point[4] memory p1 = [a1, b1, c1, d1];
G2Point[4] memory p2 = [a2, b2, c2, d2];
uint256 inputSize = 24;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < 4; i++) {
uint256 j = i * 6;
input[j + 0] = p1[i].X;
input[j + 1] = p1[i].Y;
input[j + 2] = p2[i].X[0];
input[j + 3] = p2[i].X[1];
input[j + 4] = p2[i].Y[0];
input[j + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
// Use "invalid" to make gas estimation work
switch success case 0 { invalid() }
}
require(success, "pairing-opcode-failed");
return out[0] != 0;
}
}
contract Verifier {
uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 constant PRIME_Q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
using Pairing for *;
struct VerifyingKey {
Pairing.G1Point alfa1;
Pairing.G2Point beta2;
Pairing.G2Point gamma2;
Pairing.G2Point delta2;
Pairing.G1Point[7] IC;
}
struct Proof {
Pairing.G1Point A;
Pairing.G2Point B;
Pairing.G1Point C;
}
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
vk.alfa1 = Pairing.G1Point(uint256(20692898189092739278193869274495556617788530808486270118371701516666252877969), uint256(11713062878292653967971378194351968039596396853904572879488166084231740557279));
vk.beta2 = Pairing.G2Point([uint256(12168528810181263706895252315640534818222943348193302139358377162645029937006), uint256(281120578337195720357474965979947690431622127986816839208576358024608803542)], [uint256(16129176515713072042442734839012966563817890688785805090011011570989315559913), uint256(9011703453772030375124466642203641636825223906145908770308724549646909480510)]);
vk.gamma2 = Pairing.G2Point([uint256(11559732032986387107991004021392285783925812861821192530917403151452391805634), uint256(10857046999023057135944570762232829481370756359578518086990519993285655852781)], [uint256(4082367875863433681332203403145435568316851327593401208105741076214120093531), uint256(8495653923123431417604973247489272438418190587263600148770280649306958101930)]);
vk.delta2 = Pairing.G2Point([uint256(15208606214570874334261746446200199033462678344026185572194543686340588455376), uint256(4201549448713475441700620943818443847551216333428073482030847716518222239220)], [uint256(12504569504683876560222890118098094502189148489042391982838401316936649733743), uint256(21452163545381790963880582203990389540905251758607075975866466960090453123328)]);
vk.IC[0] = Pairing.G1Point(uint256(16225148364316337376768119297456868908427925829817748684139175309620217098814), uint256(5167268689450204162046084442581051565997733233062478317813755636162413164690));
vk.IC[1] = Pairing.G1Point(uint256(12882377842072682264979317445365303375159828272423495088911985689463022094260), uint256(19488215856665173565526758360510125932214252767275816329232454875804474844786));
vk.IC[2] = Pairing.G1Point(uint256(13083492661683431044045992285476184182144099829507350352128615182516530014777), uint256(602051281796153692392523702676782023472744522032670801091617246498551238913));
vk.IC[3] = Pairing.G1Point(uint256(9732465972180335629969421513785602934706096902316483580882842789662669212890), uint256(2776526698606888434074200384264824461688198384989521091253289776235602495678));
vk.IC[4] = Pairing.G1Point(uint256(8586364274534577154894611080234048648883781955345622578531233113180532234842), uint256(21276134929883121123323359450658320820075698490666870487450985603988214349407));
vk.IC[5] = Pairing.G1Point(uint256(4910628533171597675018724709631788948355422829499855033965018665300386637884), uint256(20532468890024084510431799098097081600480376127870299142189696620752500664302));
vk.IC[6] = Pairing.G1Point(uint256(15335858102289947642505450692012116222827233918185150176888641903531542034017), uint256(5311597067667671581646709998171703828965875677637292315055030353779531404812));
}
/*
* @returns Whether the proof is valid given the hardcoded verifying key
* above and the public inputs
*/
function verifyProof(
bytes memory proof,
uint256[6] memory input
) public view returns (bool) {
uint256[8] memory p = abi.decode(proof, (uint256[8]));
// Make sure that each element in the proof is less than the prime q
for (uint8 i = 0; i < p.length; i++) {
require(p[i] < PRIME_Q, "verifier-proof-element-gte-prime-q");
}
Proof memory _proof;
_proof.A = Pairing.G1Point(p[0], p[1]);
_proof.B = Pairing.G2Point([p[2], p[3]], [p[4], p[5]]);
_proof.C = Pairing.G1Point(p[6], p[7]);
VerifyingKey memory vk = verifyingKey();
// Compute the linear combination vk_x
Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
vk_x = Pairing.plus(vk_x, vk.IC[0]);
// Make sure that every input is less than the snark scalar field
for (uint256 i = 0; i < input.length; i++) {
require(input[i] < SNARK_SCALAR_FIELD, "verifier-gte-snark-scalar-field");
vk_x = Pairing.plus(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i]));
}
return Pairing.pairing(
Pairing.negate(_proof.A),
_proof.B,
vk.alfa1,
vk.beta2,
vk_x,
vk.gamma2,
_proof.C,
vk.delta2
);
}
}
This diff is collapsed.
File added
This diff is collapsed.
{"IC":[["16225148364316337376768119297456868908427925829817748684139175309620217098814","5167268689450204162046084442581051565997733233062478317813755636162413164690","1"],["12882377842072682264979317445365303375159828272423495088911985689463022094260","19488215856665173565526758360510125932214252767275816329232454875804474844786","1"],["13083492661683431044045992285476184182144099829507350352128615182516530014777","602051281796153692392523702676782023472744522032670801091617246498551238913","1"],["9732465972180335629969421513785602934706096902316483580882842789662669212890","2776526698606888434074200384264824461688198384989521091253289776235602495678","1"],["8586364274534577154894611080234048648883781955345622578531233113180532234842","21276134929883121123323359450658320820075698490666870487450985603988214349407","1"],["4910628533171597675018724709631788948355422829499855033965018665300386637884","20532468890024084510431799098097081600480376127870299142189696620752500664302","1"],["15335858102289947642505450692012116222827233918185150176888641903531542034017","5311597067667671581646709998171703828965875677637292315055030353779531404812","1"]],"vk_alfa_1":["20692898189092739278193869274495556617788530808486270118371701516666252877969","11713062878292653967971378194351968039596396853904572879488166084231740557279","1"],"vk_beta_2":[["281120578337195720357474965979947690431622127986816839208576358024608803542","12168528810181263706895252315640534818222943348193302139358377162645029937006"],["9011703453772030375124466642203641636825223906145908770308724549646909480510","16129176515713072042442734839012966563817890688785805090011011570989315559913"],["1","0"]],"vk_gamma_2":[["10857046999023057135944570762232829481370756359578518086990519993285655852781","11559732032986387107991004021392285783925812861821192530917403151452391805634"],["8495653923123431417604973247489272438418190587263600148770280649306958101930","4082367875863433681332203403145435568316851327593401208105741076214120093531"],["1","0"]],"vk_delta_2":[["4201549448713475441700620943818443847551216333428073482030847716518222239220","15208606214570874334261746446200199033462678344026185572194543686340588455376"],["21452163545381790963880582203990389540905251758607075975866466960090453123328","12504569504683876560222890118098094502189148489042391982838401316936649733743"],["1","0"]],"vk_alfabeta_12":[[["21365812195485565970449951947073093780266368302919758441364015846541070649889","13899346400535634506212110533298291334607392402427556671205120154633328392938"],["9176241749501911223800029754421468853554325976185319022570714890557573371905","16897971416518120303319064173781767941602184168568029998374699041158871223961"],["6994180461635063460601079479427022670717591990958754250719881638298446317234","9179026066977875182617507817914233459615244337807200435373777462238862437279"]],[["12505271218650914527710842094803759916526791354425688234288687823807495160149","21079529389819175768418925187724856376731616978516023985093353832725307191172"],["17191503117818720549103434672697266076462686591305810428253469897937793366640","1460614254014044318793914579722356842222906714283817829623699739748310555420"],["8156206509351086444845867552906130156524383450240899694386232124211773153798","9170252275562998399982022993666567730500187520875477300499051353566398457339"]]],"protocol":"groth","nPublic":6}
\ No newline at end of file
const fs = require('fs');
const configRelativePath = fs.existsSync('./config.json') ? './config.json' : '../config.json';
const config = require(configRelativePath);
const shifters = {}
const XFTanon = artifacts.require('XFTanon')
const Verifier = artifacts.require('Verifier')
const Hasher = artifacts.require('Hasher')
const Storage = artifacts.require('Storage')
const Oracle = artifacts.require('Oracle')
const XFTMock = artifacts.require('XFTMock')
const XFTOLDMock = artifacts.require('XFTOLDMock')
const aUSDMock = artifacts.require('anonUSD')
const INonfungiblePositionManager = artifacts.require('INonfungiblePositionManager')
const IUniswapV3Pool = artifacts.require("IUniswapV3Pool")
const IUniswapV3Factory = artifacts.require("IUniswapV3Factory")
const IERC20 = artifacts.require('IERC20')
const IWETH9 = artifacts.require('IWETH9')
const Web3Utils = require('web3-utils')
const burnerRole = Web3Utils.keccak256("BURNER_ROLE")
const minterRole = Web3Utils.keccak256("MINTER_ROLE")
const TokenSwap = artifacts.require("TokenSwap")
const AggregatorV3 = artifacts.require("AggregatorV3Interface")
advanceTimeAndBlock = async (time) => {
await advanceTime(time);
await advanceBlock();
return Promise.resolve(web3.eth.getBlock('latest'));
}
advanceTime = (time) => {
return new Promise((resolve, reject) => {
web3.currentProvider.send({
jsonrpc: "2.0",
method: "evm_increaseTime",
params: [time],
id: new Date().getTime()
}, (err, result) => {
if (err) { return reject(err); }
return resolve(result);
});
});
}
advanceBlock = () => {
return new Promise((resolve, reject) => {
web3.currentProvider.send({
jsonrpc: "2.0",
method: "evm_mine",
id: new Date().getTime()
}, (err, result) => {
if (err) { return reject(err); }
const newBlockHash = web3.eth.getBlock('latest').hash;
return resolve(newBlockHash)
});
});
}
unlockAccount = async (address) => {
let provider = web3.currentProvider;
return new Promise((res, rej) => {
provider.send({
method: 'evm_addAccount',
params: [address, ""]
}, (d) => {
provider.send({
method: 'personal_unlockAccount',
params: [address, ""]
}, (d) => {
res(address);
});
});
});
}
module.exports = function (deployer, network, accounts) {
return deployer.then(async () => {
let {
MERKLE_TREE_HEIGHT, tokenStyle, xftToken, ethDenomination, weth9, oracle, dry,
HASHER, VERIFIER, STORAGE, XFT_POOL, INTERVAL_SHORT, INTERVAL_LONG
} = config
let { xftUniPool, NonfungiblePositionManager, UniswapV3Factory, UniswapV3Staker, nftID } = config.uniswap
let xft = xftToken
let verifier = VERIFIER
let hasher = HASHER
let storage = STORAGE
oracle = oracle || ''
let xftPool = XFT_POOL || "0x0000000000000000000000000000000000000000"
let tokenInstance, xftInstance, storageInstance, minted, account
if (verifier === '') verifierInstance = await deployer.deploy(Verifier)
else verifierInstance = await Verifier.at(VERIFIER)
verifier = verifierInstance.address
console.log(`Verifier at ${verifier}`)
if (hasher === '') hasherInstance = await deployer.deploy(Hasher)
else hasherInstance = await Hasher.at(HASHER)
hasher = hasherInstance.address
// Init storage to the null address since constructor requires it
if (storage === '') storageInstance = await deployer.deploy(Storage, "0x0000000000000000000000000000000000000000")
else storageInstance = await Storage.at(STORAGE)
storage = storageInstance.address
if (xft === '') xftInstance = await deployer.deploy(XFTMock)
else xftInstance = await XFTMock.at(xftToken)
xft = xftInstance.address
let xftOldMockInstance = await deployer.deploy(XFTOLDMock);
const xftOldMock = xftOldMockInstance.address;
// Deploy TokenSwap contract and grant it XFT Minter Permissions
const xftNewMock = xft
let tokenSwapInstance = await deployer.deploy(TokenSwap, xftOldMock, xftNewMock)
let tokenSwap = tokenSwapInstance.address
await xftInstance.grantRole(minterRole, tokenSwap)
// Contract interfaces for UniswapV3
const nonfungiblePositionManager = await INonfungiblePositionManager.at(NonfungiblePositionManager)
const xftUniswapV3Pool = await IUniswapV3Pool.at(xftUniPool)
const uniswapV3Factory = await IUniswapV3Factory.at(UniswapV3Factory)
const _weth9 = await IWETH9.at(weth9) // For wrapping/unwrapping
const WETH = await IERC20.at(weth9) // For ERC20 stuff
// Depositing 10000 ETH into Wrapped ETH, to be used in UniswapV3 Pools
await _weth9.deposit({value: "10000000000000000000000"})
// Contract deployment address
account = deployer.networks.development.from;
// Pool Initialization Function
/* Parameters
token0_: address
token1_: address
fee_: uint24,
pool_: address
*/
let initPool = async function (token0_, token1_, fee_, pool_) {
const pool = await IUniswapV3Pool.at(pool_) //Pool we're fetching init price from
const slot0 = await pool.slot0()
const price = slot0.sqrtPriceX96
const fee = await pool.fee()
// Uniswap reverts pool initialization if you don't sort by address number, beware!
let token0, token1
if (token1_ > token0_) {
token1 = token1_
token0 = token0_
} else {
token1 = token0_
token0 = token1_
}
await nonfungiblePositionManager.createAndInitializePoolIfNecessary(token0, token1, fee, price)
}
let initPoolETH = async function (token0_, token1_, fee_, price_) {
// Uniswap reverts pool initialization if you don't sort by address number, beware!
let sqrtPrice = Math.sqrt(price_)
let token0, token1, price
if (token1_ > token0_) {
token1 = token1_
token0 = token0_
} else {
token1 = token0_
token0 = token1_
}
if (token0 === weth9) price = BigInt(sqrtPrice*2**96)
else price = BigInt(2**96/sqrtPrice)
await nonfungiblePositionManager.createAndInitializePoolIfNecessary(token0, token1, fee_, price)
}
// Liquidity Providing Function
/* Parameters
token0_: address
token1_: address
fee_: uint24
tickLower_: int24
tickUpper_: int24
amount0ToMint_: uint256
amount1ToMint_: uint256
amount0Min_: uint256
amount1Min_: uint256
recipient: address
timestamp_: uint256
*/
let addLiquidity = async function (
token0_,
token1_,
fee_,
tickLower_ = -887220,
tickUpper_ = 887220,
amount0ToMint_,
amount1ToMint_,
amount0Min_ = 0,
amount1Min_ = 0,
recipient_ = account,
timestamp_ = Math.ceil(Date.now()/1000 + 300)) {
// Uniswap reverts pool initialization if you don't sort by address number, beware!
let token0, token1
if (token1_ > token0_) {
token1 = await aUSDMock.at(token1_)
token0 = await aUSDMock.at(token0_)
} else {
token1 = await aUSDMock.at(token0_)
token0 = await aUSDMock.at(token1_)
}
let mintParams = [
token0.address,
token1.address,
fee_,
tickLower_,
tickUpper_,
BigInt(amount0ToMint_),
BigInt(amount1ToMint_),
amount0Min_,
amount1Min_,
recipient_,
timestamp_
]
await token0.approve(NonfungiblePositionManager, amount0ToMint_)
await token1.approve(NonfungiblePositionManager, amount1ToMint_)
const {logs} = await nonfungiblePositionManager.mint(mintParams)
const tokenId = logs[1].args.tokenId
return tokenId
}
// Pool parameters from XFT/WETH UniswapV3 pool
const _fee = await xftUniswapV3Pool.fee()
// Min and Max tick numbers, as a multiple of 60
const tickMin = -887220
const tickMax = 887220
const defaultTimestamp = Math.ceil(Date.now()/1000 + 300)
// ERC20 contract interfaces for XFT and WETH
const xftNew = tokenStyle["XFT"]["address"]
const xftNewInstance = await IERC20.at(xftNew)
// Granting minter role to deployment account for Mock ETH and Mock XFT
await xftInstance.grantRole(minterRole, account)
// Live token balances from the XFT/WETH Uniswap V3 Pool
let token0, token1, amount0, amount1, amount0Min, amount1Min
let oldBalXFT = await xftNewInstance.balanceOf(xftUniPool)
let oldBalWETH = await WETH.balanceOf(xftUniPool)
if (xftNewMock > weth9) {
token0 = weth9
token1 = xftNewMock
amount0 = oldBalWETH
amount1 = oldBalXFT
amount0Min = BigInt(amount0)*BigInt(9)/BigInt(10) // 90% of the original balance
amount1Min = BigInt(amount1)*BigInt(9)/BigInt(10) // 90% of the original balance
} else {
token0 = xftNewMock
token1 = weth9
amount0 = oldBalXFT
amount1 = oldBalWETH
amount0Min = BigInt(amount0)*BigInt(9)/BigInt(10) // 90% of the original balance
amount1Min = BigInt(amount1)*BigInt(9)/BigInt(10) // 90% of the original balance
}
// Deployer is the LP
let recipient = account
// Minting surplus tokens to the token deployer/liquidity provider
await xftInstance.mint(recipient, BigInt(1e26))
// Raw BigNumber tick values from NonfungiblePositionManager
let xftwethTickLower = (await nonfungiblePositionManager.positions(nftID)).tickLower
let xftwethTickUpper = (await nonfungiblePositionManager.positions(nftID)).tickUpper
// Initialize mock version of the old XFT pool
await initPool(weth9, xftNewMock, _fee, xftUniPool)
const tokenId = await addLiquidity(
token0,
token1,
_fee,
xftwethTickLower,
xftwethTickUpper,
amount0,
amount1,
amount0Min,
amount1Min,
account,
defaultTimestamp
)
// Logging pool values
xftPool = await uniswapV3Factory.getPool(weth9, xftNewMock, _fee)
console.log(`XFT Pool: ${xftPool}`)
const poolBalWETH = await WETH.balanceOf(xftPool)
const poolBalXFT = await xftInstance.balanceOf(xftPool)
console.log(`New Pool Bal WETH: ${poolBalWETH.toString()}`)
console.log(`New Pool Bal XFT: ${poolBalXFT.toString()}`)
let xftPoolInstance = await IUniswapV3Pool.at(xftPool)
let xftPoolSlot0 = await xftPoolInstance.slot0()
console.log(`New XFT Pool Price: ${xftPoolSlot0.sqrtPriceX96}`)
let cardinality = 10
// Writing XFT Mock contract to shifters.ts
shifters["XFT"] = {
color: tokenStyle["XFT"]["color"],
icon: tokenStyle["XFT"]["icon"],
name: tokenStyle["XFT"]["name"],
symbol: `${tokenStyle["XFT"]["name"]}`,
zkSymbol: `${tokenStyle["XFT"]["name"]}`,
denom: "0",
contract: xft,
shifter: "0x0000000000000000000000000000000000000000",
}
shifters["WETH"] = {
color: tokenStyle["XFT"]["color"],
icon: "assets/images/wETH-white.svg",
name: "Ether",
symbol: "ETH",
zkSymbol: "WETH",
denom: "0",
contract: weth9,
shifter: "0x0000000000000000000000000000000000000000",
}
// Deploy oracle
let oracleInstance = await deployer.deploy(
Oracle,
weth9,
INTERVAL_SHORT,
INTERVAL_LONG,
BigInt(975e15) //threshold 0.975*1e18
)
oracle = oracleInstance.address
for (let [key, value] of Object.entries(tokenStyle)) {
let token = value["address"]
let name = value["name"]
let symbol = value["symbol"]
let tokenPool = value["pool"]
let chainlink = value["chainlink"]
let threshold = value["threshold"]
let denoms = value["denoms"]
let price = value["price"]
if (chainlink !== "0x0000000000000000000000000000000000000000") {
let chainlinkInstance = await AggregatorV3.at(chainlink)
let latestRoundData = await chainlinkInstance.latestRoundData();
let latestRoundPrice = Number(latestRoundData.answer);
let decimals = Number(await chainlinkInstance.decimals());
price = latestRoundPrice / 10**decimals
console.log(`Chainlink Price ${name}/ETH: ${price}`)
}
// Deploy mock token if not already deployed .
if (token === '') tokenInstance = await deployer.deploy(aUSDMock, name, symbol)
else tokenInstance = await aUSDMock.at(token)
token = tokenInstance.address
if (key !== "XFT") {
await tokenInstance.grantRole(minterRole, account)
await tokenInstance.mint(account, BigInt(value["mint"]))
let poolAddress = await uniswapV3Factory.getPool(weth9, token, _fee)
if (poolAddress === "0x0000000000000000000000000000000000000000") await initPoolETH(weth9, token, _fee, price)
tokenPool = await uniswapV3Factory.getPool(weth9, token, _fee)
value["pool"] = tokenPool
await addLiquidity(
weth9,
token,
_fee,
tickMin,
tickMax,
BigInt(value["mint"]),
BigInt(value["mint"]),
BigInt(0),
BigInt(0),
recipient,
defaultTimestamp
)
const weth9Bal = await WETH.balanceOf(tokenPool)
const tokenBal = await tokenInstance.balanceOf(tokenPool)
console.log(`WETH balance ${weth9Bal.toString()}`)
console.log(`${key} balance ${tokenBal.toString()}`)
}
// Iterate denoms
if (key !== "XFT" && denoms.length > 0)
for (let denom of denoms) {
const denomWei = Web3Utils.toWei(denom)
let shifter;
if (key == "anonETH") console.log();
shifter = await deployer.deploy(
XFTanon,
verifier,
hasher,
storage,
denomWei,
ethDenomination,
MERKLE_TREE_HEIGHT,
xft,
token,
oracle,
xftPool,
tokenPool,
weth9,
chainlink,
threshold
)
// Settings shifter address in storage to deployed shifter contract
await storageInstance.addShifter(shifter.address)
// Make sure the shifter can burn/mint
await tokenInstance.grantRole(burnerRole, shifter.address)
await tokenInstance.grantRole(minterRole, shifter.address)
await xftInstance.grantRole(minterRole, shifter.address)
await xftInstance.grantRole(burnerRole, shifter.address)
/*shifters["shifters"][`${tokenSymbol}_${denomination}`] = {
display: `${tokenSymbol} (${denomination})`,
name: tokenName,
address: shifter.address,
denomination: denom.toString(),
verifier: verifier,
storage: storage,
xftToken: token,
output: usd
}*/
let varName = `${key.toString()}${denom.replace(".", "")}`
shifters[varName] = {
color: tokenStyle[key]["color"],
icon: tokenStyle[key]["icon"],
name: tokenStyle[key]["name"],
symbol: `${tokenStyle[key]["name"]} (${denom})`,
zkSymbol: `${tokenStyle[key]["name"]}${denom.replace(".", "")}`,
denom: denomWei.toString(),
contract: token,
shifter: shifter.address,
}
console.log(`
Token: ${key}
Denomination: ${denom}
Shifter deployed to ${shifter.address}
`)
}
}
// Get the pools to be as old as INTERVAL_LONG
await advanceTimeAndBlock(INTERVAL_LONG)
await xftPoolInstance.increaseObservationCardinalityNext(cardinality)
console.log(`
Verifier deployed to ${verifier}
Hasher deployed to ${hasher}
XFT Token deployed to ${xft}
Storage deployed to ${storage}
Oracle deployed to ${oracle}
`)
fs.writeFileSync('./shifters.ts', `export const shifters = ${JSON.stringify(shifters, null, 4)}`);
})
}
{
"name": "circuits",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build:circuit:compile": "npx circom circuits/withdraw.circom -o build/circuits/withdraw.json && npx snarkjs info -c build/circuits/withdraw.json",
"build:circuit:setup": "npx snarkjs setup --protocol groth -c build/circuits/withdraw.json --pk build/circuits/withdraw_proving_key.json --vk build/circuits/withdraw_verification_key.json",
"build:circuit:bin": "node node_modules/websnark/tools/buildpkey.js -i build/circuits/withdraw_proving_key.json -o build/circuits/withdraw_proving_key.bin",
"build:circuit:contract": "npx snarkjs generateverifier -v build/circuits/Verifier.sol --vk build/circuits/withdraw_verification_key.json",
"build:circuit": "npm run build:circuit:compile && npm run build:circuit:setup && npm run build:circuit:bin && npm run build:circuit:contract",
"build:contract": "npx truffle compile",
"build": "npm run build:circuit && npm run build:contract",
"test": "npx truffle test",
"migrate": "npm run migrate:kovan",
"migrate:dev": "npx truffle migrate --network development --reset",
"multimigrate:dev": "node ./scripts/multi.js",
"eslint": "eslint --ext .js --ignore-path .gitignore .",
"prettier:check": "prettier --check . --config .prettierrc",
"prettier:fix": "prettier --write . --config .prettierrc",
"lint": "yarn eslint && yarn prettier:check",
"flat": "npx truffle-flattener contracts/XFTanon.sol > XFTanon_flat.sol",
"download": "bash scripts/download.sh",
"coverage": "yarn truffle run coverage",
"fork": "npx ganache-cli -m \"artwork story jeans lyrics expose update sword absurd rail game argue submit\" -p 8545 -h 0.0.0.0 -l 80000000 --fork <RPC URL HERE> --defaultBalanceEther 100000",
"ganache": "npx ganache-cli -m \"artwork story jeans lyrics expose update sword absurd rail game argue submit\" -p 8545 -h 0.0.0.0"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@chainlink/contracts": "^0.5.1",
"@openzeppelin/contracts": "^3.4.1",
"@truffle/contract": "^4.0.39",
"@truffle/hdwallet-provider": "^1.0.24",
"@uniswap/v3-core": "^1.0.1",
"@uniswap/v3-periphery": "^1.4.3",
"@uniswap/v3-staker": "^1.0.2",
"axios": "^0.19.0",
"babel-eslint": "^10.1.0",
"bn-chai": "1.0.1",
"browserify": "^16.5.0",
"chai": "4.2.0",
"chai-as-promised": "7.1.1",
"circom": "^0.0.35",
"circomlib": "git+https://github.com/tornadocash/circomlib.git#c372f14d324d57339c88451834bf2824e73bbdbc",
"commander": "^4.1.1",
"dotenv": "^8.2.0",
"eslint": "^7.19.0",
"eslint-config-prettier": "^7.2.0",
"eslint-plugin-prettier": "^3.3.1",
"esm": "^3.2.25",
"eth-json-rpc-filters": "^4.1.1",
"fixed-merkle-tree": "^0.6.0",
"ganache-cli": "^6.7.0",
"prettier": "^2.2.1",
"prettier-plugin-solidity": "^1.0.0-beta.3",
"snarkjs": "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5",
"solhint-plugin-prettier": "^0.0.5",
"solidity-coverage": "^0.7.20",
"truffle": "^5.1.67",
"truffle-flattener": "^1.4.2",
"web3": "^1.3.4",
"web3-utils": "^1.3.4",
"websnark": "git+https://github.com/tornadocash/websnark.git#4c0af6a8b65aabea3c09f377f63c44e7a58afa6d"
}
}
// Generates Hasher artifact at compile-time using Truffle's external compiler
// mechanism
const path = require('path')
const fs = require('fs')
const genContract = require('circomlib/src/mimcsponge_gencontract.js')
// where Truffle will expect to find the results of the external compiler
// command
const outputPath = path.join(__dirname, '..', 'build', 'Hasher.json')
function main() {
const contract = {
contractName: 'Hasher',
abi: genContract.abi,
bytecode: genContract.createCode('mimcsponge', 220),
}
fs.writeFileSync(outputPath, JSON.stringify(contract))
}
main()
if [ ! -d ./build ]; then
mkdir ./build
echo "./build directory created"
else
echo "./build already exists"
fi
if [ ! -d ./build/circuits ]; then
mkdir ./build/circuits
"./build/circuits directory created"
else
echo "./build/circuits already exists"
fi
cp ./download/Verifier.sol ./build/circuits/Verifier.sol
echo "Verifier copied"
cp ./download/withdraw_proving_key.json ./build/circuits/withdraw_proving_key.json
echo "Proving key json copied"
cp ./download/withdraw_proving_key.bin ./build/circuits/withdraw_proving_key.bin
echo "Proving key binary copied"
cp ./download/withdraw_verification_key.json ./build/circuits/withdraw_verification_key.json
echo "Verifying key copied"
cp ./download/withdraw.json ./build/circuits/withdraw.json
echo "Withdraw.json copied"
\ No newline at end of file
// This module is used only for tests
function send(method, params = []) {
return new Promise((resolve, reject) => {
// eslint-disable-next-line no-undef
web3.currentProvider.send({
jsonrpc: '2.0',
id: Date.now(),
method,
params,
}, (err, res) => {
return err ? reject(err) : resolve(res)
})
})
}
const takeSnapshot = async () => {
return await send('evm_snapshot')
}
const traceTransaction = async (tx) => {
return await send('debug_traceTransaction', [tx, {}])
}
const revertSnapshot = async (id) => {
await send('evm_revert', [id])
}
const mineBlock = async (timestamp) => {
await send('evm_mine', [timestamp])
}
const increaseTime = async (seconds) => {
await send('evm_increaseTime', [seconds])
}
const minerStop = async () => {
await send('miner_stop', [])
}
const minerStart = async () => {
await send('miner_start', [])
}
module.exports = {
takeSnapshot,
revertSnapshot,
mineBlock,
minerStop,
minerStart,
increaseTime,
traceTransaction,
}
This diff is collapsed.
This diff is collapsed.
require('dotenv').config()
const HDWalletProvider = require('@truffle/hdwallet-provider')
const utils = require('web3-utils')
module.exports = {
/**
* Networks define how you connect to your ethereum client and let you set the
* defaults web3 uses to send transactions. If you don't specify one truffle
* will spin up a development blockchain for you on port 9545 when you
* run `develop` or `test`. You can ask a truffle command to use a specific
* network from the command line, e.g
*
* $ truffle test --network <network-name>
*/
networks: {
development: {
host: '127.0.0.1', // Localhost (default: none)
port: 8545, // Standard Ethereum port (default: none)
gas: 30000000,
gasPrice: utils.toWei('1', 'gwei'),
network_id: '*', // Any network (default: none)
skipDryRun: true,
}
},
mocha: {
timeout: 3000000
},
// Configure your compilers
compilers: {
solc: {
version: '0.7.6',
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
external: {
command: 'node ./scripts/compileHasher.js',
targets: [
{
path: './build/Hasher.json',
},
],
},
},
plugins: ['solidity-coverage'],
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment