Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0c7af8e
First commit, to be squashed
area Mar 24, 2023
2b00778
Bridge skills on creation to home chain
area Apr 9, 2023
2d3f74f
Add functionality to bridge reputation state
area Apr 10, 2023
3366383
Add some more bridging tests
area Apr 13, 2023
a5526e3
Low hanging fruit from first (p)review
area Apr 20, 2023
a46de20
Test reputation decay on troubled bridging
area May 2, 2023
873c788
Additional multichain tests
area May 5, 2023
e7d6772
Straighten out bridged skill trees so they match
area May 10, 2023
3654b20
First changes following second review
area Jun 9, 2023
7663814
First changes following second review
area Jun 9, 2023
d991671
Update relevant Network struct definitions
kronosapiens Jun 12, 2023
6b7645d
Add helper functions, misc refactoring
kronosapiens Jun 12, 2023
03db8ce
Introduce ColonyNetworkSkills
kronosapiens Jun 13, 2023
d60b156
Make bridging function names consistent
kronosapiens Jun 13, 2023
e609e34
Minor test edits
kronosapiens Jun 13, 2023
61adf20
Fix chainIds, revert cross-chain setup
area Jun 18, 2023
8ecacc6
Some tweaks from review, add events
area Jun 21, 2023
d5e7179
Resurrect skipped tests as appropriate
area Jun 22, 2023
941c5a9
Minor close to final tweaks
area Jun 22, 2023
d0c6243
Non-functional tweaks
area Jun 26, 2023
cba0786
Some contract tidying, extra tests for coverage
area Jun 26, 2023
1aaadf3
Slither updates
area Jun 26, 2023
6cb654f
Change how bridged transactions are tracked in tests
area Jun 30, 2023
c2f6d7c
Add guards for unsupported large chainIds
area Aug 7, 2023
3fc7822
Add missing awaits to tests
area Aug 7, 2023
f08978e
Meaningless tweaks and correctly error-out in tests
area Aug 8, 2023
2e930ca
Continue making cross-chain tests more robust
area Aug 9, 2023
59eab70
Fix flubbed rebase
area Aug 22, 2023
14065eb
Add example tests that need to pass
area Sep 1, 2023
c423927
Add and get all bridging permission tests passing
area Sep 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .solcover.chainid.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ config.providerOptions.network_id = parseInt(process.env.CHAIN_ID, 10);
config.providerOptions._chainId = parseInt(process.env.CHAIN_ID, 10);
config.providerOptions._chainIdRpc = parseInt(process.env.CHAIN_ID, 10);
config.istanbulFolder = `./coverage-chainid-${process.env.CHAIN_ID}`

module.exports = config
19 changes: 18 additions & 1 deletion .solcover.crosschain.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
const config = require("./.solcover.js")
const log = console.log;
const { execSync } = require("child_process");
const ethers = require("ethers");

const { FORKED_XDAI_CHAINID } = require("./helpers/constants");

const existingCompileComplete = config.onCompileComplete;

config.istanbulFolder = `./coverage-cross-chain-${process.env.TRUFFLE_HOME ? "home" : "foreign"}`
let chainId;
// We configure the truffle coverage chain to have the same chainid as one of the
// nodes we've started up, but on a different port
// TODO: Actually query nodes, don't hard-code here, or work out how to get environment
// variables in package.json to work here as I want.
if (JSON.parse(process.env.TRUFFLE_FOREIGN)){
chainId = FORKED_XDAI_CHAINID + 1;
} else {
chainId = FORKED_XDAI_CHAINID;
}

config.providerOptions.network_id = chainId;
config.providerOptions._chainId = chainId;
config.providerOptions._chainIdRpc = chainId;

config.istanbulFolder = `./coverage-cross-chain-${JSON.parse(process.env.TRUFFLE_FOREIGN) ? "foreign" : "home"}`

function provisionSafeContracts(){
let output;
Expand Down
9 changes: 6 additions & 3 deletions .solcover.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ const log = console.log;
// Copies pre-built token artifacts to .coverage_artifacts/contracts
function provisionTokenContracts(config){
let output;
const provisionColonyToken = `BUILD_DIR="build-coverage" bash ./scripts/provision-token-contracts.sh`;
const provisionColonyToken = `BUILD_DIR="build-coverage" npm run provision:token:contracts`;

log('Provisioning ColonyToken contracts...')
output = execSync(provisionColonyToken);
log(output.toString())

const provisionSafeContracts = `BUILD_DIR="build-coverage" bash ./scripts/provision-safe-contracts.sh`;
const provisionSafeContracts = `BUILD_DIR="build-coverage" npm run provision:safe:contracts`;

log('Provisioning Safe contracts...')
output = execSync(provisionSafeContracts);
Expand All @@ -33,6 +33,9 @@ module.exports = {
account_keys_path: "./ganache-accounts.json",
vmErrorsOnRPCResponse: false,
total_accounts: 18,
_chainId: 265669100,
_chainIdRpc: 265669100,
network_id: 265669100,
accounts: [
{secretKey:"0x0355596cdb5e5242ad082c4fe3f8bbe48c9dba843fe1f99dd8272f487e70efae","balance":"100000000000000000000"},
{secretKey:"0xe9aebe8791ad1ebd33211687e9c53f13fe8cca53b271a6529c7d7ba05eda5ce2","balance":"100000000000000000000"},
Expand All @@ -56,5 +59,5 @@ module.exports = {
},
onCompileComplete: provisionTokenContracts,
istanbulFolder: "./coverage-contracts",
modifierWhitelist: ["always"],
modifierWhitelist: ["always", "onlyMiningChain", "onlyNotMiningChain"],
}
41 changes: 34 additions & 7 deletions contracts/colony/Colony.sol
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ contract Colony is BasicMetaTransaction, Multicall, ColonyStorage, PatriciaTreeP
function addGlobalSkill() public
stoppable
auth
onlyMiningChain
returns (uint256)
{
return IColonyNetwork(colonyNetworkAddress).addSkill(0); // ignore-swc-107
Expand Down Expand Up @@ -214,6 +215,38 @@ contract Colony is BasicMetaTransaction, Multicall, ColonyStorage, PatriciaTreeP
IColonyNetwork(colonyNetworkAddress).addColonyVersion(_version, _resolver);
}

function setBridgeData(
address _bridgeAddress,
uint256 _chainId,
uint256 _gas,
bytes4 _msgSenderSig,
address _correspondingNetwork,
bytes memory _updateLogBefore,
bytes memory _updateLogAfter,
bytes memory _skillCreationBefore,
bytes memory _skillCreationAfter,
bytes memory _setReputationRootHashBefore,
bytes memory _setReputationRootHashAfter
)
external
stoppable
auth
{
IColonyNetwork(colonyNetworkAddress).setBridgeData(
_bridgeAddress,
_chainId,
_gas,
_msgSenderSig,
_correspondingNetwork,
_updateLogBefore,
_updateLogAfter,
_skillCreationBefore,
_skillCreationAfter,
_setReputationRootHashBefore,
_setReputationRootHashAfter
);
}

function addExtensionToNetwork(bytes32 _extensionId, address _resolver)
public stoppable auth
{
Expand Down Expand Up @@ -315,14 +348,8 @@ contract Colony is BasicMetaTransaction, Multicall, ColonyStorage, PatriciaTreeP
ColonyAuthority colonyAuthority = ColonyAuthority(address(authority));
bytes4 sig;

sig = bytes4(keccak256("makeArbitraryTransactions(address[],bytes[],bool)"));
sig = bytes4(keccak256("setBridgeData(address,uint256,uint256,bytes4,address,bytes,bytes,bytes,bytes,bytes,bytes)"));
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)"));
colonyAuthority.setRoleCapability(uint8(ColonyRole.Arbitration), address(this), sig, true);
}

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

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

// Added in colony vxxx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure to set this before merging

addRoleCapability(ROOT_ROLE, "setBridgeData(address,uint256,uint256,bytes4,address,bytes,bytes,bytes,bytes,bytes,bytes)");
}

function addRoleCapability(uint8 role, bytes memory sig) private {
Expand Down
1 change: 0 additions & 1 deletion contracts/colony/ColonyRewards.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ pragma experimental "ABIEncoderV2";
import "./../tokenLocking/ITokenLocking.sol";
import "./ColonyStorage.sol";


contract ColonyRewards is ColonyStorage, PatriciaTreeProofs { // ignore-swc-123
function lockToken() public stoppable onlyOwnExtension returns (uint256) {
uint256 lockId = ITokenLocking(tokenLockingAddress).lockToken(token);
Expand Down
26 changes: 26 additions & 0 deletions contracts/colony/IMetaColony.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,30 @@ interface IMetaColony is IColony {
/// @param _extensionId keccak256 hash of the extension name, used as an indentifier
/// @param _resolver The deployed resolver containing the extension contract logic
function addExtensionToNetwork(bytes32 _extensionId, address _resolver) external;

/// @notice Called to set the details about bridge _bridgeAddress
/// @param _bridgeAddress The address of the bridge
/// @param _chainId The chainId of the corresponding network
/// @param _gas How much gas to use for a bridged transaction
/// @param _msgSenderFunctionSig The function signature of the function to call on the bridge to get the msgSender
/// @param _correspondingNetwork The address of the corresponding colony network contract on the other network
/// @param _updateLogBefore The tx data before the dynamic part of the tx to bridge to the update log
/// @param _updateLogAfter The tx data after the dynamic part of the tx to bridge to the update log
/// @param _skillCreationBefore The tx data before the dynamic part of the tx to brdige skill creation
/// @param _skillCreationAfter The tx data after the dynamic part of the tx to brdige skill creation
/// @param _setReputationRootHashBefore The tx data before the dynamic part of the tx to bridge a new reputation root hash
/// @param _setReputationRootHashAfter The tx data after the dynamic part of the tx to bridge a new reputation root hash
function setBridgeData(
address _bridgeAddress,
uint256 _chainId,
uint256 _gas,
bytes4 _msgSenderFunctionSig,
address _correspondingNetwork,
bytes memory _updateLogBefore,
bytes memory _updateLogAfter,
bytes memory _skillCreationBefore,
bytes memory _skillCreationAfter,
bytes memory _setReputationRootHashBefore,
bytes memory _setReputationRootHashAfter
) external;
}
138 changes: 4 additions & 134 deletions contracts/colonyNetwork/ColonyNetwork.sol
Original file line number Diff line number Diff line change
Expand Up @@ -111,132 +111,17 @@ contract ColonyNetwork is BasicMetaTransaction, ColonyNetworkStorage, Multicall
colonyVersionResolver[_version] = _resolver;
currentColonyVersion = _version;

if (!isMiningChain()){
skillCount = toRootSkillId(getChainId());
}

emit ColonyNetworkInitialised(_resolver);
}

function getColony(uint256 _id) public view returns (address) {
return colonies[_id];
}

function addSkill(uint _parentSkillId) public stoppable
skillExists(_parentSkillId)
allowedToAddSkill(_parentSkillId == 0)
returns (uint256)
{
skillCount += 1;

Skill storage parentSkill = skills[_parentSkillId];
// Global and local skill trees are kept separate
require(_parentSkillId == 0 || !parentSkill.globalSkill, "colony-global-and-local-skill-trees-are-separate");

Skill memory s;
if (_parentSkillId != 0) {

s.nParents = parentSkill.nParents + 1;
skills[skillCount] = s;

uint parentSkillId = _parentSkillId;
bool notAtRoot = true;
uint powerOfTwo = 1;
uint treeWalkingCounter = 1;

// Walk through the tree parent skills up to the root
while (notAtRoot) {
// Add the new skill to each parent children
parentSkill.children.push(skillCount);
parentSkill.nChildren += 1;

// When we are at an integer power of two steps away from the newly added skill (leaf) node,
// add the current parent skill to the new skill's parents array
if (treeWalkingCounter == powerOfTwo) {
// slither-disable-next-line controlled-array-length
skills[skillCount].parents.push(parentSkillId);
powerOfTwo = powerOfTwo*2;
}

// Check if we've reached the root of the tree yet (it has no parents)
// Otherwise get the next parent
if (parentSkill.nParents == 0) {
notAtRoot = false;
} else {
parentSkillId = parentSkill.parents[0];
parentSkill = skills[parentSkill.parents[0]];
}

treeWalkingCounter += 1;
}
} else {
// Add a global skill
s.globalSkill = true;
skills[skillCount] = s;
}

emit SkillAdded(skillCount, _parentSkillId);
return skillCount;
}

function getParentSkillId(uint _skillId, uint _parentSkillIndex) public view returns (uint256) {
return ascendSkillTree(_skillId, _parentSkillIndex + 1);
}

function getChildSkillId(uint _skillId, uint _childSkillIndex) public view returns (uint256) {
if (_childSkillIndex == UINT256_MAX) {
return _skillId;
} else {
Skill storage skill = skills[_skillId];
require(_childSkillIndex < skill.children.length, "colony-network-out-of-range-child-skill-index");
return skill.children[_childSkillIndex];
}
}

function deprecateSkill(uint256 _skillId, bool _deprecated) public stoppable
allowedToAddSkill(skills[_skillId].nParents == 0)
returns (bool)
{
bool changed = skills[_skillId].deprecated != _deprecated;
skills[_skillId].deprecated = _deprecated;
return changed;
}

/// @notice @deprecated
function deprecateSkill(uint256 _skillId) public stoppable {
deprecateSkill(_skillId, true);
}

function initialiseRootLocalSkill() public
stoppable
calledByColony
returns (uint256)
{
return skillCount++;
}

function appendReputationUpdateLog(address _user, int _amount, uint _skillId) public
stoppable
calledByColony
skillExists(_skillId)
{
if (_amount == 0 || _user == address(0x0)) {
// We short-circut amount=0 as it has no effect to save gas, and we ignore Address Zero because it will
// mess up the tracking of the total amount of reputation in a colony, as that's the key that it's
// stored under in the patricia/merkle tree. Colonies can still pay tokens out to it if they want,
// it just won't earn reputation.
return;
}

uint128 nParents = skills[_skillId].nParents;
// We only update child skill reputation if the update is negative, otherwise just set nChildren to 0 to save gas
uint128 nChildren = _amount < 0 ? skills[_skillId].nChildren : 0;
IReputationMiningCycle(inactiveReputationMiningCycle).appendReputationUpdateLog(
_user,
_amount,
_skillId,
msgSender(),
nParents,
nChildren
);
}

function checkNotAdditionalProtectedVariable(uint256 _slot) public view { // solhint-disable-line no-empty-blocks
}

Expand Down Expand Up @@ -278,19 +163,4 @@ contract ColonyNetwork is BasicMetaTransaction, ColonyNetworkStorage, Multicall
protectSlot(slot);
metatransactionNonces[_user] += 1;
}

function ascendSkillTree(uint _skillId, uint _parentSkillNumber) internal view returns (uint256) {
if (_parentSkillNumber == 0) {
return _skillId;
}

Skill storage skill = skills[_skillId];
for (uint256 i; i < skill.parents.length; i++) {
if (2**(i+1) > _parentSkillNumber) {
uint _newSkillId = skill.parents[i];
uint _newParentSkillNumber = _parentSkillNumber - 2**i;
return ascendSkillTree(_newSkillId, _newParentSkillNumber);
}
}
}
}
11 changes: 5 additions & 6 deletions contracts/colonyNetwork/ColonyNetworkAuction.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@
pragma solidity 0.8.21;

import "./ColonyNetworkStorage.sol";
import "./../common/MultiChain.sol";
import "./../common/BasicMetaTransaction.sol";

contract ColonyNetworkAuction is ColonyNetworkStorage, MultiChain {
contract ColonyNetworkAuction is ColonyNetworkStorage {
function startTokenAuction(address _token) public
stoppable
auth
Expand All @@ -39,12 +38,12 @@ contract ColonyNetworkAuction is ColonyNetworkStorage, MultiChain {
if (_token==clny) {
// We don't auction CLNY. We just burn it instead.
// Note we can do this more often than every 30 days.
if (isXdai()){
// On Xdai, we can't burn bridged tokens
if (isMainnet()){
ERC20Extended(clny).burn(availableTokens);
} else {
// Elsewhere, we can't burn bridged tokens
// so let's send them to the metacolony for now.
require(ERC20Extended(clny).transfer(metaColony, availableTokens), "colony-network-transfer-failed");
} else {
ERC20Extended(clny).burn(availableTokens);
}
return;
}
Expand Down
Loading