Some individuals missed out on purchasing the Golem Network Token (GNT) in the Golem Crowdfunding Funded To 820,000 ETH Cap, as the sale was over within ~ half an hour. The tokens were sold a 1 ether (ETH) = 1,000 GNTs, or 0.001 ETH per 1 GNT.
User /u/cintix on reddit.com/r/ethereum posted Trustless GNT Selling Contract stating:
I saw there was interest in a contract that sells GNT, so I made one! It sells 100,000 GNT at 2x crowdsale price. You just send ETH to it and it sends you GNT back! Be sure to check through the code and test with a small amount first!
See also Trustless GNT Selling Contract on reddit.com/r/ethtrader for many more contracts.
The code in this Trustless GNT Selling contract is based on user /u/JonnyLatte‘s code originally posted in Live testing ETH <-> Token, Atomic swap market to trade Augur REP tokens.
Table of contents
- cryptoderivatives.market
- Find GNT TokenTrader Contracts Script
- Find GNT TokenTrader Contracts In Ethereum Wallet/Mist
- Watch GNT TokenTrader Contract In Ethereum Wallet/Mist
- Trustless GNT Token Selling Contract
- The Original Trustless REP Token Trading Contract
cryptoderivatives.market
Check out the first version of https://cryptoderivatives.market/, a decentralised GNT/ETH exchange contracts market.
Find GNT TokenTrader Contracts Script
I’ve just created a script to list the TokenTrader contracts – see:
- Ethereum.StackExchange.com – How do I find a list of the Golem Network Token (GNT) TokenTrader contracts?
- Github – bokkypoobah/FindGNTTokenTrader
Find GNT TokenTrader Contracts In Ethereum Wallet/Mist
If you want to find the TokenTrader contracts that have been created by the TokenTraderFactory contract, add the TokenTraderFactor to your Watch Contracts. To do this, click on the Contracts tab and click Watch Token. Enter the GNTTokenTraderFactory
in the Contract Name field, 0xc4af56cd5254aef959d4bce2f75874007808b701
in the Contract Address field, and the following Application Binary Interace (ABI) data in the JSON Interface field and click OK:
[{"constant":false,"inputs":[{"name":"_asset","type":"address"},{"name":"_sellPrice","type":"uint256"},{"name":"_units","type":"uint256"},{"name":"_sellsTokens","type":"bool"}],"name":"createTradeContract","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"tradeContract","type":"address"}],"name":"verify","outputs":[{"name":"valid","type":"bool"},{"name":"asset","type":"address"},{"name":"sellPrice","type":"uint256"},{"name":"units","type":"uint256"},{"name":"sellsTokens","type":"bool"}],"payable":false,"type":"function"},{"payable":false,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"bookid","type":"bytes32"},{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"addr","type":"address"}],"name":"TradeListing","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"bookid","type":"bytes32"},{"indexed":false,"name":"asset","type":"address"},{"indexed":false,"name":"units","type":"uint256"}],"name":"NewBook","type":"event"}]
Now click on the GNTTOKENTRADERFACTORY contract in the Contracts tab. Scroll down and click the checkbox for Watch contract events. You will find the list of created TokenTrader contracts – the highlighted address is the address used in the next “Watch GNT TokenTrader Contract In Ethereum Wallet/Mist” section.
Watch GNT TokenTrader Contract In Ethereum Wallet/Mist
If you want to confirm the contract parameters for a TokenTrader contract in Mist, find the TokenTrader contract address your want to watch, e.g., #28 0x406a65de7a2e94ef19597a79296e269fada85a71, from the list generated in the “Find GNT TokenTrader Contracts” section above:
28 TokenTraderAddress: 0x406a65de7a2e94ef19597a79296e269fada85a71 Deployed : #2624456 at Mon, 14 Nov 2016 08:39:06 UTC txHash 0x0eca65c8457f60599d55dfe8554e9232b824eba714d941d318660d7e691629af Owner : 0x45689bac94edae26625521f1361748119f05fc30 Asset address : 0xa74476443119a942de498590fe1f2454d7d4ac0d GNT Sells tokens : true Sell price : 190 Units : 100000 Ethers per 1,000 tokens : 1.9 Current token balance : 195684.2105263157895 Current ether balance : 9.952798346
Use the following ABI:
[{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"withdraw","outputs":[{"name":"ok","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"asset","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"sellPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"sellsTokens","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"withdrawAsset","outputs":[{"name":"ok","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"units","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_token","type":"address"},{"name":"_value","type":"uint256"}],"name":"withdrawToken","outputs":[{"name":"ok","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"buy","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_sellsTokens","type":"bool"}],"name":"activate","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"type":"function"},{"inputs":[{"name":"_asset","type":"address"},{"name":"_sellPrice","type":"uint256"},{"name":"_units","type":"uint256"},{"name":"_sellsTokens","type":"bool"}],"type":"constructor"},{"payable":true,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sells","type":"bool"}],"name":"ActivatedEvent","type":"event"},{"anonymous":false,"inputs":[],"name":"UpdateEvent","type":"event"}]
Watch GNT Token In Ethereum Wallet/Mist
If you have not already added a Watch Token for the Golem Network Token in Ethereum Wallet / Mist, click on the Contracts tab and click on Watch Token. Enter the GNT TokenTrader address 0xa74476443119A942dE498590Fe1f2454d7D4aC0d
into the Token Contract Address field as shown below, then click OK:
In Ethereum Wallet / Mist, click on the Contracts tab and click on Watch Contract. I have entered the Contract Name of “GNTTokenTrader28”, the appropriate Contract Address and add the ABI above in the JSON Interface field, then click OK.
In Ethereum Wallet / Mist, click on the Contracts tab and click on your newly created Watch Contract. You will see the number of GNTs that the contract is selling:
Scrolling down the page, you will see the Read From Contract fields on the left side. You can find out the Sell Price (190 in contract #28), Units (100,000 in contract #28). The price per unit of GNT is 190 / 100,000 = 0.0019 ETH. The price per 1,000 GNTs is 1.9 ETH for this contract #28.
If you want to, you can execute the Buy function on the right side of the screen – test with a small amount first.
Trustless GNT Token Selling Contract
Following is the verified contact source for the GNT TokenTraderFactory
contract at 0xc4af56cd5254aef959d4bce2f75874007808b701. This factory contract is used to create TokenTrader
contracts as deployed to 0x399156ee3339f4b29a53e307b98cce09fda3bac7 for the 2x contract, and 0x4104e4b12e73bc99dd4f20a39525d07aa395c0d4 for the 3x contract:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
pragma solidity ^0.4.0; //https://github.com/nexusdev/erc20/blob/master/contracts/erc20.sol contract ERC20Constant { function balanceOf( address who ) constant returns (uint value); } contract ERC20Stateful { function transfer( address to, uint value) returns (bool ok); } contract ERC20Events { event Transfer(address indexed from, address indexed to, uint value); } contract ERC20 is ERC20Constant, ERC20Stateful, ERC20Events {} contract owned { address public owner; function owned() { owner = msg.sender; } modifier onlyOwner { if (msg.sender != owner) throw; _; } function transferOwnership(address newOwner) onlyOwner { owner = newOwner; } } // contract can sell tokens for ETH // prices are in amount of wei per batch of token units contract TokenTrader is owned { address public asset; // address of token uint256 public sellPrice; // contract sells lots of tokens at this price uint256 public units; // lot size (token-wei) bool public sellsTokens; // is contract selling event ActivatedEvent(bool sells); event UpdateEvent(); function TokenTrader ( address _asset, uint256 _sellPrice, uint256 _units, bool _sellsTokens ) { asset = _asset; sellPrice = _sellPrice; units = _units; sellsTokens = _sellsTokens; ActivatedEvent(sellsTokens); } // modify trading behavior function activate ( bool _sellsTokens ) onlyOwner { sellsTokens = _sellsTokens; ActivatedEvent(sellsTokens); } // allow owner to remove trade token function withdrawAsset(uint256 _value) onlyOwner returns (bool ok) { return ERC20(asset).transfer(owner,_value); UpdateEvent(); } // allow owner to remove arbitrary tokens // included just in case contract receives wrong token function withdrawToken(address _token, uint256 _value) onlyOwner returns (bool ok) { return ERC20(_token).transfer(owner,_value); UpdateEvent(); } // allow owner to remove ETH function withdraw(uint256 _value) onlyOwner returns (bool ok) { if(this.balance >= _value) { return owner.send(_value); } UpdateEvent(); } //user buys token with ETH function buy() payable { if(sellsTokens || msg.sender == owner) { uint order = msg.value / sellPrice; uint can_sell = ERC20(asset).balanceOf(address(this)) / units; if(order > can_sell) { uint256 change = msg.value - (can_sell * sellPrice); order = can_sell; if(!msg.sender.send(change)) throw; } if(order > 0) { if(!ERC20(asset).transfer(msg.sender,order * units)) throw; } UpdateEvent(); } else if(!msg.sender.send(msg.value)) throw; // return user funds if the contract is not selling } // sending ETH to contract sells GNT to user function () payable { buy(); } } // This contract deploys TokenTrader contracts and logs the event // trade pairs are identified with sha3(asset,units) contract TokenTraderFactory { event TradeListing(bytes32 bookid, address owner, address addr); event NewBook(bytes32 bookid, address asset, uint256 units); mapping( address => bool ) _verify; mapping( bytes32 => bool ) pairExits; function verify(address tradeContract) constant returns ( bool valid, address asset, uint256 sellPrice, uint256 units, bool sellsTokens ) { valid = _verify[tradeContract]; if(valid) { TokenTrader t = TokenTrader(tradeContract); asset = t.asset(); sellPrice = t.sellPrice(); units = t.units(); sellsTokens = t.sellsTokens(); } } function createTradeContract( address _asset, uint256 _sellPrice, uint256 _units, bool _sellsTokens ) returns (address) { if(_units == 0) throw; // can't sell zero units address trader = new TokenTrader ( _asset, _sellPrice, _units, _sellsTokens); var bookid = sha3(_asset,_units); _verify[trader] = true; // record that this factory created the trader TokenTrader(trader).transferOwnership(msg.sender); // set the owner to whoever called the function if(pairExits[bookid] == false) { pairExits[bookid] = true; NewBook(bookid, _asset, _units); } TradeListing(bookid,msg.sender,trader); } function () { throw; // Prevents accidental sending of ether to the factory } } |
Following are the instructions by /u/JonnyLatte posted at Trustless GNT Selling Contract for using the contract above:
Someone has asked me how to use my contract to sell GNT. I’m going to put the reply here so that I am not repeating myself:
I gave some simple instructions for using my platform to make your own trades here
It should be fine to sell GNT however I have not tested it and it wont be able to buy GNT only sell because GNT is missing the approve() and transferFrom() functions. Since these functions are not used for selling or adding and withdrawing funds from a trade contract it should not be a problem. I have not tested this though so if you do decide to use it you should test with a small amount first.
However since OP has gone to the trouble of stripping out the missing GNT functionality and is successfully selling I may as well show how to use this contract rather than my own.
First up let me describe a trade contract and then how to create one:
A trade contract holds funds and has an owner that can withdraw those funds to their account. To deposit tokens into it you just send them to its address. To withdraw them you call its withdrawToken function giving it the address of the token and the amount in that tokens smallest units.
The trade contract can also sell one token called the asset at a fixed rate that is determined when the contract is created. For ease of use you can also withdraw that token using withdrawAsset which does not require you to specify the address of the token because that was already given when the contract was created. I have pasted a copy of the trade contract’s ABI which the owners of a trade contract can use to follow instances for withdrawing funds.
You do not deploy a trade contract directly, instead you use a factory contract which creates an instance for you given the setup. You do that by following the factory address with the factory ABI and calling the function createTradeContract.
The parameters of createTradeContract for OP’s sell only factory are:
address _asset, uint256 _sellPrice, uint256 _units, bool _sellsTokensthe asset is the address of the token being sold. In the case of GNT thats 0xa74476443119A942dE498590Fe1f2454d7D4aC0d _sellPrice is the number of WEI the contract needs to be sent to send some tokens in return _units is how many of the smallest units of the token that are sent in return for sending _sellPrice amounts of WEI _sellsTokens should be set to true if you want the contract to immediately accept ETH and sell the token or false if you want to start with selling deactivated for the purpose of testing (the owner account will be able to sell to it but no one else until activate(true) is called)For example OP made the contract at 0x4104e4b12e73bc99dd4f20a39525d07aa395c0d4 selling GNT at 3x the crowd sale price. The parameters they used are:
address _asset = 0xa74476443119a942de498590fe1f2454d7d4ac0d (GNT) uint256 _sellPrice = 300 uint256 _units = 100000 bool _sellsTokens = trueI would suggest sticking with their choice of units and adjusting _sellPrice to fit whatever price level you want: 100 for the same price as the crowd sale 200 for double etc.
If you successfully create a trade contract the factory will fire off an event showing the address and owner. You can also see them at https://etherscan.io/address/0xc4af56cd5254aef959d4bce2f75874007808b701#internaltx and then follow the one you think is yours double checking you are the owner.
The Original Trustless REP Token Trading Contract
Following is the verified contact source for the original Augur REP TokenTraderFactory
contract at 0x3398080b81a1cff1429af347ce2b17fc28de3937 by /u/JonnyLatte. This factory contract then creates the TokenTrader
contract as deployed to 0x399156ee3339f4b29a53e307b98cce09fda3bac7. See The Original Augur REP TokenTraderFactory Contract for further information on this contract:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
pragma solidity ^0.4.0; //https://github.com/nexusdev/erc20/blob/master/contracts/erc20.sol contract ERC20Constant { function totalSupply() constant returns (uint supply); function balanceOf( address who ) constant returns (uint value); function allowance(address owner, address spender) constant returns (uint _allowance); } contract ERC20Stateful { function transfer( address to, uint value) returns (bool ok); function transferFrom( address from, address to, uint value) returns (bool ok); function approve(address spender, uint value) returns (bool ok); } contract ERC20Events { event Transfer(address indexed from, address indexed to, uint value); event Approval( address indexed owner, address indexed spender, uint value); } contract ERC20 is ERC20Constant, ERC20Stateful, ERC20Events {} contract owned { address public owner; function owned() { owner = msg.sender; } modifier onlyOwner { if (msg.sender != owner) throw; _; } function transferOwnership(address newOwner) onlyOwner { owner = newOwner; } } // contract can buy or sell tokens for ETH // prices are in amount of wei per batch of token units contract TokenTrader is owned { address public asset; // address of token uint256 public buyPrice; // contact buys lots of token at this price uint256 public sellPrice; // contract sells lots at this price uint256 public units; // lot size (token-wei) bool public sellsTokens; // is contract selling bool public buysTokens; // is contract buying event ActivatedEvent(bool sells, bool buys); event UpdateEvent(); function TokenTrader ( address _asset, uint256 _buyPrice, uint256 _sellPrice, uint256 _units, bool _sellsTokens, bool _buysTokens ) { asset = _asset; buyPrice = _buyPrice; sellPrice = _sellPrice; units = _units; sellsTokens = _sellsTokens; buysTokens = _buysTokens; ActivatedEvent(sellsTokens,buysTokens); } // modify trading behavior function activate ( bool _sellsTokens, bool _buysTokens ) onlyOwner { sellsTokens = _sellsTokens; buysTokens = _buysTokens; ActivatedEvent(sellsTokens,buysTokens); } // allows owner to deposit ETH // deposit tokens by sending them directly to contract // buyers must not send tokens to the contract, use: sell(...) function deposit() payable onlyOwner { UpdateEvent(); } // allow owner to remove trade token function withdrawAsset(uint256 _value) onlyOwner returns (bool ok) { return ERC20(asset).transfer(owner,_value); UpdateEvent(); } // allow owner to remove arbitrary tokens // included just in case contract receives wrong token function withdrawToken(address _token, uint256 _value) onlyOwner returns (bool ok) { return ERC20(_token).transfer(owner,_value); UpdateEvent(); } // allow owner to remove ETH function withdraw(uint256 _value) onlyOwner returns (bool ok) { if(this.balance >= _value) { return owner.send(_value); } UpdateEvent(); } //user buys token with ETH function buy() payable { if(sellsTokens || msg.sender == owner) { uint order = msg.value / sellPrice; uint can_sell = ERC20(asset).balanceOf(address(this)) / units; if(order > can_sell) { uint256 change = msg.value - (can_sell * sellPrice); order = can_sell; if(!msg.sender.send(change)) throw; } if(order > 0) { if(!ERC20(asset).transfer(msg.sender,order * units)) throw; } UpdateEvent(); } else if(!msg.sender.send(msg.value)) throw; // return user funds if the contract is not selling } // user sells token for ETH // user must set allowance for this contract before calling function sell(uint256 amount) { if (buysTokens || msg.sender == owner) { uint256 can_buy = this.balance / buyPrice; // token lots contract can buy uint256 order = amount / units; // token lots available if(order > can_buy) order = can_buy; // adjust order for funds if (order > 0) { // extract user tokens if(!ERC20(asset).transferFrom(msg.sender, address(this), amount)) throw; // pay user if(!msg.sender.send(order * buyPrice)) throw; } UpdateEvent(); } } // sending ETH to contract sells ETH to user function () payable { buy(); } } // This contract deploys TokenTrader contracts and logs the event // trade pairs are identified with sha3(asset,units) contract TokenTraderFactory { event TradeListing(bytes32 bookid, address owner, address addr); event NewBook(bytes32 bookid, address asset, uint256 units); mapping( address => bool ) _verify; mapping( bytes32 => bool ) pairExits; function verify(address tradeContract) constant returns ( bool valid, address asset, uint256 buyPrice, uint256 sellPrice, uint256 units, bool sellsTokens, bool buysTokens ) { valid = _verify[tradeContract]; if(valid) { TokenTrader t = TokenTrader(tradeContract); asset = t.asset(); buyPrice =t.buyPrice(); sellPrice = t.sellPrice(); units = t.units(); sellsTokens = t.sellsTokens(); buysTokens = t.buysTokens(); } } function createTradeContract( address _asset, uint256 _buyPrice, uint256 _sellPrice, uint256 _units, bool _sellsTokens, bool _buysTokens ) returns (address) { if(_buyPrice > _sellPrice) throw; // must make profit on spread if(_units == 0) throw; // can't sell zero units address trader = new TokenTrader ( _asset, _buyPrice, _sellPrice, _units, _sellsTokens, _buysTokens); var bookid = sha3(_asset,_units); _verify[trader] = true; // record that this factory created the trader TokenTrader(trader).transferOwnership(msg.sender); // set the owner to whoever called the function if(pairExits[bookid] == false) { pairExits[bookid] = true; NewBook(bookid, _asset, _units); } TradeListing(bookid,msg.sender,trader); } function () { throw; // Prevents accidental sending of ether to the factory } } |