@@ -340,14 +340,21 @@ contract("Colony Expenditure", (accounts) => {
340340 "colony-expenditure-not-owner"
341341 ) ;
342342
343- await colony . setExpenditurePayoutModifiers ( expenditureId , [ SLOT1 , SLOT2 ] , [ WAD . divn ( 2 ) , WAD ] , { from : ADMIN } ) ;
343+ await colony . setExpenditurePayoutModifiers ( expenditureId , [ SLOT1 , SLOT2 ] , [ WAD . divn ( - 2 ) , WAD . muln ( - 1 ) ] , { from : ADMIN } ) ;
344344
345345 expenditureSlot = await colony . getExpenditureSlot ( expenditureId , SLOT0 ) ;
346346 expect ( expenditureSlot . payoutModifier ) . to . be . zero ;
347347 expenditureSlot = await colony . getExpenditureSlot ( expenditureId , SLOT1 ) ;
348- expect ( expenditureSlot . payoutModifier ) . to . eq . BN ( WAD . divn ( 2 ) ) ;
348+ expect ( expenditureSlot . payoutModifier ) . to . eq . BN ( WAD . divn ( - 2 ) ) ;
349349 expenditureSlot = await colony . getExpenditureSlot ( expenditureId , SLOT2 ) ;
350- expect ( expenditureSlot . payoutModifier ) . to . eq . BN ( WAD ) ;
350+ expect ( expenditureSlot . payoutModifier ) . to . eq . BN ( WAD . muln ( - 1 ) ) ;
351+ } ) ;
352+
353+ it ( "should not allow owners to update many slot payout modifiers at once if one is >0" , async ( ) => {
354+ await checkErrorRevert (
355+ colony . setExpenditurePayoutModifiers ( expenditureId , [ SLOT1 , SLOT2 ] , [ 0 , 1 ] , { from : ADMIN } ) ,
356+ "colony-expenditure-bad-payout-modifier"
357+ ) ;
351358 } ) ;
352359
353360 it ( "should not allow owners to update many slot payout modifiers with mismatched arguments" , async ( ) => {
@@ -463,7 +470,7 @@ contract("Colony Expenditure", (accounts) => {
463470 [ SLOT0 , SLOT1 ] ,
464471 [ 10 , 20 ] ,
465472 [ SLOT0 , SLOT2 ] ,
466- [ WAD . divn ( 3 ) , WAD . divn ( 2 ) ] ,
473+ [ WAD . divn ( - 3 ) , WAD . divn ( - 2 ) ] ,
467474 [ token . address , otherToken . address ] ,
468475 [
469476 [ SLOT0 , SLOT1 ] ,
@@ -481,7 +488,7 @@ contract("Colony Expenditure", (accounts) => {
481488 expect ( slot . recipient ) . to . equal ( RECIPIENT ) ;
482489 expect ( slot . skills [ 0 ] ) . to . be . zero ;
483490 expect ( slot . claimDelay ) . to . eq . BN ( 10 ) ;
484- expect ( slot . payoutModifier ) . to . eq . BN ( WAD . divn ( 3 ) ) ;
491+ expect ( slot . payoutModifier ) . to . eq . BN ( WAD . divn ( - 3 ) ) ;
485492
486493 slot = await colony . getExpenditureSlot ( expenditureId , SLOT1 ) ;
487494 expect ( slot . recipient ) . to . equal ( USER ) ;
@@ -493,7 +500,7 @@ contract("Colony Expenditure", (accounts) => {
493500 expect ( slot . recipient ) . to . equal ( ADMIN ) ;
494501 expect ( slot . skills [ 0 ] ) . to . eq . BN ( GLOBAL_SKILL_ID ) ;
495502 expect ( slot . claimDelay ) . to . be . zero ;
496- expect ( slot . payoutModifier ) . to . eq . BN ( WAD . divn ( 2 ) ) ;
503+ expect ( slot . payoutModifier ) . to . eq . BN ( WAD . divn ( - 2 ) ) ;
497504
498505 let payout ;
499506 payout = await colony . getExpenditureSlotPayout ( expenditureId , SLOT0 , token . address ) ;
@@ -522,7 +529,7 @@ contract("Colony Expenditure", (accounts) => {
522529 [ SLOT0 , SLOT1 ] ,
523530 [ 10 , 20 ] ,
524531 [ SLOT0 , SLOT2 ] ,
525- [ WAD . divn ( 3 ) , WAD . divn ( 2 ) ] ,
532+ [ WAD . divn ( - 3 ) , WAD . divn ( - 2 ) ] ,
526533 [ token . address , otherToken . address ] ,
527534 [ [ SLOT0 ] , [ SLOT1 , SLOT2 ] ] ,
528535 [
@@ -561,7 +568,7 @@ contract("Colony Expenditure", (accounts) => {
561568 [ SLOT0 , SLOT1 ] ,
562569 [ 10 , 20 ] ,
563570 [ SLOT0 , SLOT2 ] ,
564- [ WAD . divn ( 3 ) , WAD . divn ( 2 ) ] ,
571+ [ WAD . divn ( - 3 ) , WAD . divn ( - 2 ) ] ,
565572 [ token . address , otherToken . address ] ,
566573 [
567574 [ SLOT0 , SLOT1 ] ,
@@ -582,7 +589,7 @@ contract("Colony Expenditure", (accounts) => {
582589 expect ( slot . recipient ) . to . equal ( RECIPIENT ) ;
583590 expect ( slot . skills [ 0 ] ) . to . be . zero ;
584591 expect ( slot . claimDelay ) . to . eq . BN ( 10 ) ;
585- expect ( slot . payoutModifier ) . to . eq . BN ( WAD . divn ( 3 ) ) ;
592+ expect ( slot . payoutModifier ) . to . eq . BN ( WAD . divn ( - 3 ) ) ;
586593
587594 slot = await colony . getExpenditureSlot ( expenditureId , SLOT1 ) ;
588595 expect ( slot . recipient ) . to . equal ( USER ) ;
@@ -594,7 +601,7 @@ contract("Colony Expenditure", (accounts) => {
594601 expect ( slot . recipient ) . to . equal ( ADMIN ) ;
595602 expect ( slot . skills [ 0 ] ) . to . eq . BN ( GLOBAL_SKILL_ID ) ;
596603 expect ( slot . claimDelay ) . to . be . zero ;
597- expect ( slot . payoutModifier ) . to . eq . BN ( WAD . divn ( 2 ) ) ;
604+ expect ( slot . payoutModifier ) . to . eq . BN ( WAD . divn ( - 2 ) ) ;
598605
599606 let payout ;
600607 payout = await colony . getExpenditureSlotPayout ( expenditureId , SLOT0 , token . address ) ;
@@ -1274,12 +1281,48 @@ contract("Colony Expenditure", (accounts) => {
12741281 it ( "should allow arbitration users to update expenditure slot payoutModifier" , async ( ) => {
12751282 const mask = [ MAPPING , ARRAY ] ;
12761283 const keys = [ "0x0" , bn2bytes32 ( new BN ( 2 ) ) ] ;
1277- const value = bn2bytes32 ( new BN ( 100 ) ) ;
1284+ const value = bn2bytes32 ( new BN ( 100 ) . muln ( - 1 ) ) ;
12781285
12791286 await colony . setExpenditureState ( 1 , UINT256_MAX , expenditureId , EXPENDITURESLOTS_SLOT , mask , keys , value , { from : ARBITRATOR } ) ;
12801287
12811288 const expenditureSlot = await colony . getExpenditureSlot ( expenditureId , 0 ) ;
1282- expect ( expenditureSlot . payoutModifier ) . to . eq . BN ( 100 ) ;
1289+ expect ( expenditureSlot . payoutModifier ) . to . eq . BN ( new BN ( 100 ) . muln ( - 1 ) ) ;
1290+ } ) ;
1291+
1292+ it ( "should allow not allow arbitration users to update expenditure slot payoutModifier to a value greater than 1" , async ( ) => {
1293+ const mask = [ MAPPING , ARRAY ] ;
1294+ const keys = [ "0x0" , bn2bytes32 ( new BN ( 2 ) ) ] ;
1295+ const value = bn2bytes32 ( WAD . muln ( 2 ) ) ;
1296+
1297+ await checkErrorRevert (
1298+ colony . setExpenditureState ( 1 , UINT256_MAX , expenditureId , EXPENDITURESLOTS_SLOT , mask , keys , value , { from : ARBITRATOR } ) ,
1299+ "colony-expenditure-bad-payout-modifier"
1300+ ) ;
1301+
1302+ const expenditureSlot = await colony . getExpenditureSlot ( expenditureId , 0 ) ;
1303+ expect ( expenditureSlot . payoutModifier ) . to . eq . BN ( 0 ) ;
1304+ } ) ;
1305+
1306+ it ( "should allow root users to update expenditure slot payoutModifier to a value greater than 1" , async ( ) => {
1307+ const mask = [ MAPPING , ARRAY ] ;
1308+ const keys = [ "0x0" , bn2bytes32 ( new BN ( 2 ) ) ] ;
1309+ const value = bn2bytes32 ( WAD . muln ( 2 ) ) ;
1310+
1311+ await colony . setExpenditureState ( 1 , UINT256_MAX , expenditureId , EXPENDITURESLOTS_SLOT , mask , keys , value , { from : ROOT } ) ;
1312+
1313+ const expenditureSlot = await colony . getExpenditureSlot ( expenditureId , 0 ) ;
1314+ expect ( expenditureSlot . payoutModifier ) . to . eq . BN ( WAD . muln ( 2 ) ) ;
1315+ } ) ;
1316+
1317+ it ( "not even root users should be allowed to update expenditure slot payoutModifier to a value less than -1" , async ( ) => {
1318+ const mask = [ MAPPING , ARRAY ] ;
1319+ const keys = [ "0x0" , bn2bytes32 ( new BN ( 2 ) ) ] ;
1320+ const value = bn2bytes32 ( WAD . muln ( - 2 ) ) ;
1321+
1322+ await checkErrorRevert (
1323+ colony . setExpenditureState ( 1 , UINT256_MAX , expenditureId , EXPENDITURESLOTS_SLOT , mask , keys , value , { from : ROOT } ) ,
1324+ "colony-expenditure-bad-payout-modifier"
1325+ ) ;
12831326 } ) ;
12841327
12851328 it ( "should not allow arbitration users to pass an invalid payoutModifier" , async ( ) => {
@@ -1451,7 +1494,7 @@ contract("Colony Expenditure", (accounts) => {
14511494 const mask = [ MAPPING , ARRAY ] ;
14521495 const keys = [ "0x0" , bn2bytes32 ( new BN ( 2 ) ) ] ;
14531496 const value = bn2bytes32 ( WAD ) ;
1454- await colony . setExpenditureState ( 1 , UINT256_MAX , expenditureId , EXPENDITURESLOTS_SLOT , mask , keys , value , { from : ARBITRATOR } ) ;
1497+ await colony . setExpenditureState ( 1 , UINT256_MAX , expenditureId , EXPENDITURESLOTS_SLOT , mask , keys , value , { from : ROOT } ) ;
14551498
14561499 const expenditure = await colony . getExpenditure ( expenditureId ) ;
14571500 await colony . moveFundsBetweenPots ( 1 , UINT256_MAX , UINT256_MAX , domain1 . fundingPotId , expenditure . fundingPotId , WAD , token . address ) ;
@@ -1473,14 +1516,44 @@ contract("Colony Expenditure", (accounts) => {
14731516 expect ( entry . amount ) . to . eq . BN ( WAD . muln ( 2 ) ) ;
14741517 } ) ;
14751518
1519+ it ( "should scale up payout by payoutScalar for large payouts" , async ( ) => {
1520+ await colony . setExpenditureRecipient ( expenditureId , SLOT0 , RECIPIENT , { from : ADMIN } ) ;
1521+ await colony . setExpenditurePayout ( expenditureId , SLOT0 , token . address , WAD , { from : ADMIN } ) ;
1522+
1523+ // Modifier of 1 WAD translates to scalar of 2 WAD
1524+ const mask = [ MAPPING , ARRAY ] ;
1525+ const keys = [ "0x0" , bn2bytes32 ( new BN ( 2 ) ) ] ;
1526+ const value = bn2bytes32 ( WAD . muln ( 100 ) ) ;
1527+ await colony . setExpenditureState ( 1 , UINT256_MAX , expenditureId , EXPENDITURESLOTS_SLOT , mask , keys , value , { from : ROOT } ) ;
1528+
1529+ const expenditure = await colony . getExpenditure ( expenditureId ) ;
1530+ await colony . moveFundsBetweenPots ( 1 , UINT256_MAX , UINT256_MAX , domain1 . fundingPotId , expenditure . fundingPotId , WAD , token . address ) ;
1531+ await colony . finalizeExpenditure ( expenditureId , { from : ADMIN } ) ;
1532+
1533+ const recipientBalanceBefore = await token . balanceOf ( RECIPIENT ) ;
1534+ await colony . claimExpenditurePayout ( expenditureId , SLOT0 , token . address ) ;
1535+
1536+ // Cash payout maxes out at payout
1537+ const recipientBalanceAfter = await token . balanceOf ( RECIPIENT ) ;
1538+ expect ( recipientBalanceAfter . sub ( recipientBalanceBefore ) ) . to . eq . BN ( WAD . divn ( 100 ) . muln ( 99 ) . subn ( 1 ) ) ; // eslint-disable-line prettier/prettier
1539+
1540+ // But reputation gets a boost
1541+ const addr = await colonyNetwork . getReputationMiningCycle ( false ) ;
1542+ const repCycle = await IReputationMiningCycle . at ( addr ) ;
1543+ const numEntries = await repCycle . getReputationUpdateLogLength ( ) ;
1544+ const entry = await repCycle . getReputationUpdateLogEntry ( numEntries . subn ( 1 ) ) ;
1545+ expect ( entry . user ) . to . equal ( RECIPIENT ) ;
1546+ expect ( entry . amount ) . to . eq . BN ( WAD . muln ( 101 ) ) ;
1547+ } ) ;
1548+
14761549 it ( "should not overflow when using the maximum payout * modifier" , async ( ) => {
14771550 await colony . setExpenditureRecipient ( expenditureId , SLOT0 , RECIPIENT , { from : ADMIN } ) ;
14781551 await colony . setExpenditurePayout ( expenditureId , SLOT0 , token . address , MAX_PAYOUT , { from : ADMIN } ) ;
14791552
14801553 const mask = [ MAPPING , ARRAY ] ;
14811554 const keys = [ "0x0" , bn2bytes32 ( new BN ( 2 ) ) ] ;
1482- const value = bn2bytes32 ( WAD ) ;
1483- await colony . setExpenditureState ( 1 , UINT256_MAX , expenditureId , EXPENDITURESLOTS_SLOT , mask , keys , value , { from : ARBITRATOR } ) ;
1555+ const value = bn2bytes32 ( UINT256_MAX ) ;
1556+ await colony . setExpenditureState ( 1 , UINT256_MAX , expenditureId , EXPENDITURESLOTS_SLOT , mask , keys , value , { from : ROOT } ) ;
14841557
14851558 const expenditure = await colony . getExpenditure ( expenditureId ) ;
14861559 await colony . moveFundsBetweenPots ( 1 , UINT256_MAX , UINT256_MAX , domain1 . fundingPotId , expenditure . fundingPotId , MAX_PAYOUT , token . address ) ;
0 commit comments