Skip to content

Instantly share code, notes, and snippets.

@crypto-perry
Created July 31, 2019 22:21
Show Gist options
  • Save crypto-perry/7634a45fc79eeba3a2794b2ddb2b3077 to your computer and use it in GitHub Desktop.
Save crypto-perry/7634a45fc79eeba3a2794b2ddb2b3077 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.5.1+commit.c8a2cb62.js&optimize=true&gist=
pragma solidity >=0.5.0;
import './tradeoracleinterface.sol';
contract FuturesEscrow {
enum TradeState {None, Filled, Closed}
event Deposit(address account, uint256 amount);
event Withdrawal(address account, uint256 amount);
event CompletedTrade(bytes32 tradeId, bytes32 buyer, uint256 amount);
struct Trade {
address payable buyer;
address payable seller;
uint256 price;
uint256 deposit;
uint256 amount;
uint256 expiration;
TradeState state;
}
mapping (bytes32 => Trade) trades;
mapping (address => uint256) balances;
mapping (address => bytes32) addrOnOther; // hashes of user's address on other blockchain (the hash of a string)
TradeOracle tradeVerifier;
address owner;
modifier onlyOwner {
require(msg.sender == owner);
_;
}
constructor() public {
owner = msg.sender;
}
function setTradeVerifier(address tradeOracle) public onlyOwner {
tradeVerifier = TradeOracle(tradeOracle);
}
function completeTrade(bytes32 tradeId) public {
Trade memory trade = trades[tradeId];
require(trade.state == TradeState.Filled);
require(trade.expiration > now);
require(tradeVerifier.recordSale(addrOnOther[trade.seller], trade.amount));
trades[tradeId].state = TradeState.Closed;
balances[owner] += computeFee(trade.price) * 2; // change our balance
emit CompletedTrade(tradeId, addrOnOther[trade.buyer], trade.amount);
trade.seller.transfer(trade.deposit + trade.price);
}
function expireTrade(bytes32 tradeId) public onlyOwner {
Trade memory trade = trades[tradeId];
require(trade.state == TradeState.Filled);
require(trade.expiration < now);
trades[tradeId].state = TradeState.Closed;
balances[owner] += computeFee(trade.price) * 2; // change our balance
trade.buyer.transfer(trade.deposit + trade.price);
}
function linkOtherAddress(string memory addr) public {
require(addrOnOther[msg.sender] == 0);
addrOnOther[msg.sender] = keccak256(abi.encodePacked(addr));
}
function linkOtherAddress(address ethAddress, string memory addr) public onlyOwner {
addrOnOther[ethAddress] = keccak256(abi.encodePacked(addr));
}
function() external payable {
balances[msg.sender] += msg.value;
emit Deposit(msg.sender, msg.value);
}
// Anyone (including us) can only withdraw the amount allocated in balances.
// So we can only ever take the fees.
function withdraw(uint256 amount) public {
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount;
msg.sender.transfer(amount);
emit Withdrawal(msg.sender, amount);
}
// Anyone (including us) can only withdraw the amount allocated in balances.
// So we can only ever take the fees.
function withdrawFor(address payable user, uint256 amount) public onlyOwner {
require(balances[user] >= amount);
balances[user] -= amount;
user.transfer(amount);
emit Withdrawal(user, amount);
}
function makeTrade(bytes32 tradeId, address payable buyer, address payable seller, uint256 price, uint256 deposit, uint256 amount, uint256 expireAfter) public onlyOwner {
uint256 fee = computeFee(price);
require(balances[buyer] >= price + fee);
require(balances[seller] >= deposit + fee);
require(trades[tradeId].state == TradeState.None);
balances[buyer] -= (price + fee); // change buyer balance
balances[seller] -= (deposit + fee); // change seller balance
// notice how the fees are not accounted for here, they will be given to us only when the trade is complete or expired.
trades[tradeId] = Trade(buyer, seller, price, deposit, amount, now + (expireAfter * 1 hours), TradeState.Filled);
}
function computeFee(uint256 price) private pure returns (uint256) {
uint256 fee = price * 5;
require(fee / 5 == price); // Check overflow
return fee / 1000; // This is the fee we take on each side (0.5% * price)
}
}
pragma solidity >=0.5.0;
import './tradeoracleinterface.sol';
contract ManualTradeVerifier is TradeOracle {
constructor(address escrow) TradeOracle(escrow) public {}
function registerDepositManually(bytes32 seller, uint256 amount) public onlyOwner {
balances[seller] += amount;
}
function forceDecreaseBalance(bytes32 seller, uint256 amount) public onlyOwner {
balances[seller] -= amount;
}
}
pragma solidity >=0.5.0;
contract OtcButlerEventStorage {
event Deposit(address account, uint256 amount);
event Withdrawal(address account, uint256 amount);
struct Trade {
address payable buyer;
address payable seller;
uint256 price;
uint256 deposit;
uint256 amount;
uint256 expiration;
TradeState state;
}
mapping (bytes32 => Trade) trades;
mapping (address => uint256) balances;
mapping (address => bytes32) hashAddresses;
TradeOracle tradeVerifier;
address owner;
modifier onlyOwner {
require(msg.sender == owner);
_;
}
constructor() public {
owner = msg.sender;
}
function setTradeVerifier(address tradeOracle) public onlyOwner {
tradeVerifier = TradeOracle(tradeOracle);
}
function completeTrade(bytes32 tradeId, bytes memory proof) public {
Trade memory trade = trades[tradeId];
require(trade.state == TradeState.Filled);
require(trade.expiration > now);
require(tradeVerifier.verifyTrade(hashAddresses[trade.buyer], hashAddresses[trade.seller], trade.amount, tradeId, proof));
trades[tradeId].state = TradeState.Closed;
balances[owner] += computeFee(trade.price) * 2; // change our balance
trade.seller.transfer(trade.deposit + trade.price);
}
function expireTrade(bytes32 tradeId) public onlyOwner {
Trade memory trade = trades[tradeId];
require(trade.state == TradeState.Filled);
require(trade.expiration < now);
trades[tradeId].state = TradeState.Closed;
balances[owner] += computeFee(trade.price) * 2; // change our balance
trade.buyer.transfer(trade.deposit + trade.price);
}
function linkHashAddress(bytes32 addressHash) public {
require(hashAddresses[msg.sender] == 0);
hashAddresses[msg.sender] = addressHash;
}
function linkHashAddress(address ethAddress, bytes32 addressHash) public onlyOwner {
hashAddresses[ethAddress] = addressHash;
}
function() external payable {
balances[msg.sender] += msg.value;
emit Deposit(msg.sender, msg.value);
}
// Anyone (including us) can only withdraw the amount allocated in balances.
// So we can only ever take the fees.
function withdraw(uint256 amount) public {
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount;
msg.sender.transfer(amount);
emit Withdrawal(msg.sender, amount);
}
// Anyone (including us) can only withdraw the amount allocated in balances.
// So we can only ever take the fees.
function withdraw(address payable user, uint256 amount) public onlyOwner {
require(balances[user] >= amount);
balances[user] -= amount;
user.transfer(amount);
emit Withdrawal(user, amount);
}
function makeTrade(bytes32 tradeId, address payable buyer, address payable seller, uint256 price, uint256 deposit, uint256 amount, uint256 expireAfter) public onlyOwner {
uint256 fee = computeFee(price);
require(balances[buyer] >= price + fee);
require(balances[seller] >= deposit + fee);
require(trades[tradeId].state == TradeState.None);
balances[buyer] -= (price + fee); // change buyer balance
balances[seller] -= (deposit + fee); // change seller balance
// notice how the fees are not accounted for here, they will be given to us only when the trade is complete or expired.
trades[tradeId] = Trade(buyer, seller, price, deposit, amount, now + (expireAfter * 1 hours), TradeState.Filled);
}
function computeFee(uint256 price) private pure returns (uint256) {
uint256 fee = price * 5;
require(fee / 5 == price); // Check overflow
return fee / 1000; // This is the fee we take on each side (0.5% * price)
}
}
pragma solidity >=0.5.0;
contract TradeOracle {
mapping (bytes32 => uint256) balances;
address owner;
address escrowContract;
modifier onlyOwner {
require(msg.sender == owner);
_;
}
modifier onlyEscrow {
require(msg.sender == escrowContract);
_;
}
constructor(address escrow) public {
owner = msg.sender;
escrowContract = escrow;
}
function setEscrowContract(address escrow) public onlyOwner {
escrowContract = escrow;
}
function recordSale(bytes32 seller, uint256 amount) external onlyEscrow returns (bool) {
require(balances[seller] >= amount);
balances[seller] -= amount;
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment