├── .gitignore ├── truffle.js ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── Dockerfile ├── circle.yml ├── README.md ├── package.json ├── contracts ├── Migrations.sol ├── EventethController.sol └── Eventeth.sol ├── LICENSE └── test ├── eventethcontroller.js └── eventeth.js /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules 3 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | } 4 | }; 5 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | var EventethController = artifacts.require("./EventethController.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(EventethController); 5 | }; 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:8 2 | 3 | ADD package*.json ./ 4 | RUN npm install 5 | 6 | ADD contracts contracts 7 | ADD migrations migrations 8 | ADD test test 9 | ADD truffle.js ./ 10 | 11 | CMD ["npm", "test"] 12 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | machine: true 5 | steps: 6 | - checkout 7 | - run: 8 | name: build 9 | command: docker build -t tester . 10 | - run: 11 | name: test 12 | command: docker run tester 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eventeth-contracts 2 | 3 | [![CircleCI](https://circleci.com/gh/y-matsuwitter/eventeth-contracts.svg?style=svg&circle-token=36a001c1910ea5d81b1c21b791c16c6016eee539)](https://circleci.com/gh/y-matsuwitter/eventeth-contracts) 4 | 5 | ## What's this? 6 | Ethereum contracts for a decentralized event management tool. 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eventeth-contracts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "devDependencies": { 10 | "truffle": "^4.0.1" 11 | }, 12 | "scripts": { 13 | "start": "truffle develop", 14 | "test": "truffle compile && truffle test" 15 | }, 16 | "author": "y-matsuwitter", 17 | "license": "MIT" 18 | } 19 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.4; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | modifier restricted() { 8 | if (msg.sender == owner) _; 9 | } 10 | 11 | function Migrations() { 12 | owner = msg.sender; 13 | } 14 | 15 | function setCompleted(uint completed) restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 y_matsuwitter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /contracts/EventethController.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | 3 | import "./Eventeth.sol"; 4 | 5 | contract EventethController { 6 | address owner; 7 | 8 | address[] events; 9 | mapping (address => uint[]) organizerEvents; 10 | 11 | event EventCreated( 12 | address eventAddress, 13 | address _organizer, string _name, 14 | uint _registrationStarted, uint _registrationEnded, 15 | uint _minimumGuarantee, uint _capacity); 16 | 17 | function EventethController() public { 18 | owner = msg.sender; 19 | } 20 | 21 | function createEvent(address _organizer, string _name, uint _registrationStarted, uint _registrationEnded, uint _minimumGuarantee, uint _capacity) 22 | public 23 | returns (address eventAddr) 24 | { 25 | eventAddr = new Eventeth(_organizer, _name, _registrationStarted, _registrationEnded, _minimumGuarantee, _capacity, owner); 26 | uint idx = events.length; 27 | events.push(eventAddr); 28 | organizerEvents[_organizer].push(idx); 29 | EventCreated(eventAddr, _organizer, _name, now, _registrationEnded, _minimumGuarantee, _capacity); 30 | } 31 | 32 | function getOrganizerEvents(address _organizer) 33 | public 34 | constant 35 | returns (address[] _events) 36 | { 37 | var evts = organizerEvents[_organizer]; 38 | _events = new address[](evts.length); 39 | for (uint i = 0; i < evts.length; i++) { 40 | _events[i] = events[evts[i]]; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/eventethcontroller.js: -------------------------------------------------------------------------------- 1 | var EV = artifacts.require("./Eventeth.sol"); 2 | var EVC = artifacts.require("./EventethController"); 3 | 4 | contract('EventethController', function(accounts) { 5 | let evc; 6 | 7 | beforeEach(async function(){ 8 | evc = await EVC.new() 9 | }) 10 | 11 | it("should create event.", async function() { 12 | const name = "test event"; 13 | 14 | let tx = await evc.createEvent(accounts[0], name, 15 | Math.floor(new Date().getTime()/1000) - 24*60*60, 16 | Math.floor(new Date().getTime()/1000) + 24*60*60, 17 | web3.toWei("0.01", "ether"), 10, {from: accounts[0]}) 18 | 19 | assert.equal(tx.logs.length, 1, "EventCreated event should be omitted."); 20 | assert.equal(tx.logs[0].event, "EventCreated", "EventCreated event should be omitted."); 21 | 22 | const evAddr = tx.logs[0].args.eventAddress; 23 | let events = await evc.getOrganizerEvents(accounts[0]) 24 | assert.notEqual(events.indexOf(evAddr), -1) 25 | 26 | let ev = await EV.at(evAddr); 27 | assert.equal(await ev.name(), name) 28 | }); 29 | 30 | it("should returns organizer's event.", async function() { 31 | const name = "test event"; 32 | await evc.createEvent(accounts[0], name, 33 | Math.floor(new Date().getTime()/1000) - 24*60*60, 34 | Math.floor(new Date().getTime()/1000) + 24*60*60, 35 | web3.toWei("0.01", "ether"), 10, {from: accounts[0]}) 36 | 37 | const evs = await evc.getOrganizerEvents.call(accounts[0]) 38 | assert.equal(evs.length, 1) 39 | const ev = await EV.at(evs[0]) 40 | assert.equal(await ev.organizer(), accounts[0]) 41 | assert.equal(await ev.name(), name) 42 | }) 43 | }); 44 | -------------------------------------------------------------------------------- /contracts/Eventeth.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.15; 2 | 3 | /* Eventeth is a contract to manage event registration and auctions. 4 | * TODO: 5 | * - cancellation from Eventeth owner. 6 | * - cancellation from EventethController owner. 7 | */ 8 | contract Eventeth { 9 | address public organizer; 10 | address public owner; // owner of EventethConroller 11 | string public name; 12 | uint public registrationStarted; 13 | uint public registrationEnded; 14 | uint public minimumGuarantee; 15 | uint public capacity; 16 | bool public canceled = false; 17 | 18 | uint private constant OWNER_FEE = 100; 19 | uint private constant FEE_PRECISION = 10000; 20 | 21 | struct Candidate { 22 | address registrant; 23 | string name; 24 | uint fee; 25 | } 26 | 27 | event Canceled(address _eventAddress, string _name); 28 | event Registered(address _registrant, string _name); 29 | event Deregistered(address _registrant, string _name); 30 | event RequestedDelegation(address _registrant, string _name, uint _fee); 31 | event CancelDelegation(address _registrant, string _name, uint _fee); 32 | event AcquiredDelegation(address _registrant, string _name, uint _fee); 33 | event RegistrantApproved(address[] _registrants); 34 | 35 | /* TODO: make these to private */ 36 | Candidate[] public candidates; 37 | address[] public invitations; 38 | mapping (address => Candidate) public approved; 39 | mapping (address => uint) public refunds; 40 | mapping (address => Candidate) public delegations; 41 | 42 | modifier duringRegistrationPeriod() { 43 | require(now > registrationStarted); 44 | require(now <= registrationEnded); 45 | _; 46 | } 47 | 48 | modifier afterRegistrationEnd() { 49 | require(now > registrationEnded); 50 | _; 51 | } 52 | 53 | modifier beforeRegistrationEnd() { 54 | require(now <= registrationEnded); 55 | _; 56 | } 57 | 58 | modifier notCanceled() { 59 | require(!canceled); 60 | _; 61 | } 62 | 63 | modifier onlyOrganizer() { 64 | require(organizer == msg.sender); 65 | _; 66 | } 67 | 68 | modifier onlyAdministrator() { 69 | require(organizer == msg.sender || owner == msg.sender); 70 | _; 71 | } 72 | 73 | function Eventeth(address _organizer, string _name, uint _registrationStarted, uint _registrationEnded, 74 | uint _minimumGuarantee, uint _capacity, address _owner) 75 | public payable 76 | { 77 | organizer = _organizer; 78 | owner = _owner; 79 | name = _name; 80 | registrationStarted = _registrationStarted; 81 | registrationEnded = _registrationEnded; 82 | minimumGuarantee = _minimumGuarantee; 83 | capacity = _capacity; 84 | } 85 | 86 | function register(string _name) 87 | public 88 | payable 89 | duringRegistrationPeriod() 90 | notCanceled() 91 | { 92 | require(msg.value >= minimumGuarantee); 93 | 94 | var c = getCandidate(msg.sender); 95 | 96 | addCandidate(msg.sender, _name, msg.value); 97 | Registered(msg.sender, _name); 98 | if (c.registrant == msg.sender) { 99 | msg.sender.transfer(c.fee); 100 | } 101 | } 102 | 103 | function deregister() 104 | public 105 | duringRegistrationPeriod() 106 | notCanceled() 107 | returns (bool success) 108 | { 109 | var c = getCandidate(msg.sender); 110 | if (c.registrant == msg.sender) { 111 | removeCandidate(msg.sender); 112 | uint refund = refunds[msg.sender] + c.fee; 113 | msg.sender.transfer(refund); 114 | refunds[msg.sender] = 0; 115 | Deregistered(msg.sender, c.name); 116 | success = true; 117 | }else{ 118 | success = false; 119 | } 120 | } 121 | 122 | function checkRegistered() 123 | public 124 | duringRegistrationPeriod() 125 | notCanceled() 126 | constant 127 | returns (bool success) 128 | { 129 | var c = getCandidate(msg.sender); 130 | success = c.registrant == msg.sender; 131 | } 132 | 133 | function invitationByOwner(address[] registrants) 134 | public 135 | onlyOrganizer() 136 | notCanceled() 137 | returns (bool success) 138 | { 139 | for (uint i = 0; i < registrants.length ; i++ ) { 140 | var registrant = registrants[i]; 141 | var c = getCandidate(registrant); 142 | require(c.registrant == registrant); 143 | invitations.push(registrant); 144 | } 145 | success = true; 146 | } 147 | 148 | function revealApproved() 149 | public 150 | onlyOrganizer() 151 | afterRegistrationEnd() 152 | notCanceled() 153 | returns (bool success) 154 | { 155 | uint amount; 156 | uint approvedCount = 0; 157 | uint i; 158 | 159 | var registrants = new address[](capacity); 160 | 161 | /* Approve prioritized registrants by an owner.*/ 162 | for(i = 0; i < invitations.length && approvedCount <= capacity ; i++) { 163 | var c = getCandidate(invitations[i]); 164 | if (c.registrant != 0x0 && approved[c.registrant].registrant == 0x0) { 165 | approved[c.registrant] = c; 166 | amount += c.fee; 167 | registrants[approvedCount] = c.registrant; 168 | approvedCount++; 169 | } 170 | } 171 | /* Sort left candidates by each fee.*/ 172 | Candidate[] memory tmp = sortedCandidates(); 173 | 174 | /* Fetch approve candidates until capacity < approved.length*/ 175 | for(i = 0; i < tmp.length ; i++) { 176 | var _c = tmp[i]; 177 | 178 | /* Add candidates to refunds if this event is full.*/ 179 | if (_c.registrant != 0x0 && approvedCount == capacity) { 180 | refunds[_c.registrant] += _c.fee; 181 | } 182 | 183 | if (_c.registrant != 0x0 && approved[_c.registrant].registrant == 0x0 && approvedCount < capacity) { 184 | approved[_c.registrant] = _c; 185 | amount += _c.fee; 186 | registrants[approvedCount] = _c.registrant; 187 | approvedCount++; 188 | } 189 | } 190 | 191 | /* Send registrants fee to organizer.*/ 192 | uint ownerFee = amount * OWNER_FEE / FEE_PRECISION; 193 | organizer.transfer(amount - ownerFee); 194 | owner.transfer(ownerFee); 195 | 196 | RegistrantApproved(registrants); 197 | success = true; 198 | } 199 | 200 | function cancelEvent() 201 | public 202 | onlyAdministrator() 203 | notCanceled() 204 | beforeRegistrationEnd() 205 | { 206 | canceled = true; 207 | Canceled(address(this), name); 208 | for(uint i = 0; i < candidates.length ; i++){ 209 | var c = candidates[i]; 210 | if (c.registrant != 0x0) { 211 | refunds[c.registrant] = c.fee; 212 | } 213 | } 214 | } 215 | 216 | function registrationApproved() 217 | public 218 | afterRegistrationEnd() 219 | notCanceled() 220 | constant returns (bool success) 221 | { 222 | var c = approved[msg.sender]; 223 | success = c.registrant == msg.sender; 224 | } 225 | 226 | function checkRefund() 227 | public 228 | constant returns (uint) 229 | { 230 | return refunds[msg.sender]; 231 | } 232 | 233 | function withdrawalRefund() 234 | public 235 | returns (bool success) 236 | { 237 | require(now > registrationEnded || canceled); 238 | uint refund = refunds[msg.sender]; 239 | if (refund > 0) { 240 | refunds[msg.sender] = 0; 241 | msg.sender.transfer(refund); 242 | success = true; 243 | } else { 244 | success = false; 245 | } 246 | } 247 | 248 | function requestRegistrationTransfer() 249 | public 250 | notCanceled() 251 | afterRegistrationEnd() 252 | { 253 | var c = approved[msg.sender]; 254 | require(c.registrant == msg.sender); 255 | 256 | var _c = Candidate(msg.sender, c.name, c.fee); 257 | delegations[msg.sender] = _c; 258 | delete approved[msg.sender]; 259 | RequestedDelegation(_c.registrant, _c.name, _c.fee); 260 | } 261 | 262 | function cancelRegistrationTransfer() 263 | public 264 | notCanceled() 265 | afterRegistrationEnd() 266 | { 267 | var c = delegations[msg.sender]; 268 | require(c.registrant == msg.sender); 269 | 270 | var _c = Candidate(msg.sender, c.name, c.fee); 271 | approved[msg.sender] = _c; 272 | delete delegations[msg.sender]; 273 | CancelDelegation(_c.registrant, _c.name, _c.fee); 274 | } 275 | 276 | function checkRegistrationTransferring() 277 | public 278 | notCanceled() 279 | afterRegistrationEnd() 280 | constant 281 | returns (bool success) 282 | { 283 | var c = delegations[msg.sender]; 284 | success = c.registrant == msg.sender; 285 | } 286 | 287 | function acquireRegistrationTransfer(address _from, string _name) 288 | public 289 | payable 290 | notCanceled() 291 | afterRegistrationEnd() 292 | { 293 | var c = delegations[_from]; 294 | 295 | require(c.registrant == _from && (c.fee == 0 || msg.value >= c.fee)); 296 | 297 | var delegation = Candidate(msg.sender, _name, c.fee); 298 | delete delegations[_from]; 299 | approved[msg.sender] = delegation; 300 | AcquiredDelegation(msg.sender, _name, c.fee); 301 | uint ownerFee = msg.value * OWNER_FEE / FEE_PRECISION; 302 | _from.transfer(msg.value - ownerFee); 303 | owner.transfer(ownerFee); 304 | } 305 | 306 | /*****************************/ 307 | /***** PRIVATE FUNCTIONS *****/ 308 | /*****************************/ 309 | function addCandidate(address _registrant, string _name, uint _fee) private { 310 | bool added = false; 311 | for (uint i = 0; i < candidates.length ; i++) { 312 | var c = candidates[i]; 313 | if (c.registrant == _registrant) { 314 | candidates[i] = Candidate(_registrant, _name, _fee); 315 | added = true; 316 | break; 317 | } 318 | } 319 | if (!added) { 320 | candidates.push(Candidate(_registrant, _name, _fee)); 321 | } 322 | } 323 | 324 | function removeCandidate(address _registrant) 325 | private 326 | returns (bool success) 327 | { 328 | success = false; 329 | for (uint i = 0; i < candidates.length ; i++) { 330 | var c = candidates[i]; 331 | if (c.registrant == _registrant) { 332 | delete candidates[i]; 333 | success = true; 334 | } 335 | } 336 | } 337 | 338 | function getCandidate(address _registrant) 339 | private 340 | constant 341 | returns (Candidate c) 342 | { 343 | for (uint i = 0; i < candidates.length ; i++) { 344 | var _c = candidates[i]; 345 | if (_c.registrant == _registrant) { 346 | c = _c; 347 | break; 348 | } 349 | } 350 | } 351 | 352 | function sortedCandidates() 353 | private 354 | constant 355 | returns (Candidate[] sorted) 356 | { 357 | uint len = candidates.length; 358 | uint i = 0; 359 | uint j = 0; 360 | 361 | sorted = new Candidate[](len); 362 | 363 | for(i = 0; i < len; i++) { 364 | sorted[i] = candidates[i]; 365 | } 366 | 367 | for(i = 1; i < sorted.length; i++ ) { 368 | var c = sorted[i]; 369 | 370 | for(j = i; j > 0 && sorted[j-1].fee < c.fee; j-- ) { 371 | sorted[j] = sorted[j-1]; 372 | } 373 | 374 | sorted[j] = c; 375 | } 376 | } 377 | } 378 | -------------------------------------------------------------------------------- /test/eventeth.js: -------------------------------------------------------------------------------- 1 | const EV = artifacts.require("./Eventeth.sol"); 2 | const EVC = artifacts.require("./EventethController"); 3 | 4 | // specify time to increment by seconds 5 | const timeTravel = function (time) { 6 | return new Promise((resolve, reject) => { 7 | web3.currentProvider.sendAsync({ 8 | jsonrpc: "2.0", 9 | method: "evm_increaseTime", 10 | params: [time], 11 | id: new Date().getTime() 12 | }, (err, result) => { 13 | if(err){ return reject(err) } 14 | return resolve(result) 15 | }); 16 | }) 17 | } 18 | 19 | // Workaround for https://github.com/ethereumjs/testrpc/issues/336 20 | const mineBlock = function () { 21 | return new Promise((resolve, reject) => { 22 | web3.currentProvider.sendAsync({ 23 | jsonrpc: "2.0", 24 | method: "evm_mine" 25 | }, (err, result) => { 26 | if(err){ return reject(err) } 27 | return resolve(result) 28 | }); 29 | }) 30 | } 31 | 32 | contract('Eventeth', function(accounts) { 33 | const registrationPeriod = 2*24*60*60; 34 | const owner = accounts[1]; 35 | const organizer = accounts[0]; 36 | const EVENT_INIT_PARAMS = { 37 | _organizer: organizer, 38 | _name: "test", 39 | _registrationStarted: Math.floor(new Date().getTime()/1000) - registrationPeriod/2, 40 | _registrationEnded: Math.floor(new Date().getTime()/1000) + registrationPeriod/2, 41 | _minimumGuarantee: web3.toWei("0.01", "ether"), 42 | _capacity: 2, 43 | _owner: owner 44 | } 45 | 46 | const account1 = accounts[2]; 47 | const account2 = accounts[3]; 48 | const account3 = accounts[4]; 49 | 50 | let event; 51 | 52 | beforeEach(async function(){ 53 | const nowTime = web3.eth.getBlock(web3.eth.blockNumber).timestamp 54 | 55 | event = await EV.new( 56 | EVENT_INIT_PARAMS._organizer, 57 | EVENT_INIT_PARAMS._name, 58 | nowTime - registrationPeriod/2, 59 | nowTime + registrationPeriod/2, 60 | EVENT_INIT_PARAMS._minimumGuarantee, 61 | EVENT_INIT_PARAMS._capacity, 62 | EVENT_INIT_PARAMS._owner, 63 | {}); 64 | }) 65 | 66 | it("should have constructor value", async function() { 67 | assert(await event.organizer(), EVENT_INIT_PARAMS._organizer); 68 | assert(await event.name(), EVENT_INIT_PARAMS._name); 69 | assert(await event.minimumGuarantee(), EVENT_INIT_PARAMS._minimumGuarantee); 70 | assert(await event.capacity(), EVENT_INIT_PARAMS._capacity); 71 | assert(await event.owner(), EVENT_INIT_PARAMS._owner); 72 | }) 73 | 74 | it("should enable users to register event.", async function() { 75 | const origin = web3.eth.getBalance(account1).toNumber() 76 | assert.equal(await event.checkRegistered.call({from: account1}), false) 77 | await event.register("test", {from: account1, value: web3.toWei("0.01", "ether")}) 78 | assert.equal(await event.checkRegistered.call({from: account1}), true) 79 | assert.isBelow(web3.eth.getBalance(account1).toNumber(), origin - web3.toWei(0.01, "ether")) 80 | assert.equal(web3.eth.getBalance(event.address).toNumber(), web3.toWei(0.01, "ether")) 81 | 82 | await timeTravel(registrationPeriod/2 + 1) 83 | await event.revealApproved() 84 | assert.typeOf( 85 | await event.register("test", {from: account2, value: web3.toWei("0.1", "ether")}).catch(function(e){return e;}), 86 | "error", "error should thrown if an user try to register after registrationEnded.") 87 | }) 88 | 89 | it("should return old registration fee if the user registered multiple times", async function(){ 90 | await event.register("test", {from: account1, value: web3.toWei("0.01", "ether")}) 91 | const afterRegistration = web3.eth.getBalance(account1).toNumber() 92 | 93 | await event.register("test", {from: account1, value: web3.toWei("0.1", "ether")}) 94 | 95 | assert.equal(await event.checkRegistered.call({from: account1}), true) 96 | assert.isAbove(web3.eth.getBalance(account1).toNumber(), afterRegistration - web3.toWei(0.1, "ether")) 97 | assert.isBelow(web3.eth.getBalance(account1).toNumber(), afterRegistration + web3.toWei(0.01, "ether")) 98 | assert.equal(web3.eth.getBalance(event.address).toNumber(), web3.toWei(0.1, "ether")) 99 | }) 100 | 101 | it("should enable users to de-register event.", async function() { 102 | await event.register("test", {from: account1, value: web3.toWei("0.01", "ether")}) 103 | assert.equal(await event.checkRegistered.call({from: account1}), true) 104 | 105 | const origin = web3.eth.getBalance(account1).toNumber() 106 | await event.deregister({from: account1}) 107 | assert.equal(await event.checkRegistered.call({from: account1}), false) 108 | assert.isAbove(web3.eth.getBalance(account1).toNumber(), origin) 109 | assert.isBelow(web3.eth.getBalance(account1).toNumber(), origin + 1.0 * web3.toWei("0.01", "ether")) 110 | }); 111 | 112 | it("should return refund value.", async function(){ 113 | assert.equal(await event.checkRefund().then(function(i){ return i.toNumber()}), 0) 114 | await event.register("test1", {from: account1, value: web3.toWei("0.01", "ether")}) 115 | await event.register("test2", {from: account2, value: web3.toWei("0.02", "ether")}) 116 | await event.register("test3", {from: account3, value: web3.toWei("0.03", "ether")}) 117 | 118 | await timeTravel(registrationPeriod/2 + 1) 119 | await event.revealApproved() 120 | 121 | assert.equal((await event.checkRefund({from: account1})).toNumber(), web3.toWei(0.01, "ether")) 122 | assert.equal((await event.checkRefund({from: account2})).toNumber(), 0) 123 | assert.equal((await event.checkRefund({from: account3})).toNumber(), 0) 124 | 125 | const origin = web3.eth.getBalance(account1).toNumber() 126 | await event.withdrawalRefund({from: account1}) 127 | assert.equal((await event.checkRefund({from: account1})).toNumber(), 0) 128 | assert.isAbove(web3.eth.getBalance(account1).toNumber(), origin) 129 | assert.isBelow(web3.eth.getBalance(account1).toNumber(), origin + web3.toWei(0.01, "ether")) 130 | }) 131 | 132 | it("should approve registrant.", async function(){ 133 | await event.register("test1", {from: account1, value: web3.toWei("0.01", "ether")}) 134 | await event.register("test2", {from: account2, value: web3.toWei("0.02", "ether")}) 135 | await event.register("test3", {from: account3, value: web3.toWei("0.03", "ether")}) 136 | 137 | assert.typeOf( 138 | await event.revealApproved().catch(function(e){return e;}), 139 | "error", "error should thrown if called before the registrationEnded.") 140 | 141 | const origin = web3.eth.getBalance(organizer).toNumber() 142 | const originOwner = web3.eth.getBalance(owner).toNumber() 143 | 144 | await timeTravel(registrationPeriod/2 + 1) 145 | await event.revealApproved() 146 | 147 | assert.equal(await event.registrationApproved.call({from: account1}), false) 148 | assert.equal(await event.registrationApproved.call({from: account2}), true) 149 | assert.equal(await event.registrationApproved.call({from: account3}), true) 150 | 151 | assert.isAbove(web3.eth.getBalance(organizer).toNumber(), origin) 152 | assert.isAtMost(web3.eth.getBalance(organizer).toNumber(), origin + 1.0 * web3.toWei(0.05 * 0.99, "ether")) 153 | assert.equal(web3.eth.getBalance(owner).toNumber(), originOwner + 1.0 * web3.toWei(0.05 * 0.01, "ether")) 154 | }) 155 | 156 | it("should approve invited users registration by owner", async function() { 157 | await event.register("test1", {from: account1, value: web3.toWei("0.01", "ether")}) 158 | await event.register("test2", {from: account2, value: web3.toWei("0.02", "ether")}) 159 | await event.register("test3", {from: account3, value: web3.toWei("0.03", "ether")}) 160 | await event.invitationByOwner([account1]) 161 | 162 | await timeTravel(registrationPeriod/2 + 1) 163 | await event.revealApproved() 164 | 165 | assert.equal(await event.registrationApproved.call({from: account1}), true) 166 | assert.equal(await event.registrationApproved.call({from: account2}), false) 167 | assert.equal(await event.registrationApproved.call({from: account3}), true) 168 | }); 169 | 170 | it("should delegate approved registration.", async function(){ 171 | // registration and approval 172 | await event.register("test1", {from: account1, value: web3.toWei("0.01", "ether")}) 173 | await event.register("test2", {from: account2, value: web3.toWei("0.02", "ether")}) 174 | await timeTravel(registrationPeriod/2 + 1) 175 | await event.revealApproved() 176 | assert.equal(await event.registrationApproved.call({from: account1}), true) 177 | 178 | await event.requestRegistrationTransfer({from: account1}) 179 | assert.isFalse(await event.registrationApproved.call({from: account1})) 180 | assert.isFalse(await event.registrationApproved.call({from: account3})) 181 | assert.isTrue(await event.checkRegistrationTransferring.call({from: account1})) 182 | 183 | const origin = web3.eth.getBalance(account1).toNumber() 184 | const originOwner = web3.eth.getBalance(owner).toNumber() 185 | await event.acquireRegistrationTransfer(account1, "test1", {from: account3, value: web3.toWei("0.01", "ether")}) 186 | assert.isFalse(await event.registrationApproved.call({from: account1})) 187 | assert.isTrue(await event.registrationApproved.call({from: account3})) 188 | assert.isFalse(await event.checkRegistrationTransferring.call({from: account1})) 189 | 190 | assert.isAbove(web3.eth.getBalance(account1).toNumber(), origin) 191 | assert.isAtMost(web3.eth.getBalance(account1).toNumber(), origin + 1.0 * web3.toWei(0.01 * 0.99, "ether")) 192 | assert.equal(web3.eth.getBalance(owner).toNumber(), originOwner + 1.0 * web3.toWei(0.01 * 0.01, "ether")) 193 | 194 | assert.typeOf( 195 | await event.requestRegistrationTransfer({from: account1}).catch(function(e){return e;}), 196 | "error", "error should thrown") 197 | assert.typeOf(await event.acquireRegistrationTransfer( 198 | account1, "test1", {from: account3, value: web3.toWei("0.01", "ether")} 199 | ).catch(function(e){return e;}), 200 | "error", "error should thrown.") 201 | }) 202 | 203 | it("should cancel registration delegation.", async function(){ 204 | // registration and approval 205 | await event.register("test1", {from: account1, value: web3.toWei("0.01", "ether")}) 206 | await event.register("test2", {from: account2, value: web3.toWei("0.02", "ether")}) 207 | await timeTravel(registrationPeriod/2 + 1) 208 | await event.revealApproved() 209 | assert.equal(await event.registrationApproved.call({from: account1}), true) 210 | 211 | await event.requestRegistrationTransfer({from: account1}) 212 | assert.isFalse(await event.registrationApproved.call({from: account1})) 213 | assert.isTrue(await event.checkRegistrationTransferring.call({from: account1})) 214 | 215 | await event.cancelRegistrationTransfer({from: account1}) 216 | assert.isFalse(await event.checkRegistrationTransferring.call({from: account1})) 217 | assert.isTrue(await event.registrationApproved.call({from: account1})) 218 | 219 | assert.typeOf( 220 | await event.cancelRegistrationTransfer({from: account1}).catch(function(e){return e;}), 221 | "error", "error should thrown if cancel twice or more.") 222 | }) 223 | 224 | it("should cancel event by organizer and stop any action except withdrawal.", async function(){ 225 | await event.register("test1", {from: account1, value: web3.toWei("0.01", "ether")}) 226 | await event.cancelEvent({from: organizer}) 227 | assert.isTrue(await event.canceled()) 228 | 229 | assert.typeOf( 230 | await event.register("test2", {from: account2, value: web3.toWei("0.02", "ether")}).catch(function(e){return e;}), 231 | "error", "error should thrown if cancel twice or more.") 232 | 233 | const origin = web3.eth.getBalance(account1).toNumber() 234 | assert.equal((await event.checkRefund({from: account1})).toNumber(), web3.toWei(0.01, "ether")) 235 | await event.withdrawalRefund({from: account1}) 236 | assert.equal((await event.checkRefund({from: account1})).toNumber(), 0) 237 | assert.isAbove(web3.eth.getBalance(account1).toNumber(), origin) 238 | assert.isAtMost(web3.eth.getBalance(account1).toNumber(), origin + 1.0 * web3.toWei(0.01, "ether")) 239 | }) 240 | }) 241 | --------------------------------------------------------------------------------