A generic auction implementation in Solidity that allows managed bids from backend and supports bids in ERC20 tokens.
The file app.js
has a simple web proxy to make transactions and read contracts state and events via http (origin).
An example of advanced proxy implementation that is written in TypeScript and uses strongly-typed contracts generated by Soltsice library could be found here.
npm install -g truffle
if it is not installed already.truffle compile --all
- to compile contracts (deletebuild
folder before this command if something breaks in a weird way after this step and try again).npm run dist
- to copy artifcats and pack generated contracts indist
folder. A further call tonpm pack
/npm publish
produces an isomorphic package with TypeScript contracts that could be used from DApps or Node.js (using Soltsice library).npm test
- for tests on in-process TestRPC (Ganache) and examples of generated contracts usage.npm run dev
- to run test server with nodemon.npm start
- to run production server.
Need to save owner private key in config/config.json
as hex.
curl --request POST \
--url http://localhost:3000/getTransaction \
--header 'content-type: application/json' \
--data '{"args": ["0xfe42d74d7ea48402aa901d3eca295e6ffe1e17e7526b728e32db9bbab0fe1d9c"]}'
!IMPORTANT! Wallet must be a normal contract or a wallet contract that supports ERC20 tokens in the case when token payments are supported, otherwise tokens will be lost (https://www.reddit.com/r/ethereum/comments/60ql37/attention_be_careful_using_ethereum_tokens/)
- at - address of deployed factory, should be a part of a config
- args - correspond to solidity signature:
address _owner, address _wallet, address _token, uint _endSeconds, uint256 _weiPerToken, string _item, uint256 _minPrice, bool _allowManagedBids
- _owner - account managing the auction process: '0xHexOfOwnerAddress'
- _wallet - account that will receive payments when the auction ends: '0xHexOfWalletAddress'
- _token - address of a deployed token, use '0x06147110022B768BA8F99A8f385df11a151A9cc8' for AceToken on mainnet
- _endSeconds - end time in Unix seconds, 1514160000 for Dec 25, 2017 (need to double check!)
- _weiPerToken - exchange rate of one token to Ether wei (1e-18), 0.0001 BTC is approximately 2400000000000000
- _maxTokens - max tokens to accept (must be below 1000 for Ace)
- _item - short string desciption of an item
- _minPrice - min item price in wei
- _allowManagedBids - allow managed bids in fiat/BTC from backend, should be true
curl --request POST \
--url http://localhost:3000/contract \
--header 'content-type: application/json' \
--data '{"contract": "AuctionFactory",
"method": "produceForOwnerCustomToken",
"at": "0xHexOfAuctionFactoryAddress",
"args": ["0xHexOfOwnerAddress", "0xHexOfWalletAddress", "0x06147110022B768BA8F99A8f385df11a151A9cc8", 1514160000, 2400000000000000, 50, "test_item", true ]}'
{
"result": "0xfe42d74d7ea48402aa901d3eca295e6ffe1e17e7526b728e32db9bbab0fe1d9c",
"statusCode": 200
}
Mined transactions returns a receipt with new Auction contract address available as: auctionTx.logs[0].args.addr
- at - address of deployed auction, should be a part of a config (if deployed manually) or stored somewhere from factory calls
- args - correspond to solidity signature:
uint64 _managedBidder, uint256 _managedBid
- _managedBidder - intenal id of managed bidder, managed on backend
- _managedBid - bid in Ether Wei (1e-18 unit). Could be a problem with large values, need to test. Will make a wrapper if long numbers cannot be deserialized correctly.
curl --request POST \
--url http://localhost:3000/contract \
--header 'content-type: application/json' \
--data '{"contract": "Auction",
"method": "managedBid",
"at": "0xHexOfAuctionAddress",
"args": [42, 123000000000000000000 ]}'
{
"result": "0xfe42d74d7ea48402aa901d3eca295e6ffe1e17e7526b728e32db9bbab0fe1d9c",
"statusCode": 200
}
- at - address of deployed auction, should be a part of a config (if deployed manually) or stored somewhere from factory calls
- args - correspond to solidity signature:
uint64 _managedBidder, uint256 _managedBid, address _knownManagedBidder
- _managedBidder - intenal id of managed bidder, managed on backend
- _managedBid - bid in Ether Wei (1e-18 unit). Could be a problem with large values, need to test. Will make a wrapper if long numbers cannot be deserialized correctly.
- _knownManagedBidder - Ethereum address of bidder to sum direct and managed bids.
curl --request POST \
--url http://localhost:3000/contract \
--header 'content-type: application/json' \
--data '{"contract": "Auction",
"method": "managedBid2",
"at": "0xHexOfAuctionAddress",
"args": [42, 123000000000000000000, '0x39a0951b13931b5bA8d97EfF4b3F66696aDfF16F' ]}'
{
"result": "0xfe42d74d7ea48402aa901d3eca295e6ffe1e17e7526b728e32db9bbab0fe1d9c",
"statusCode": 200
}
Same as above, a single parameter: uint256 _weiPerToken
must meet the requirement: require (_weiPerToken > (1e15) && _weiPerToken < 5 * (1e15));
We could update the rate daily. Could be called only by owner.
End auction (after end date), could be called only by owner. Will transfer the highest bid - if it is in Ether - to the wallet address
curl --request POST \
--url http://localhost:3000/contract \
--header 'content-type: application/json' \
--data '{"contract": "Auction",
"method": "finalizeAuction",
"at": "0xHexOfAuctionAddress",
"args": []}'
{
"result": "0xfe42d74d7ea48402aa901d3eca295e6ffe1e17e7526b728e32db9bbab0fe1d9c",
"statusCode": 200
}
curl --request POST \
--url http://localhost:3000/contract \
--header 'content-type: application/json' \
--data '{"contract": "Auction",
"method": "cancelAuction",
"at": "0xHexOfAuctionAddress",
"args": []}'
{
"result": "0xfe42d74d7ea48402aa901d3eca295e6ffe1e17e7526b728e32db9bbab0fe1d9c",
"statusCode": 200
}
Methods highestBidder
, highestManagedBidder
, highestBid
with no args.
!NB! Could also parse events - there is an event NewHighestBidder with three parameters: NewHighestBidder(address indexed bidder, uint64 indexed managedBidder, uint256 indexed bid);
If managedBidder is zero then Ethereum direct bidder is the highest. bid
is in wei tokens, need to test parsing.
curl --request POST \
--url http://localhost:3000/contract \
--header 'content-type: application/json' \
--data '{"contract": "Auction",
"method": "highestBidder",
"at": "0xHexOfAuctionAddress",
"args": []}'
{
"result": "...value or address...",
"statusCode": 200
}
Get request: http://localhost:3000/events/0x305d46467b8c2ebf89b154f8f0c27d9aee75271f/1391507
http://localhost:3000/events/[0xContractAddress]/[block_number]
- block_number could be ommited and then set to zero
- if there are too many events then use block number from the lastest block minus 1 (without decrementing there is a risk of missing some event)
curl --request POST --url http://localhost:3000/events --header 'content-type: application/json' --data '{"contract": "Auction", "at": "0x305d46467b8c2ebf89b154f8f0c27d9aee75271f"}'
{
"result": [array of event logs],
"statusCode": 200
}
Sample output:
{"result":[{"address":"0x305d46467b8c2EBf89B154f8F0c27D9aee75271F","blockNumber":1391507,"transactionHash":"0x1a1e5a963848cdbbcea114ae6528b788ceebd482d3c8a918ce2f4195fcb9421f","transactionIndex":1,"blockHash":"0x7306d6c8febd0fca10a28c809d685cee6d3849e2173ec9258173ec78b94f39e4","logIndex":2,"removed":false,"id":"log_b5db72b8","returnValues":{"0":"0","1":"0","bidder":"0","bid":"0"},"event":"ManagedBid","signature":"0x18a7ab87afd10104bc436ca632cd189b747830ba7bbdb1729260ca549ac16e6b","raw":{"data":"0x0000000000000000000000000000000000000000000000000001639167c890b900000000000000000000000000000000000000000000000000110d9316ec0000","topics":["0x18a7ab87afd10104bc436ca632cd189b747830ba7bbdb1729260ca549ac16e6b"]}}],"statusCode":200}
MIT