diff --git a/contracts/PolyDistribution.sol b/contracts/PolyDistribution.sol index b510c38..ba9b7c9 100755 --- a/contracts/PolyDistribution.sol +++ b/contracts/PolyDistribution.sol @@ -41,9 +41,11 @@ contract PolyDistribution is Ownable { uint256 amountClaimed; // Total tokens claimed } mapping (address => Allocation) public allocations; - + + // List of admins mapping (address => bool) public airdropAdmins; - + + // Keeps track of whether or not a 250 POLY airdrop has been made to a particular address mapping (address => bool) public airdrops; modifier onlyOwnerOrAdmin() { @@ -100,30 +102,27 @@ contract PolyDistribution is Ownable { AVAILABLE_TOTAL_SUPPLY = AVAILABLE_TOTAL_SUPPLY.sub(_totalAllocated); LogNewAllocation(_recipient, _supply, _totalAllocated, grandTotalAllocated()); } - + /** * @dev Add an airdrop admin - * @param _admin - * @param _isAdmin */ function setAirdropAdmin(address _admin, bool _isAdmin) public onlyOwner { airdropAdmins[_admin] = _isAdmin; } - + /** * @dev perform a transfer of allocations - * @param _reciepients - * @param _allocated + * @param _recipient is a list of recipients */ function airdropTokens(address[] _recipient) public onlyOwnerOrAdmin { - require(_startTime >= now); + require(now >= startTime); uint airdropped; for(uint8 i = 0; i< _recipient.length; i++) { if (!airdrops[_recipient[i]]) { airdrops[_recipient[i]] = true; - require(POLY.transfer(_recipient[i], 250*(decimalsFactor)); - airdropped = airdropped.add(250*decimalsFactor); + require(POLY.transfer(_recipient[i], 250 * decimalFactor)); + airdropped = airdropped.add(250 * decimalFactor); } } AVAILABLE_AIRDROP_SUPPLY = AVAILABLE_AIRDROP_SUPPLY.sub(airdropped); diff --git a/package.json b/package.json index 0106777..fec818c 100755 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "scripts": { "test": "scripts/test.sh", "compile": "truffle compile", + "coverage": "./node_modules/.bin/solidity-coverage", "migrate-local": "truffle migrate --network=local --reset", "migrate-ropsten": "truffle migrate --network=ropsten --reset", "flatten": "sol-merger './contracts/*.sol' ./flat" diff --git a/scripts/csv_allocation.js b/scripts/csv_allocation.js index ddcf216..5f2f9b6 100644 --- a/scripts/csv_allocation.js +++ b/scripts/csv_allocation.js @@ -47,7 +47,7 @@ async function setAllocation() { if(prevAllocation[3].toNumber() ==0){ try{ console.log("Attempting to allocate",distribData[i][0], "to account",distribData[i][1]); - polyDistribution.setAllocation(distribData[i][1],new BigNumber(distribData[i][0] * (10 ** 18)),2,{from:accounts[0], gas:300000, gasPrice:5000000000}); + polyDistribution.setAllocation(distribData[i][1],new BigNumber(distribData[i][0] * (10 ** 18)),2,{from:accounts[0], gas:300000, gasPrice:20000000000}); //let allocation = await polyDistribution.allocations(distribData[i][1],{from:accounts[0]}); //console.log(r); //console.log("Allocated", allocation[3].toString(10), "tokens for account:",distribData[i][1]); diff --git a/scripts/distrib.csv b/scripts/distrib.csv index bd2f5a4..77ad528 100644 --- a/scripts/distrib.csv +++ b/scripts/distrib.csv @@ -113,4 +113,4 @@ 5000,0x126910b84d1d270c1cf76aa1d3d9f3ab3932c7cd 1150,0x9a9e6588AF6d1bC42572B0E3c3D2F827dabA64Ac 4200,0x6d9ECe11860fDc4Ac3815eCF4077eae9973A7f2b -987,0x6d9ECe11860fDc4Ac3815eCF4077eae9973A7f2c +987,0xbf26b856d016421ce9187d3626b21ce6786af7f8 diff --git a/test/TestPolyDistribution.js b/test/TestPolyDistribution.js index 35e3f31..cfebaf4 100755 --- a/test/TestPolyDistribution.js +++ b/test/TestPolyDistribution.js @@ -59,13 +59,25 @@ contract('PolyDistribution', function(accounts) { let account_presale = accounts[1]; let account_founder1 = accounts[2]; let account_founder2 = accounts[3]; - let account_airdrop1 = accounts[4]; - let account_airdrop2 = accounts[5]; let account_bonus1 = accounts[6]; let account_advisor1 = accounts[7]; let account_advisor2 = accounts[8]; let account_reserve = accounts[9]; + let account_admin1 = accounts[4]; + + let airdrop_massive = new Array(); + for (var i = 0; i< 50; i++){ + var acc = web3.eth.accounts.create(); + airdrop_massive[i] = acc.address; + } + + let airdrop_massive2 = new Array(); + for (var i = 0; i< 50; i++){ + var acc = web3.eth.accounts.create(); + airdrop_massive2[i] = acc.address; + } + let allocationStruct = { AllocationSupply: 0, // Type of allocation endCliff: 0, // Tokens are locked until @@ -122,10 +134,6 @@ contract('PolyDistribution', function(accounts) { oldPresaleSupply = await polyDistribution.AVAILABLE_FOUNDER_SUPPLY({from:account_owner}); allocationTypeNum = 1; break; - case "AIRDROP": - oldPresaleSupply = await polyDistribution.AVAILABLE_AIRDROP_SUPPLY({from:account_owner}); - allocationTypeNum = 2; - break; case "ADVISOR": oldPresaleSupply = await polyDistribution.AVAILABLE_ADVISOR_SUPPLY({from:account_owner}); allocationTypeNum = 3; @@ -169,9 +177,6 @@ contract('PolyDistribution', function(accounts) { case "FOUNDER": newPresaleSupply = await polyDistribution.AVAILABLE_FOUNDER_SUPPLY({from:account_owner}); break; - case "AIRDROP": - newPresaleSupply = await polyDistribution.AVAILABLE_AIRDROP_SUPPLY({from:account_owner}); - break; case "ADVISOR": newPresaleSupply = await polyDistribution.AVAILABLE_ADVISOR_SUPPLY({from:account_owner}); break; @@ -265,30 +270,6 @@ contract('PolyDistribution', function(accounts) { }); - describe("AIRDROP 1 Allocation", async function () { - - let tokensToAllocate = 50; - doAllocationTests("AIRDROP",tokensToAllocate,account_airdrop1); - - after(async() => { - oldTotalSupply = new BigNumber(oldTotalSupply.minus(tokensToAllocate)); - grantTotalAllocationSum = new BigNumber(grantTotalAllocationSum.plus(tokensToAllocate)); - }); - - }); - - describe("AIRDROP 2 Allocation", async function () { - - let tokensToAllocate = 75; - doAllocationTests("AIRDROP",tokensToAllocate,account_airdrop2); - - after(async() => { - oldTotalSupply = new BigNumber(oldTotalSupply.minus(tokensToAllocate)); - grantTotalAllocationSum = new BigNumber(grantTotalAllocationSum.plus(tokensToAllocate)); - }); - - }); - describe("ADVISOR 1 Allocation", async function () { let tokensToAllocate = 3333; @@ -485,100 +466,76 @@ contract('PolyDistribution', function(accounts) { }); - }); - - describe("Withdraw 6 months after allocations", async function () { + it("should perform the AIRDROP for 50 accounts", async function () { + await polyDistribution.airdropTokens(airdrop_massive,{from:accounts[0]}); - before(async() => { - //Time travel to startTime + 6 months; - await timeTravel((3600 * 24 * 180))// Move forward in time so the crowdsale has started - await mineBlock() // workaround for https://github.com/ethereumjs/testrpc/issues/336 }); - it("should withdraw AIRDROP tokens", async function () { - let currentBlock = await web3.eth.getBlock("latest"); - - // Check token balance for account before calling transferTokens, then check afterwards. - let tokenBalance = await polyToken.balanceOf(account_airdrop1,{from:accounts[0]}); - await polyDistribution.transferTokens(account_airdrop1,{from:accounts[0]}); - let new_tokenBalance = await polyToken.balanceOf(account_airdrop1,{from:accounts[0]}); + it("airdrop accounts should have 250 POLY each", async function () { + for (var i = 0; i< airdrop_massive.length; i++){ + let tokenBalance = await polyToken.balanceOf(airdrop_massive[i],{from:accounts[0]}); + assert.equal(tokenBalance.toString(10), "250000000000000000000"); - //PRESALE tokens are completely distributed once allocated as they have no vesting period nor cliff - let allocation = await polyDistribution.allocations(account_airdrop1,{from:account_owner}); + } + }); - logWithdrawalData("AIRDROP",currentBlock.timestamp,account_airdrop1,contractStartTime,allocation,new_tokenBalance); + it("should set another admin for airdrop", async function () { + await polyDistribution.setAirdropAdmin(account_admin1,true,{from:accounts[0]}); - let expectedTokenBalance = calculateExpectedTokens(allocation,currentBlock.timestamp,contractStartTime); - assert.equal(expectedTokenBalance.toString(10),new_tokenBalance.toString(10)); }); - }); + it("should perform the AIRDROP for 50 accounts with an admin", async function () { + await polyDistribution.airdropTokens(airdrop_massive2,{from:account_admin1}); + + }); - describe("Withdraw 9 months after allocations", async function () { + it("airdrop accounts should have 250 POLY each", async function () { + for (var i = 0; i< airdrop_massive2.length; i++){ + let tokenBalance = await polyToken.balanceOf(airdrop_massive2[i],{from:accounts[0]}); + assert.equal(tokenBalance.toString(10), "250000000000000000000"); - before(async() => { - //Time travel to startTime + 9 months; - await timeTravel((3600 * 24 * 90))// Move forward in time so the crowdsale has started - await mineBlock() // workaround for https://github.com/ethereumjs/testrpc/issues/336 + } }); - it("should fail to withdraw AIRDROP 1 tokens as they have already been fully distributed", async function () { - try { - await polyDistribution.transferTokens(account_airdrop1,{from:accounts[0]}); - } catch (error) { - let currentBlock = await web3.eth.getBlock("latest"); - let new_tokenBalance = await polyToken.balanceOf(account_airdrop1,{from:accounts[0]}); - let allocation = await polyDistribution.allocations(account_airdrop1,{from:account_owner}); - logWithdrawalData("AIRDROP",currentBlock.timestamp,account_airdrop1,contractStartTime,allocation,new_tokenBalance); + }); - logError("✅ Failed to withdraw"); - return true; - } - throw new Error("I should never see this!") + describe("Withdraw 8 months after allocations", async function () { + before(async() => { + //Time travel to startTime + 8 months; + await timeTravel((3600 * 24 * 240))// Move forward in time so the crowdsale has started + await mineBlock() // workaround for https://github.com/ethereumjs/testrpc/issues/336 }); - // it("should withdraw AIRDROP tokens", async function () { - // let currentBlock = await web3.eth.getBlock("latest"); - // - // // Check token balance for account before calling transferTokens, then check afterwards. - // let tokenBalance = await polyToken.balanceOf(account_airdrop1,{from:accounts[0]}); - // await polyDistribution.transferTokens(account_airdrop1,{from:accounts[0]}); - // let new_tokenBalance = await polyToken.balanceOf(account_airdrop1,{from:accounts[0]}); - // - // //PRESALE tokens are completely distributed once allocated as they have no vesting period nor cliff - // let allocation = await polyDistribution.allocations(account_airdrop1,{from:account_owner}); - // - // logWithdrawalData("AIRDROP",currentBlock.timestamp,account_airdrop1,contractStartTime,allocation,new_tokenBalance); - // - // }); - - it("should withdraw AIRDROP tokens", async function () { + it("should withdraw RESERVE tokens", async function () { let currentBlock = await web3.eth.getBlock("latest"); // Check token balance for account before calling transferTokens, then check afterwards. - let tokenBalance = await polyToken.balanceOf(account_airdrop2,{from:accounts[0]}); - await polyDistribution.transferTokens(account_airdrop2,{from:accounts[0]}); - let new_tokenBalance = await polyToken.balanceOf(account_airdrop2,{from:accounts[0]}); + let tokenBalance = await polyToken.balanceOf(account_reserve,{from:accounts[0]}); + await polyDistribution.transferTokens(account_reserve,{from:accounts[0]}); + let new_tokenBalance = await polyToken.balanceOf(account_reserve,{from:accounts[0]}); //PRESALE tokens are completely distributed once allocated as they have no vesting period nor cliff - let allocation = await polyDistribution.allocations(account_airdrop2,{from:account_owner}); + let allocation = await polyDistribution.allocations(account_reserve,{from:account_owner}); - logWithdrawalData("AIRDROP",currentBlock.timestamp,account_airdrop2,contractStartTime,allocation,new_tokenBalance); + logWithdrawalData("RESERVE",currentBlock.timestamp,account_reserve,contractStartTime,allocation,new_tokenBalance); let expectedTokenBalance = calculateExpectedTokens(allocation,currentBlock.timestamp,contractStartTime); assert.equal(expectedTokenBalance.toString(10),new_tokenBalance.toString(10)); }); + }); + + describe("Withdraw 15 months after allocations", async function () { before(async() => { - //Time travel to startTime + 9 months; - await timeTravel((3600 * 24 * 180))// Move forward in time so the crowdsale has started + //Time travel to startTime + 15 months; + await timeTravel((3600 * 24 * 210))// Move forward in time so the crowdsale has started await mineBlock() // workaround for https://github.com/ethereumjs/testrpc/issues/336 }); diff --git a/truffle.js b/truffle.js index fc666ac..ef9bb4d 100755 --- a/truffle.js +++ b/truffle.js @@ -16,6 +16,13 @@ module.exports = { gas: 3500000, gasPrice: 10000000000 }, + ropsten: { + host: 'localhost', + port: 8545, + network_id: '3', // Match any network id + gas: 3500000, + gasPrice: 50000000000 + }, local: { host: 'localhost', port: 8545,