UNPKG

@nodeset/contracts

Version:

Protocol for accessing NodeSet's Constellation Ethereum staking network

449 lines (331 loc) 16.7 kB
import { increaseTime, mineBlocks } from '../_utils/evm'; import { printTitle } from '../_utils/formatting'; import { shouldRevert } from '../_utils/testing'; import { RocketDAONodeTrustedSettingsMinipool, RocketDAOProtocolSettingsAuction, RocketNodeStaking } from '../_utils/artifacts'; import { auctionCreateLot, auctionPlaceBid, getLotStartBlock, getLotPriceAtBlock } from '../_helpers/auction'; import { userDeposit } from '../_helpers/deposit'; import { createMinipool, stakeMinipool } from '../_helpers/minipool'; import { submitPrices } from '../_helpers/network'; import { registerNode, setNodeTrusted, nodeStakeRPL } from '../_helpers/node'; import { setDAOProtocolBootstrapSetting } from '../dao/scenario-dao-protocol-bootstrap'; import { mintRPL } from '../_helpers/tokens'; import { createLot } from './scenario-create-lot'; import { placeBid } from './scenario-place-bid'; import { claimBid } from './scenario-claim-bid'; import { recoverUnclaimedRPL } from './scenario-recover-rpl'; import { withdrawValidatorBalance } from '../minipool/scenario-withdraw-validator-balance' import { setDAONodeTrustedBootstrapSetting } from '../dao/scenario-dao-node-trusted-bootstrap'; import { assertBN } from '../_helpers/bn'; export default function() { contract('RocketAuctionManager', async (accounts) => { // Accounts const [ owner, node, trustedNode, random1, random2, ] = accounts; // Setup let scrubPeriod = (60 * 60 * 24); // 24 hours let minipool; before(async () => { // Set settings await setDAONodeTrustedBootstrapSetting(RocketDAONodeTrustedSettingsMinipool, 'minipool.scrub.period', scrubPeriod, {from: owner}); // Register node await registerNode({from: node}); // Register trusted node await registerNode({from: trustedNode}); await setNodeTrusted(trustedNode, 'saas_1', 'node@home.com', owner); // Mint RPL to node & stake; create & stake minipool const rplAmount = '10000'.ether; await mintRPL(owner, node, rplAmount); await nodeStakeRPL(rplAmount, {from: node}); minipool = await createMinipool({from: node, value: '8'.ether}); await userDeposit({from: random1, value: '24'.ether}); await increaseTime(web3, scrubPeriod + 1); await stakeMinipool(minipool, {from: node}); // Send 8 ETH to the minipool so a slash will occur on distribute await web3.eth.sendTransaction({ from: owner, to: minipool.address, value: '8'.ether, }); }); it(printTitle('random address', 'can create a lot'), async () => { // Slash RPL assigned to minipool to fill auction contract await withdrawValidatorBalance(minipool, '0'.ether, node, true); // Create first lot await createLot({ from: random1, }); // Create second lot await createLot({ from: random1, }); }); it(printTitle('random address', 'cannot create a lot while lot creation is disabled'), async () => { // Slash RPL assigned to minipool to fill auction contract await withdrawValidatorBalance(minipool, '0'.ether, node, true); // Disable lot creation await setDAOProtocolBootstrapSetting(RocketDAOProtocolSettingsAuction, 'auction.lot.create.enabled', false, {from: owner}); // Attempt to create lot await shouldRevert(createLot({ from: random1, }), 'Created a lot while lot creation was disabled'); }); it(printTitle('random address', 'cannot create a lot with an insufficient RPL balance'), async () => { // Attempt to create lot await shouldRevert(createLot({ from: random1, }), 'Created a lot with an insufficient RPL balance'); }); it(printTitle('auction lot', 'has correct price at block'), async () => { // Set lot settings await setDAOProtocolBootstrapSetting(RocketDAOProtocolSettingsAuction, 'auction.lot.duration', 100, {from: owner}); await setDAOProtocolBootstrapSetting(RocketDAOProtocolSettingsAuction, 'auction.price.start', '1'.ether, {from: owner}); await setDAOProtocolBootstrapSetting(RocketDAOProtocolSettingsAuction, 'auction.price.reserve', '0'.ether, {from: owner}); // Set RPL price let block = await web3.eth.getBlockNumber(); await submitPrices(block, '1'.ether, {from: trustedNode}); // Create lot await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); // Get lot start block const startBlock = parseInt(await getLotStartBlock(0)); // Set expected prices at blocks const values = [ {block: startBlock + 0, expectedPrice: '1.0000'.ether}, {block: startBlock + 12, expectedPrice: '0.9856'.ether}, {block: startBlock + 25, expectedPrice: '0.9375'.ether}, {block: startBlock + 37, expectedPrice: '0.8631'.ether}, {block: startBlock + 50, expectedPrice: '0.7500'.ether}, {block: startBlock + 63, expectedPrice: '0.6031'.ether}, {block: startBlock + 75, expectedPrice: '0.4375'.ether}, {block: startBlock + 88, expectedPrice: '0.2256'.ether}, {block: startBlock + 100, expectedPrice: '0.0000'.ether}, ]; // Check fees for (let vi = 0; vi < values.length; ++vi) { let v = values[vi]; let price = await getLotPriceAtBlock(0, v.block); assertBN.equal(price, v.expectedPrice, 'Lot price does not match expected price at block'); } }); it(printTitle('random address', 'can place a bid on a lot'), async () => { // Create lots await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); await auctionCreateLot({from: random1}); // Place bid on first lot from first address await placeBid(0, { from: random1, value: '4'.ether, }); // Increase bid on first lot from first address await placeBid(0, { from: random1, value: '4'.ether, }); // Place bid on first lot from second address await placeBid(0, { from: random2, value: '4'.ether, }); // Place bid on second lot from first address await placeBid(1, { from: random1, value: '2'.ether, }); // Increase bid on second lot from first address await placeBid(1, { from: random1, value: '2'.ether, }); // Place bid on second lot from second address await placeBid(1, { from: random2, value: '2'.ether, }); }); it(printTitle('random address', 'cannot bid on a lot which doesn\'t exist'), async () => { // Create lot await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); // Attempt to place bid await shouldRevert(placeBid(1, { from: random1, value: '4'.ether, }), 'Bid on a lot which doesn\'t exist'); }); it(printTitle('random address', 'cannot bid on a lot while bidding is disabled'), async () => { // Create lot await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); // Disable bidding await setDAOProtocolBootstrapSetting(RocketDAOProtocolSettingsAuction, 'auction.lot.bidding.enabled', false, {from: owner}); // Attempt to place bid await shouldRevert(placeBid(0, { from: random1, value: '4'.ether, }), 'Bid on a lot while bidding was disabled'); }); it(printTitle('random address', 'cannot bid an invalid amount on a lot'), async () => { // Create lot await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); // Attempt to place bid await shouldRevert(placeBid(0, { from: random1, value: '0'.ether, }), 'Bid an invalid amount on a lot'); }); it(printTitle('random address', 'cannot bid on a lot after the lot bidding period has concluded'), async () => { // Set lot duration await setDAOProtocolBootstrapSetting(RocketDAOProtocolSettingsAuction, 'auction.lot.duration', 0, {from: owner}); // Create lot await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); // Attempt to place bid await shouldRevert(placeBid(0, { from: random1, value: '4'.ether, }), 'Bid on a lot after the bidding period concluded'); }); it(printTitle('random address', 'cannot bid on a lot after the RPL allocation has been exhausted'), async () => { // Create lot await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); // Place bid & claim all RPL await placeBid(0, { from: random1, value: '1000'.ether, }); // Attempt to place bid await shouldRevert(placeBid(0, { from: random2, value: '4'.ether, }), 'Bid on a lot after the RPL allocation was exhausted'); }); it(printTitle('random address', 'can claim RPL from a lot'), async () => { // Create lots & place bids to clear await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); await auctionCreateLot({from: random1}); await auctionPlaceBid(0, {from: random1, value: '5'.ether}); await auctionPlaceBid(0, {from: random2, value: '5'.ether}); await auctionPlaceBid(1, {from: random1, value: '3'.ether}); await auctionPlaceBid(1, {from: random2, value: '3'.ether}); // Claim RPL on first lot from first address await claimBid(0, { from: random1, }); // Claim RPL on first lot from second address await claimBid(0, { from: random2, }); // Claim RPL on second lot from first address await claimBid(1, { from: random1, }); // Claim RPL on second lot from second address await claimBid(1, { from: random2, }); }); it(printTitle('random address', 'cannot claim RPL from a lot which doesn\'t exist'), async () => { // Create lot & place bid to clear await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); await auctionPlaceBid(0, {from: random1, value: '1000'.ether}); // Attempt to claim RPL await shouldRevert(claimBid(1, { from: random1, }), 'Claimed RPL from a lot which doesn\'t exist'); }); it(printTitle('random address', 'cannot claim RPL from a lot before it has cleared'), async () => { // Create lot & place bid await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); await auctionPlaceBid(0, {from: random1, value: '4'.ether}); // Attempt to claim RPL await shouldRevert(claimBid(0, { from: random1, }), 'Claimed RPL from a lot before it has cleared'); }); it(printTitle('random address', 'cannot claim RPL from a lot it has not bid on'), async () => { // Create lot & place bid to clear await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); await auctionPlaceBid(0, {from: random1, value: '1000'.ether}); // Attempt to claim RPL await shouldRevert(claimBid(0, { from: random2, }), 'Address claimed RPL from a lot it has not bid on'); }); it(printTitle('random address', 'can recover unclaimed RPL from a lot'), async () => { // Create closed lots await setDAOProtocolBootstrapSetting(RocketDAOProtocolSettingsAuction, 'auction.lot.duration', 0, {from: owner}); await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); await auctionCreateLot({from: random1}); // Recover RPL from first lot await recoverUnclaimedRPL(0, { from: random1, }); // Recover RPL from second lot await recoverUnclaimedRPL(1, { from: random1, }); }); it(printTitle('random address', 'cannot recover unclaimed RPL from a lot which doesn\'t exist'), async () => { // Create closed lot await setDAOProtocolBootstrapSetting(RocketDAOProtocolSettingsAuction, 'auction.lot.duration', 0, {from: owner}); await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); // Attempt to recover RPL await shouldRevert(recoverUnclaimedRPL(1, { from: random1, }), 'Recovered unclaimed RPL from a lot which doesn\'t exist'); }); it(printTitle('random address', 'cannot recover unclaimed RPL from a lot before the lot bidding period has concluded'), async () => { // Create lot await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); // Attempt to recover RPL await shouldRevert(recoverUnclaimedRPL(0, { from: random1, }), 'Recovered unclaimed RPL from a lot before its bidding period had concluded'); }); it(printTitle('random address', 'cannot recover unclaimed RPL from a lot twice'), async () => { // Create closed lot await setDAOProtocolBootstrapSetting(RocketDAOProtocolSettingsAuction, 'auction.lot.duration', 0, {from: owner}); await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); // Recover RPL await recoverUnclaimedRPL(0, {from: random1}); // Attempt to recover RPL again await shouldRevert(recoverUnclaimedRPL(0, { from: random1, }), 'Recovered unclaimed RPL from a lot twice'); }); it(printTitle('random address', 'cannot recover unclaimed RPL from a lot which has no RPL to recover'), async () => { // Set lot duration await setDAOProtocolBootstrapSetting(RocketDAOProtocolSettingsAuction, 'auction.lot.duration', 10, {from: owner}); // Create lot & place bid to clear await withdrawValidatorBalance(minipool, '0'.ether, node, true); await auctionCreateLot({from: random1}); await auctionPlaceBid(0, {from: random1, value: '1000'.ether}); // Move to lot bidding period end await mineBlocks(web3, 10); // Attempt to recover RPL again await shouldRevert(recoverUnclaimedRPL(0, { from: random1, }), 'Recovered unclaimed RPL from a lot which had no RPL to recover'); }); }); }