Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions DEV_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Hello wonderful veil devs!

To start off I would like to apologize in advance for being horrifically unprofessional ;)

I'm making this pull request because one day while I was shamelessly copying your virtual augur shares for my own project I noticed that you were not using
the clone factory optimization. This dissapointed me because I want to do as little work as possible and it meant I would have to add it myself :(
So instead of remaking all your contracts and testing them like a responsible adult I figured I would just haphazardly throw some extra functionality in
just enough so it compiles and barely works and let you guys do the rest. So without further ado here is my explanation of whats going on in these changes

first of all most of the changes are changing syntax or adding explicit conversions to make newer compiler versions happy so you can ignore 90% of my changes

Secondly I suppose I should somewhat explain what the cloneFactory does, here are some links (https://github.com/optionality/clone-factory) (https://github.com/optionality/EIPs/blob/master/EIPS/eip-1167.md)

basically it makes cheap clones of existing contracts with separate state. I'd tell you more, but I'm not smart enough to have any idea how it actually works.
Did I say cheap clones? I meant VERY cheap clones, by my calculations this will save your users approximately 10 metric fucktons of gas every time they create a new market. (in all seriousness you're looking at about a >90% gas cost reduction)

Here's an example of Augur itself using the clone factory BTW (https://github.com/AugurProject/augur/blob/master/packages/augur-core/source/contracts/factories/ShareTokenFactory.sol)

And finally onto the changes....

The first thing you will notice is that I've added two files CloneFactory.sol and CloneFactory16.sol, these are straight out of the clone factory library.

next there are important changes in VirtualAugurShare and VirtualAugurShareFactory. I removed the constructor in VirtualAugurShare and added some initialization
functions, this is because the cloneFactory can't call the constructor when making a clone. The initialization function just does everything the constructor does. I
also added an extra modifier so those initialization functions can only be called once.

In VirtualAugurShareFactory I imported CloneFactory16, this is an extra optimization that I will discuss later. CloneFactory16 can just be considered the regular
CloneFactory for now. Inheriting from CloneFactory gives us the createClone method which takes the address of the deployed VirtualAugurShare contract and clones it
cheaply, returning the address of the cloned contract. We call createClone in the create() function and then call the initialization functions in the new clone and
we're all done!

Now for the extra optimization: CloneFactory16 shaves off the first four 0's of a contract address so that it uses even less storage on the EVM. So by creating a
vanity contract address using vanity-eth (https://github.com/MyEtherWallet/VanityEth) with the command vanity-eth -i 0000 --contract, we can make our clones even
cheaper! You will notice that the address of the contract being cloned starts with four 0's for this reason. I have edited the ganache.sh file to initialize ganache
with one such vanity address (0xb142bee56c35df2906f013edfffe901c0b2502b9) private key: 0xa66195e41058b11e278a65c0e811944857c08d78d618e1fffdcc99cf3e9cec5a
the other account is used to deploy the contracts other than VirtualAugurShare because the vanity address will can only create its first ever contract with four
leading 0's. I have also modified the migrations scripts so that each contract is deployed by the correct address.

I think that just about covers it, if you have any questions I'll be in your discord most evenings. Thanks so much by the way for helping to grow augur :)
you guys are pioneers <3
55 changes: 55 additions & 0 deletions contracts/CloneFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
pragma solidity >=0.4.23;

/*
The MIT License (MIT)
Copyright (c) 2018 Murray Software, LLC.
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.
*/
//solhint-disable max-line-length
//solhint-disable no-inline-assembly

contract CloneFactory {

function createClone(address target) internal returns (address result) {
bytes20 targetBytes = bytes20(target);
assembly {
let clone := mload(0x40)
mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(clone, 0x14), targetBytes)
mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
result := create(0, clone, 0x37)
}
}

function isClone(address target, address query) internal view returns (bool result) {
bytes20 targetBytes = bytes20(target);
assembly {
let clone := mload(0x40)
mstore(clone, 0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000)
mstore(add(clone, 0xa), targetBytes)
mstore(add(clone, 0x1e), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)

let other := add(clone, 0x40)
extcodecopy(query, other, 0, 0x2d)
result := and(
eq(mload(clone), mload(other)),
eq(mload(add(clone, 0xd)), mload(add(other, 0xd)))
)
}
}
}
56 changes: 56 additions & 0 deletions contracts/CloneFactory16.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
pragma solidity >=0.4.23;

/*
The MIT License (MIT)
Copyright (c) 2018 Murray Software, LLC.
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.
*/
//solhint-disable max-line-length
//solhint-disable no-inline-assembly

contract CloneFactory16 {

function createClone(address target) internal returns (address result) {
bytes20 targetBytes = bytes20(target)<<32;//offset target address by 32 bytes for the four leading zeroes in the vanity contract address
assembly {
let clone := mload(0x40)
mstore(clone, 0x3d602980600a3d3981f3363d3d373d3d3d363d6f000000000000000000000000)
mstore(add(clone, 0x14), targetBytes)
mstore(add(clone, 0x24), 0x5af43d82803e903d91602757fd5bf30000000000000000000000000000000000)
result := create(0, clone, 0x33)
}
}

function isClone(address target, address query) internal view returns (bool result) {
bytes20 targetBytes = bytes20(target)<<32;
assembly {
let clone := mload(0x40)
mstore(clone, 0x363d3d373d3d3d363d6f00000000000000000000000000000000000000000000)
mstore(add(clone, 0xa), targetBytes)
mstore(add(clone, 0x1a), 0x5af43d82803e903d91602757fd5bf30000000000000000000000000000000000)

let other := add(clone, 0x40)
extcodecopy(query, other, 0, 0x29)

result := and(
eq(mload(clone), mload(other)),
eq(mload(add(clone, 0x20)), mload(add(other, 0x20)))
)
}
}
}
2 changes: 1 addition & 1 deletion contracts/Migrations.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity 0.4.24;
pragma solidity >=0.4.24;


/**
Expand Down
6 changes: 3 additions & 3 deletions contracts/UnlimitedAllowanceToken.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity 0.4.24;
pragma solidity >=0.4.24;

import { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol";
import { IERC20 } from "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
Expand All @@ -17,7 +17,7 @@ contract UnlimitedAllowanceToken is IERC20 {

/* ============ State variables ============ */

uint256 public totalSupply;
uint256 public supply;
mapping (address => uint256) public balances;
mapping (address => mapping (address => uint256)) public allowed;

Expand Down Expand Up @@ -67,6 +67,6 @@ contract UnlimitedAllowanceToken is IERC20 {
}

function totalSupply() public view returns (uint256) {
return totalSupply;
return supply;
}
}
10 changes: 5 additions & 5 deletions contracts/VeilCompleteSets.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity 0.4.24;
pragma solidity >=0.4.24;

import { IERC20 } from "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import { VirtualAugurShare } from "./VirtualAugurShare.sol";
Expand Down Expand Up @@ -64,7 +64,7 @@ contract VeilCompleteSets {
/**
* @dev Fallback function
*/
function() public {
function() external {
revert("Fallback function reverts");
}

Expand All @@ -85,7 +85,7 @@ contract VeilCompleteSets {
require(_amount.mul(IMarket(_augurMarket).getNumTicks()) == msg.value, "Msg.value is incorrect");

// Deposit Cash and buy complete sets
if (ICash(_augurCash).allowance(this, _augurContract) != uint256(-1)) {
if (ICash(_augurCash).allowance(address(this), _augurContract) != uint256(-1)) {
require(ICash(_augurCash).approve(_augurContract, uint256(-1)), "Cash approval failed");
}
ICash(_augurCash).depositEther.value(msg.value)();
Expand All @@ -95,11 +95,11 @@ contract VeilCompleteSets {
IERC20 augurLongToken = IERC20(IMarket(_augurMarket).getShareToken(1));
IERC20 augurShortToken = IERC20(IMarket(_augurMarket).getShareToken(0));

if (augurLongToken.allowance(this, _virtualLongToken) != uint256(-1)) {
if (augurLongToken.allowance(address(this), _virtualLongToken) != uint256(-1)) {
require(augurLongToken.approve(_virtualLongToken, uint256(-1)), "Long approval failed");
}

if (augurShortToken.allowance(this, _virtualShortToken) != uint256(-1)) {
if (augurShortToken.allowance(address(this), _virtualShortToken) != uint256(-1)) {
require(augurShortToken.approve(_virtualShortToken, uint256(-1)), "Short approval failed");
}

Expand Down
6 changes: 3 additions & 3 deletions contracts/VeilEther.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity 0.4.24;
pragma solidity >=0.4.24;

import { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol";
import { UnlimitedAllowanceToken } from "./UnlimitedAllowanceToken.sol";
Expand Down Expand Up @@ -33,7 +33,7 @@ contract VeilEther is UnlimitedAllowanceToken {
/**
* @dev Fallback function can be used to buy tokens by proxying the call to deposit()
*/
function() public payable {
function() external payable {
deposit();
}

Expand All @@ -57,7 +57,7 @@ contract VeilEther is UnlimitedAllowanceToken {
* @param _amount Amount to withdraw
* @param _target Address to send the withdrawn ETH
*/
function withdrawAndTransfer(uint256 _amount, address _target) public returns (bool) {
function withdrawAndTransfer(uint256 _amount, address payable _target) public returns (bool) {
require(balances[msg.sender] >= _amount, "Insufficient user balance");
require(_target != address(0), "Invalid target address");

Expand Down
35 changes: 18 additions & 17 deletions contracts/VirtualAugurShare.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma solidity 0.4.24;
pragma solidity >=0.4.24;

import { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol";
import { IERC20 } from "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
Expand Down Expand Up @@ -36,27 +36,12 @@ contract VirtualAugurShare is UnlimitedAllowanceToken, Ownable {
event Withdrawal(address indexed src, uint256 amount);
event SetToken(address indexed token);

/* ============ Constructor ============ */

/**
* Constructor function for VirtualAugurShare token
*
* @param _token Underlying ERC-20 token address to wrap
* @param _defaultSpender This address will have unlimited allowance by default
*/
constructor(address _token, address _defaultSpender) public {
require(_defaultSpender != address(0), "Invalid defaultSpender address");

token = _token;
defaultSpender = _defaultSpender;
}

/* ============ Public Functions ============ */

/**
* @dev Fallback function
*/
function() public {
function() external {
revert("Fallback function reverts");
}

Expand All @@ -70,6 +55,11 @@ contract VirtualAugurShare is UnlimitedAllowanceToken, Ownable {
_;
}

modifier whenDefaultSpenderIsNotSet {
require(defaultSpender == address(0), "Default spender is already set");
_;
}

/**
* Sets the underlying ERC-20 token of the VirtualAugurShare. Only callable by the owner when
* when the token is not address(0)
Expand All @@ -82,6 +72,17 @@ contract VirtualAugurShare is UnlimitedAllowanceToken, Ownable {
return true;
}

/**
* Sets the default spender (0x contract) of the VirtualAugurShare. Only callable by the owner when
* when the default spender is not address(0)
*
* @param _defaultSpender default spender address (0x contract)
*/
function setDefaultSpender(address _defaultSpender) public onlyOwner whenDefaultSpenderIsNotSet returns (bool) {
defaultSpender = _defaultSpender;
return true;
}

/**
* Buys tokens with the underlying token, exchanging them 1:1 and sets the spender allowance.
* Only callable when token is not address(0)
Expand Down
11 changes: 7 additions & 4 deletions contracts/VirtualAugurShareFactory.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pragma solidity 0.4.24;
pragma solidity >=0.4.24;

import { VirtualAugurShare } from "./VirtualAugurShare.sol";
import { CloneFactory16 } from "./CloneFactory16.sol";


/**
Expand All @@ -9,7 +10,7 @@ import { VirtualAugurShare } from "./VirtualAugurShare.sol";
*
* Token factory that creates new VirtualAugurShares
*/
contract VirtualAugurShareFactory {
contract VirtualAugurShareFactory is CloneFactory16 {

/* ============ Events ============ */

Expand All @@ -29,8 +30,10 @@ contract VirtualAugurShareFactory {
* @param _defaultSpender This address will have unlimited allowance by default
*/
function create(address _token, address _defaultSpender) public returns (address) {
address virtualToken = new VirtualAugurShare(_token, _defaultSpender);
address virtualToken = createClone(address(0x00004a7b379d528BB7CC9A9071E2754966463FEd));//this is the address of the deployed VirtualAugurShare contract ~~~~~~replace with new value on main net~~~~~~
VirtualAugurShare(virtualToken).transferOwnership(msg.sender);
require(VirtualAugurShare(virtualToken).setToken(_token));
require(VirtualAugurShare(virtualToken).setDefaultSpender(_defaultSpender));

emit TokenCreation(_token, virtualToken, _defaultSpender);
return virtualToken;
Expand All @@ -42,7 +45,7 @@ contract VirtualAugurShareFactory {
* @param _tokens Array of underlying ERC-20 token address to wrap
* @param _defaultSpenders Array of addresses that will have unlimited allowance by default
*/
function batchCreate(address[] _tokens, address[] _defaultSpenders) public returns (address[]) {
function batchCreate(address[] memory _tokens, address[] memory _defaultSpenders) public returns (address[] memory) {
require(_tokens.length == _defaultSpenders.length, "Mismatch of token and spender counts");

address[] memory virtualTokens = new address[](_tokens.length);
Expand Down
3 changes: 2 additions & 1 deletion ganache.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ while [ "$1" != "" ]; do
shift
done

ganache-cli -b 1 -l 300000000 -p $PORT -e 100000 --mnemonic "almost nasty switch remind embark holiday seminar decline space unable all evil"
ganache-cli -b 1 -l 300000000 -p $PORT -a 10 -e 100000 --account 0xa66195e41058b11e278a65c0e811944857c08d78d618e1fffdcc98cf3e9cec5a,100000000000000 0xa66195e41058b11e278a65c0e811944857c08d78d618e1fffdcc99cf3e9cec5a,1000000000000000000000

2 changes: 1 addition & 1 deletion migrations/1_initial_migration.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const Migrations = artifacts.require("Migrations");

module.exports = function(deployer, _, accounts) {
deployer.deploy(Migrations);
deployer.deploy(Migrations, {from: "0x5680ca2e3b4f8bc043aceb31837c89dba8bfba75"});
};
8 changes: 5 additions & 3 deletions migrations/2_deploy_contracts.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
const VeilEther = artifacts.require("VeilEther");
const VirtualAugurShareFactory = artifacts.require("VirtualAugurShareFactory");
const VeilCompleteSets = artifacts.require("VeilCompleteSets");
const VirtualAugurShare = artifacts.require("VirtualAugurShare")

module.exports = function(deployer, network, accounts) {
deployer.then(async () => {
await deployer.deploy(VeilEther);
await deployer.deploy(VirtualAugurShareFactory);
await deployer.deploy(VeilCompleteSets);
await deployer.deploy(VirtualAugurShare, {from: "0xb142bee56c35df2906f013edfffe901c0b2502b9"});//vanity contract address
await deployer.deploy(VeilEther, {from: "0x5680ca2e3b4f8bc043aceb31837c89dba8bfba75"});
await deployer.deploy(VirtualAugurShareFactory, {from: "0x5680ca2e3b4f8bc043aceb31837c89dba8bfba75"});
await deployer.deploy(VeilCompleteSets, {from: "0x5680ca2e3b4f8bc043aceb31837c89dba8bfba75"});
});
};