Skip to content

Instantly share code, notes, and snippets.

@nourharidy
Created October 29, 2019 10:14
Show Gist options
  • Save nourharidy/17be9f2129cfc208ea8f047da3e24b95 to your computer and use it in GitHub Desktop.
Save nourharidy/17be9f2129cfc208ea8f047da3e24b95 to your computer and use it in GitHub Desktop.
Gasless
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