Created
October 29, 2019 10:14
-
-
Save nourharidy/17be9f2129cfc208ea8f047da3e24b95 to your computer and use it in GitHub Desktop.
Gasless
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity 0.5.11; | |
import "openzeppelin-solidity/contracts/math/SafeMath.sol"; | |
interface DSR { | |
function join(uint) external; | |
function exit(uint) external; | |
function chi() external view returns (uint256); | |
} | |
interface MCD { | |
function approve(address usr, uint wad) external returns (bool); | |
function permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) external; | |
function transfer(address dst, uint wad) external returns (bool); | |
function transferFrom(address src, address dst, uint wad) external returns (bool); | |
} | |
interface UniswapExchange { | |
function tokenToEthTransferInput( | |
uint256 tokens_sold, | |
uint256 min_eth, | |
uint256 deadline, | |
address recipient | |
) external returns (uint256 eth_bought); | |
} | |
contract Gasless { | |
using SafeMath for uint; | |
uint MAX_UINT256 = 2**256-1; | |
DSR DSRContract; | |
MCD MCDContract; | |
UniswapExchange UniswapExchangeContract; | |
address relayer; | |
mapping (address => uint256) public nonces; | |
mapping (address => uint256) public dsrBalances; | |
modifier onlyRelayer () { | |
require(msg.sender == relayer, "Only the relayer address is authorized to send this tx"); | |
_; | |
} | |
constructor(address initialRelayer, address DSRaddress, address MCDaddress, address UniswapExchangeAddress) public { | |
DSRContract = DSR(DSRaddress); | |
MCDContract = MCD(MCDaddress); | |
UniswapExchangeContract = UniswapExchange(UniswapExchangeAddress); | |
relayer = initialRelayer; | |
approveUniswap(); | |
} | |
function send(address from, address to, uint value, uint fee, uint deadline, uint8 v, bytes32 r, bytes32 s) public onlyRelayer { | |
require(block.number <= deadline, "Deadline expired"); | |
require(from == recover(keccak256(abi.encodePacked( | |
"send", | |
relayer, | |
to, | |
value, | |
fee, | |
tx.gasprice, | |
nonces[from], | |
deadline | |
)), v, r, s), "Invalid signature"); | |
nonces[from]++; | |
MCDContract.transferFrom(from, to, value.sub(fee)); | |
MCDContract.transferFrom(from, msg.sender, fee); | |
} | |
function recover(bytes32 messageHash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { | |
bytes memory prefix = "\x19Ethereum Signed Message:\n32"; | |
bytes32 prefixedMessageHash = keccak256(abi.encodePacked(prefix, messageHash)); | |
return ecrecover(prefixedMessageHash, v, r, s); | |
} | |
function daiToEthSwap( | |
address from, | |
uint dai_sold, | |
uint min_eth, | |
uint fee, | |
uint deadline, | |
uint8 v, | |
bytes32 r, | |
bytes32 s | |
) public onlyRelayer { | |
require(block.number <= deadline, "Deadline expired"); | |
require(from == recover(keccak256(abi.encodePacked( | |
"daiToEthSwap", | |
relayer, | |
dai_sold, | |
min_eth, | |
fee, | |
tx.gasprice, | |
nonces[from], | |
deadline | |
)), v, r, s), "Invalid signature"); | |
nonces[from]++; | |
MCDContract.transferFrom(from, msg.sender, fee); | |
MCDContract.transferFrom(from, address(this), dai_sold.sub(fee)); | |
UniswapExchangeContract.tokenToEthTransferInput(dai_sold, min_eth, deadline, from); | |
} | |
function joinDSR(address from, uint dai_amount, uint fee, uint deadline, uint8 v, bytes32 r, bytes32 s) public onlyRelayer { | |
require(block.number <= deadline, "Deadline expired"); | |
require(from == recover(keccak256(abi.encodePacked( | |
"joinDSR", | |
relayer, | |
dai_amount, | |
fee, | |
tx.gasprice, | |
nonces[from], | |
deadline | |
)), v, r, s), "Invalid signature"); | |
nonces[from]++; | |
uint real_amount = dai_amount.sub(fee); | |
dsrBalances[from] = dsrBalances[from].add(real_amount); | |
MCDContract.transferFrom(from, address(this), real_amount); | |
MCDContract.transferFrom(from, msg.sender, fee); | |
DSRContract.join(real_amount); | |
} | |
function exitDSR(address from, uint dai_amount, uint fee, uint deadline, uint8 v, bytes32 r, bytes32 s) public onlyRelayer { | |
require(block.number <= deadline, "Deadline expired"); | |
require(from == recover(keccak256(abi.encodePacked( | |
"exitDSR", | |
relayer, | |
dai_amount, | |
fee, | |
tx.gasprice, | |
nonces[from], | |
deadline | |
)), v, r, s), "Invalid signature"); | |
nonces[from]++; | |
dsrBalances[from] = dsrBalances[from].sub(dai_amount); | |
DSRContract.exit(dai_amount); | |
MCDContract.transfer(from, DSRContract.chi().mul(dai_amount)); | |
MCDContract.transferFrom(from, msg.sender, fee); | |
} | |
function approveUniswap() public { | |
MCDContract.approve(address(UniswapExchangeContract), MAX_UINT256); | |
} | |
function accumulatedBalanceOf(address user) public view returns (uint256) { | |
return DSRContract.chi().mul(dsrBalances[user]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment