Skip to content

Commit

Permalink
cancelExpenditureViaArbitration
Browse files Browse the repository at this point in the history
  • Loading branch information
area committed Mar 7, 2024
1 parent 7cd5441 commit fdf225e
Show file tree
Hide file tree
Showing 12 changed files with 104 additions and 54 deletions.
49 changes: 2 additions & 47 deletions contracts/colony/Colony.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ contract Colony is BasicMetaTransaction, Multicall, ColonyStorage, PatriciaTreeP
// This function, exactly as defined, is used in build scripts. Take care when updating.
// Version number should be upped with every change in Colony or its dependency contracts or libraries.
// prettier-ignore
function version() public pure returns (uint256 colonyVersion) { return 14; }
function version() public pure returns (uint256 colonyVersion) { return 15; }

function getColonyNetwork() public view returns (address) {
return colonyNetworkAddress;
Expand Down Expand Up @@ -303,57 +303,12 @@ contract Colony is BasicMetaTransaction, Multicall, ColonyStorage, PatriciaTreeP
emit ColonyUpgraded(msgSender(), currentVersion, _newVersion);
}

// v11 to v12
function finishUpgrade() public always {
ColonyAuthority colonyAuthority = ColonyAuthority(address(authority));
bytes4 sig;

sig = bytes4(keccak256("makeArbitraryTransactions(address[],bytes[],bool)"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Root), address(this), sig, true);

sig = bytes4(keccak256("setDefaultGlobalClaimDelay(uint256)"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Root), address(this), sig, true);

sig = bytes4(keccak256("setExpenditureMetadata(uint256,uint256,uint256,string)"));
sig = bytes4(keccak256("cancelExpenditureViaArbitration(uint256,uint256,uint256)"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Arbitration), address(this), sig, true);

// Remove Task & Payment functions
sig = bytes4(keccak256("makeTask(uint256,uint256,bytes32,uint256,uint256,uint256)"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Administration), address(this), sig, false);
sig = bytes4(keccak256("addPayment(uint256,uint256,address,address,uint256,uint256,uint256)"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Administration), address(this), sig, false);
sig = bytes4(keccak256("setPaymentRecipient(uint256,uint256,uint256,address)"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Administration), address(this), sig, false);
sig = bytes4(keccak256("setPaymentSkill(uint256,uint256,uint256,uint256)"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Administration), address(this), sig, false);
sig = bytes4(keccak256("setPaymentPayout(uint256,uint256,uint256,address,uint256)"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Administration), address(this), sig, false);
sig = bytes4(keccak256("finalizePayment(uint256,uint256,uint256)"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Administration), address(this), sig, false);

// Remove Global Skills functions
sig = bytes4(keccak256("addGlobalSkill()"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Root), address(this), sig, false);
sig = bytes4(keccak256("deprecateGlobalSkill(uint256)"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Root), address(this), sig, false);

// If OneTxPayment extension is installed, add the new role and upgrade it
bytes32 ONE_TX_PAYMENT = keccak256("OneTxPayment");
IColonyNetwork network = IColonyNetwork(colonyNetworkAddress);
address oneTxPaymentAddress = network.getExtensionInstallation(ONE_TX_PAYMENT, address(this));

if (oneTxPaymentAddress != address(0x0)) {
uint256 installedVersion = ColonyExtension(oneTxPaymentAddress).version();
require(installedVersion >= 5, "colony-upgrade-one-tx-payment-to-6");
if (installedVersion == 5) {
// If installed in root, add arbitration permission
if (colonyAuthority.hasUserRole(oneTxPaymentAddress, 1, uint8(ColonyRole.Administration))) {
colonyAuthority.setUserRole(oneTxPaymentAddress, 1, uint8(ColonyRole.Arbitration), true);
}
// Upgrade extension
network.upgradeExtension(ONE_TX_PAYMENT, 6);
}
}
}

function getMetatransactionNonce(address _user) public view override returns (uint256 nonce) {
Expand Down
2 changes: 2 additions & 0 deletions contracts/colony/ColonyAuthority.sol
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ contract ColonyAuthority is CommonAuthority {

// Added in colony v10 (ginger-lwss)
addRoleCapability(ARBITRATION_ROLE, "setExpenditurePayout(uint256,uint256,uint256,uint256,address,uint256)");

addRoleCapability(ARBITRATION_ROLE, "cancelExpenditureViaArbitration(uint256,uint256,uint256)");
}

function addRoleCapability(uint8 role, bytes memory sig) private {
Expand Down
15 changes: 15 additions & 0 deletions contracts/colony/ColonyExpenditure.sol
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,21 @@ contract ColonyExpenditure is ColonyStorage {
emit ExpenditureTransferred(msgSender(), _id, _newOwner);
}

function cancelExpenditureViaArbitration(
uint256 _permissionDomainId,
uint256 _childSkillIndex,
uint256 _id
)
public
stoppable
expenditureDraftOrLocked(_id)
authDomain(_permissionDomainId, _childSkillIndex, expenditures[_id].domainId)
{
expenditures[_id].status = ExpenditureStatus.Cancelled;

emit ExpenditureCancelled(msgSender(), _id);
}

function cancelExpenditure(
uint256 _id
) public stoppable expenditureDraft(_id) expenditureOnlyOwner(_id) {
Expand Down
11 changes: 11 additions & 0 deletions contracts/colony/IColony.sol
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,17 @@ interface IColony is ColonyDataTypes, IRecovery, IBasicMetaTransaction, IMultica
address _newOwner
) external;

/// @notice Cancels the expenditure and prevents further editing.
/// @param _permissionDomainId The domainId in which I have the permission to take this action
/// @param _childSkillIndex The index that the `_domainId` is relative to `_permissionDomainId`,
/// (only used if `_permissionDomainId` is different to `_domainId`)
/// @param _id Expenditure identifier
function cancelExpenditureViaArbitration(
uint256 _permissionDomainId,
uint256 _childSkillIndex,
uint256 _id
) external;

/// @notice Cancels the expenditure and prevents further editing. Can only be called by expenditure owner.
/// @param _id Expenditure identifier
function cancelExpenditure(uint256 _id) external;
Expand Down
14 changes: 14 additions & 0 deletions docs/interfaces/icolony.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,20 @@ Cancels the expenditure and prevents further editing. Can only be called by expe
|_id|uint256|Expenditure identifier


### `cancelExpenditureViaArbitration(uint256 _permissionDomainId, uint256 _childSkillIndex, uint256 _id)`

Cancels the expenditure and prevents further editing.


**Parameters**

|Name|Type|Description|
|---|---|---|
|_permissionDomainId|uint256|The domainId in which I have the permission to take this action
|_childSkillIndex|uint256|The index that the `_domainId` is relative to `_permissionDomainId`, (only used if `_permissionDomainId` is different to `_domainId`)
|_id|uint256|Expenditure identifier


### `claimColonyFunds(address _token)`

Move any funds received by the colony in `_token` denomination to the top-level domain pot, siphoning off a small amount to the reward pot. If called against a colony's own token, no fee is taken.
Expand Down
2 changes: 1 addition & 1 deletion helpers/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const INT256_MIN = new BN(2).pow(new BN(255)).mul(new BN(-1));
const INT128_MAX = new BN(2).pow(new BN(127)).sub(new BN(1));
const INT128_MIN = new BN(2).pow(new BN(127)).mul(new BN(-1));

const CURR_VERSION = 14;
const CURR_VERSION = 15;

const RECOVERY_ROLE = 0;
const ROOT_ROLE = 1;
Expand Down
13 changes: 13 additions & 0 deletions scripts/deployOldUpgradeableVersion.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@ module.exports.deployColonyVersionGLWSS4 = (colonyNetwork) => {
);
};

module.exports.deployColonyVersionHMWSS = (colonyNetwork) => {
return module.exports.deployOldColonyVersion(
"Colony",
"IMetaColony",
[
// eslint-disable-next-line max-len
"Colony,ColonyDomains,ColonyExpenditure,ColonyFunding,ColonyRewards,ColonyRoles,ContractRecovery,ColonyArbitraryTransaction",
],
"hmwss",
colonyNetwork,
);
};

module.exports.deployColonyNetworkVersionGLWSS4 = () => {
return module.exports.deployOldColonyNetworkVersion(
"",
Expand Down
10 changes: 5 additions & 5 deletions test-smoke/colony-storage-consistent.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,11 @@ contract("Contract Storage", (accounts) => {
console.log("miningCycleStateHash:", miningCycleStateHash);
console.log("tokenLockingStateHash:", tokenLockingStateHash);

expect(colonyNetworkStateHash).to.equal("0x7df06499d65ae6b6164fc768c7cfc89e0c7a56d5483a21a9a95cafa8eaaee719");
expect(colonyStateHash).to.equal("0xcfcaeb63eba9378b73a4c62e5a4cb4674b4e301f73814776f16f717055a7c295");
expect(metaColonyStateHash).to.equal("0xba451b41b29bc477b8b53f057b9252c6daedeab4ee917b5ba00d46f6d2919bfc");
expect(miningCycleStateHash).to.equal("0xf453858c03397af01668d54e6031e5a5594cff94c8fdb618c44899cd24cb1856");
expect(tokenLockingStateHash).to.equal("0xb0e53da184faa87011a47b92e99d95f22afcc2feba5aa009be659242df09df63");
expect(colonyNetworkStateHash).to.equal("0x3551c05ff92b9a33b93694ceb651c5a6bf9cbdddcb49ec03fc6ad7d1f0f56c04");
expect(colonyStateHash).to.equal("0x51163e3683b36c5031e968af138a3102a57915be5e13ad165ae008b00eba6e3e");
expect(metaColonyStateHash).to.equal("0x6c1447525a40a2d3fabea2a758043a52c9d44ee4fdf1e65f956810bdcc19e0cf");
expect(miningCycleStateHash).to.equal("0x5f04f203ae1ca038a9e86f46cadb22f9a5f75d70732b4af7415ef627bfe153e9");
expect(tokenLockingStateHash).to.equal("0x06cb0760dd2c02417a7577013c119523e123aeb2bbc8343d278d2b94fd2652ce");
});
});
});
27 changes: 27 additions & 0 deletions test/contracts-network/colony-expenditure.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const {
downgradeColony,
deployColonyNetworkVersionGLWSS4,
downgradeColonyNetwork,
deployColonyVersionHMWSS,
} = require("../../scripts/deployOldUpgradeableVersion");

const { expect } = chai;
Expand Down Expand Up @@ -146,6 +147,20 @@ contract("Colony Expenditure", (accounts) => {
expect(expenditure.owner).to.equal(USER);
});

it("should allow arbitration users to cancel expenditures", async () => {
await colony.makeExpenditure(1, UINT256_MAX, 1, { from: ADMIN });
const expenditureId = await colony.getExpenditureCount();

let expenditure = await colony.getExpenditure(expenditureId);
expect(expenditure.status).to.eq.BN(DRAFT);

await checkErrorRevert(colony.cancelExpenditureViaArbitration(1, UINT256_MAX, expenditureId, { from: ADMIN }), "ds-auth-unauthorized");
await colony.cancelExpenditureViaArbitration(1, UINT256_MAX, expenditureId, { from: ARBITRATOR });

expenditure = await colony.getExpenditure(expenditureId);
expect(expenditure.status).to.eq.BN(CANCELLED);
});

it("a non-root user cannot setDefaultGlobalClaimDelay", async () => {
await checkErrorRevert(colony.setDefaultGlobalClaimDelay(0, { from: ADMIN }), "ds-auth-unauthorized");
});
Expand Down Expand Up @@ -179,6 +194,7 @@ contract("Colony Expenditure", (accounts) => {
it("should error if the expenditure does not exist", async () => {
await checkErrorRevert(colony.setExpenditureSkills(100, [SLOT0], [localSkillId]), "colony-expenditure-does-not-exist");
await checkErrorRevert(colony.transferExpenditure(100, USER), "colony-expenditure-does-not-exist");
await checkErrorRevert(colony.cancelExpenditure(100, { from: ARBITRATOR }), "colony-expenditure-does-not-exist");
await checkErrorRevert(
colony.transferExpenditureViaArbitration(0, UINT256_MAX, 100, USER, { from: ARBITRATOR }),
"colony-expenditure-does-not-exist",
Expand Down Expand Up @@ -301,6 +317,7 @@ contract("Colony Expenditure", (accounts) => {

it("should not allow owners to set a (now defunct) global skill, either deprecated or undeprecated", async () => {
const { OldInterface } = await deployColonyVersionGLWSS4(colonyNetwork);
await deployColonyVersionHMWSS(colonyNetwork);
await downgradeColony(colonyNetwork, metaColony, "glwss4");

// Make the colonyNetwork the old version
Expand All @@ -322,6 +339,7 @@ contract("Colony Expenditure", (accounts) => {
// Upgrade to current version
await colonyNetworkAsEtherRouter.setResolver(latestResolver);
await metaColony.upgrade(14);
await metaColony.upgrade(15);

await checkErrorRevert(colony.setExpenditureSkill(expenditureId, SLOT0, globalSkillId, { from: ADMIN }), "colony-not-valid-local-skill");
await checkErrorRevert(colony.setExpenditureSkill(expenditureId, SLOT0, globalSkillId2, { from: ADMIN }), "colony-not-valid-local-skill");
Expand Down Expand Up @@ -460,6 +478,15 @@ contract("Colony Expenditure", (accounts) => {
await checkErrorRevert(colony.setExpenditurePayout(expenditureId, SLOT0, token.address, WAD, { from: ADMIN }), "colony-expenditure-not-draft");
});

it("should not allow arbitration to cancel an expenditure that has been finalized", async () => {
await colony.finalizeExpenditure(expenditureId, { from: ADMIN });

await checkErrorRevert(
colony.cancelExpenditureViaArbitration(1, UINT256_MAX, expenditureId, { from: ARBITRATOR }),
"colony-expenditure-not-draft-or-locked",
);
});

it("should not allow non-owners to set a payout", async () => {
await checkErrorRevert(colony.setExpenditurePayout(expenditureId, SLOT0, token.address, WAD, { from: USER }), "colony-expenditure-not-owner");
});
Expand Down
7 changes: 6 additions & 1 deletion test/contracts-network/colony.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const {
fundColonyWithTokens,
setupColony,
} = require("../../helpers/test-data-generator");
const { deployColonyVersionGLWSS4 } = require("../../scripts/deployOldUpgradeableVersion");
const { deployColonyVersionGLWSS4, deployColonyVersionHMWSS } = require("../../scripts/deployOldUpgradeableVersion");

const { expect } = chai;
chai.use(bnChai(web3.utils.BN));
Expand Down Expand Up @@ -448,6 +448,7 @@ contract("Colony", (accounts) => {
let oldColony;
before(async () => {
({ OldInterface } = await deployColonyVersionGLWSS4(colonyNetwork));
await deployColonyVersionHMWSS(colonyNetwork);
});

beforeEach(async () => {
Expand All @@ -465,6 +466,7 @@ contract("Colony", (accounts) => {
it("should be able to query for a task", async () => {
await oldColony.makeTask(1, UINT256_MAX, SPECIFICATION_HASH, 1, localSkillId, 0, { from: USER0 });
await colony.upgrade(14);
await colony.upgrade(15);
const taskId = await colony.getTaskCount();
const task = await colony.getTask(taskId);

Expand All @@ -486,6 +488,7 @@ contract("Colony", (accounts) => {
it("should be able to query for a payment", async () => {
await oldColony.addPayment(1, UINT256_MAX, USER1, token.address, WAD, 1, localSkillId, { from: USER0 });
await colony.upgrade(14);
await colony.upgrade(15);

const paymentId = await colony.getPaymentCount();
const payment = await colony.getPayment(paymentId);
Expand All @@ -506,6 +509,7 @@ contract("Colony", (accounts) => {
// Move funds into task funding pot
await colony.moveFundsBetweenPots(1, UINT256_MAX, 1, UINT256_MAX, UINT256_MAX, 1, fundingPotId, WAD, token.address);
await colony.upgrade(14);
await colony.upgrade(15);
// Move funds back
await colony.moveFundsBetweenPots(1, UINT256_MAX, 1, UINT256_MAX, UINT256_MAX, fundingPotId, 1, WAD, token.address);
});
Expand All @@ -522,6 +526,7 @@ contract("Colony", (accounts) => {
// Move funds into task funding pot
await colony.moveFundsBetweenPots(1, UINT256_MAX, 1, UINT256_MAX, UINT256_MAX, 1, fundingPotId, WAD, token.address);
await colony.upgrade(14);
await colony.upgrade(15);
// Move funds back
await colony.moveFundsBetweenPots(1, UINT256_MAX, 1, UINT256_MAX, UINT256_MAX, fundingPotId, 1, WAD, token.address);
});
Expand Down
3 changes: 3 additions & 0 deletions test/contracts-network/meta-colony.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const {
downgradeColonyNetwork,
deployColonyVersionGLWSS4,
deployColonyNetworkVersionGLWSS4,
deployColonyVersionHMWSS,
} = require("../../scripts/deployOldUpgradeableVersion");

const IMetaColony = artifacts.require("IMetaColony");
Expand Down Expand Up @@ -421,6 +422,7 @@ contract("Meta Colony", (accounts) => {
let globalSkillId;
beforeEach(async () => {
const { OldInterface } = await deployColonyVersionGLWSS4(colonyNetwork);
await deployColonyVersionHMWSS(colonyNetwork);
await downgradeColony(colonyNetwork, metaColony, "glwss4");

// Make the colonyNetwork the old version
Expand All @@ -439,6 +441,7 @@ contract("Meta Colony", (accounts) => {
// Upgrade to current version
await colonyNetworkAsEtherRouter.setResolver(latestResolver);
await metaColony.upgrade(14);
await metaColony.upgrade(15);
});

describe("when getting a skill", () => {
Expand Down
5 changes: 5 additions & 0 deletions test/extensions/one-tx-payment.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const {
downgradeColonyNetwork,
deployColonyVersionGLWSS4,
deployColonyNetworkVersionGLWSS4,
deployColonyVersionHMWSS,
} = require("../../scripts/deployOldUpgradeableVersion");

contract("One transaction payments", (accounts) => {
Expand Down Expand Up @@ -260,6 +261,7 @@ contract("One transaction payments", (accounts) => {

it("should not allow an admin to specify a global skill (which is now removed functionality), either deprecated or undeprecated", async () => {
const { OldInterface } = await deployColonyVersionGLWSS4(colonyNetwork);
await deployColonyVersionHMWSS(colonyNetwork);
await downgradeColony(colonyNetwork, metaColony, "glwss4");

// Make the colonyNetwork the old version
Expand All @@ -281,6 +283,7 @@ contract("One transaction payments", (accounts) => {
// Upgrade to current version
await colonyNetworkAsEtherRouter.setResolver(latestResolver);
await metaColony.upgrade(14);
await metaColony.upgrade(15);

await checkErrorRevert(
oneTxPayment.makePaymentFundedFromDomain(1, UINT256_MAX, 1, UINT256_MAX, [USER1], [token.address], [10], 1, globalSkillId),
Expand Down Expand Up @@ -557,6 +560,8 @@ contract("One transaction payments", (accounts) => {
// V5 is `glwss4`,
await deployOldExtensionVersion("OneTxPayment", "OneTxPayment", ["OneTxPayment"], "glwss4", colonyNetwork);
await deployColonyNetworkVersionGLWSS4();
await deployColonyVersionGLWSS4(colonyNetwork);
await deployColonyVersionHMWSS(colonyNetwork);
});

beforeEach(async () => {
Expand Down

0 comments on commit fdf225e

Please sign in to comment.