Skip to content

Commit 60a8ee6

Browse files
committed
Introduce Korporatio extension
1 parent ba3a875 commit 60a8ee6

File tree

6 files changed

+562
-2
lines changed

6 files changed

+562
-2
lines changed
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
/*
2+
This file is part of The Colony Network.
3+
4+
The Colony Network is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
The Colony Network is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with The Colony Network. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
pragma solidity 0.7.3;
19+
pragma experimental ABIEncoderV2;
20+
21+
import "./../../lib/dappsys/erc20.sol";
22+
import "./../colonyNetwork/IColonyNetwork.sol";
23+
import "./ColonyExtensionMeta.sol";
24+
25+
// ignore-file-swc-108
26+
27+
28+
contract Korporatio is ColonyExtensionMeta {
29+
30+
// Constants
31+
32+
// Events
33+
34+
event StakeSubmitted(uint256 indexed stakeId, address indexed staker);
35+
event StakeCancelled(uint256 indexed stakeId);
36+
event StakeReclaimed(uint256 indexed stakeId);
37+
event StakeSlashed(uint256 indexed stakeId);
38+
event ApplicationHashUpdated(uint256 indexed stakeId, bytes32 ipfsHash);
39+
event ApplicationHashSubmitted(uint256 indexed stakeId, bytes32 ipfsHash);
40+
41+
// Data structures
42+
43+
struct Stake {
44+
address staker;
45+
uint256 amount;
46+
uint256 cancelledAt;
47+
}
48+
49+
// Storage
50+
51+
address colonyNetworkAddress;
52+
uint256 stakeFraction;
53+
uint256 claimDelay;
54+
55+
uint256 numStakes;
56+
mapping (uint256 => Stake) stakes;
57+
58+
// Modifiers
59+
60+
modifier onlyRootArchitect() {
61+
require(
62+
colony.hasUserRole(msgSender(), 1, ColonyDataTypes.ColonyRole.Architecture),
63+
"korporatio-caller-not-root-architect"
64+
);
65+
_;
66+
}
67+
68+
// Overrides
69+
70+
/// @notice Returns the identifier of the extension
71+
function identifier() public override pure returns (bytes32) {
72+
return keccak256("Korporatio");
73+
}
74+
75+
/// @notice Returns the version of the extension
76+
function version() public override pure returns (uint256) {
77+
return 1;
78+
}
79+
80+
/// @notice Configures the extension
81+
/// @param _colony The colony in which the extension holds permissions
82+
function install(address _colony) public override auth {
83+
require(address(colony) == address(0x0), "extension-already-installed");
84+
85+
colony = IColony(_colony);
86+
colonyNetworkAddress = colony.getColonyNetwork();
87+
}
88+
89+
/// @notice Called when upgrading the extension
90+
function finishUpgrade() public override auth {}
91+
92+
/// @notice Called when deprecating (or undeprecating) the extension
93+
function deprecate(bool _deprecated) public override auth {
94+
deprecated = _deprecated;
95+
}
96+
97+
/// @notice Called when uninstalling the extension
98+
function uninstall() public override auth {
99+
selfdestruct(address(uint160(address(colony))));
100+
}
101+
102+
// Public
103+
104+
function setStakeFraction(uint256 _stakeFraction) public onlyRootArchitect {
105+
stakeFraction = _stakeFraction;
106+
}
107+
108+
function setClaimDelay(uint256 _claimDelay) public onlyRootArchitect {
109+
claimDelay = _claimDelay;
110+
}
111+
112+
function submitStake(
113+
bytes memory _colonyKey,
114+
bytes memory _colonyValue,
115+
uint256 _colonyBranchMask,
116+
bytes32[] memory _colonySiblings,
117+
bytes memory _userKey,
118+
bytes memory _userValue,
119+
uint256 _userBranchMask,
120+
bytes32[] memory _userSiblings
121+
)
122+
public
123+
notDeprecated
124+
{
125+
bytes32 rootHash = IColonyNetwork(colonyNetworkAddress).getReputationRootHash();
126+
uint256 rootSkillId = colony.getDomain(1).skillId;
127+
128+
uint256 colonyReputation = checkReputation(rootHash, rootSkillId, address(0x0), _colonyKey, _colonyValue, _colonyBranchMask, _colonySiblings);
129+
uint256 userReputation = checkReputation(rootHash, rootSkillId, msgSender(), _userKey, _userValue, _userBranchMask, _userSiblings);
130+
131+
uint256 requiredStake = wmul(colonyReputation, stakeFraction);
132+
require(userReputation >= requiredStake, "korporatio-insufficient-rep");
133+
134+
stakes[++numStakes] = Stake({
135+
staker: msgSender(),
136+
amount: requiredStake,
137+
cancelledAt: UINT256_MAX
138+
});
139+
140+
colony.obligateStake(msgSender(), 1, requiredStake);
141+
142+
emit StakeSubmitted(numStakes, msgSender());
143+
}
144+
145+
function submitNullStake()
146+
public
147+
notDeprecated
148+
{
149+
require (
150+
colony.hasUserRole(msgSender(), 1, ColonyDataTypes.ColonyRole.Root) ||
151+
colony.hasUserRole(msgSender(), 1, ColonyDataTypes.ColonyRole.Administration),
152+
"korporatio-must-submit-stake"
153+
);
154+
155+
stakes[++numStakes] = Stake({
156+
staker: msgSender(),
157+
amount: 0,
158+
cancelledAt: UINT256_MAX
159+
});
160+
161+
emit StakeSubmitted(numStakes, msgSender());
162+
}
163+
164+
function cancelStake(uint256 _stakeId) public {
165+
require(stakes[_stakeId].staker == msgSender(), "korporatio-cannot-cancel");
166+
167+
stakes[_stakeId].cancelledAt = block.timestamp;
168+
169+
emit StakeCancelled(_stakeId);
170+
}
171+
172+
function reclaimStake(uint256 _stakeId) public {
173+
Stake storage stake = stakes[_stakeId];
174+
require(stake.cancelledAt + claimDelay <= block.timestamp, "korporatio-cannot-reclaim");
175+
176+
uint256 stakeAmount = stake.amount;
177+
delete stakes[_stakeId];
178+
179+
colony.deobligateStake(msgSender(), 1, stakeAmount);
180+
181+
emit StakeReclaimed(_stakeId);
182+
}
183+
184+
function slashStake(uint256 _stakeId, bool _punish) public {
185+
require(stakes[_stakeId].amount > 0, "korporatio-cannot-slash");
186+
187+
require(
188+
colony.hasInheritedUserRole(msgSender(), 1, ColonyDataTypes.ColonyRole.Arbitration, UINT256_MAX, 1),
189+
"staked-expenditure-caller-not-arbitration"
190+
);
191+
192+
address staker = stakes[_stakeId].staker;
193+
uint256 amount = stakes[_stakeId].amount;
194+
delete stakes[_stakeId];
195+
196+
colony.transferStake(1, UINT256_MAX, address(this), staker, 1, amount, address(0x0));
197+
if (_punish) { colony.emitDomainReputationPenalty(1, UINT256_MAX, 1, staker, -int256(amount)); }
198+
199+
emit StakeSlashed(_stakeId);
200+
}
201+
202+
function updateIpfsHash(uint256 _stakeId, bytes32 _ipfsHash) public {
203+
require(stakes[_stakeId].staker == msgSender(), "korporatio-not-staker");
204+
require(stakes[_stakeId].cancelledAt == UINT256_MAX, "korporatio-stake-cancelled");
205+
206+
emit ApplicationHashUpdated(_stakeId, _ipfsHash);
207+
}
208+
209+
function submitIpfsHash(uint256 _stakeId, bytes32 _ipfsHash) public {
210+
require(colony.hasUserRole(msgSender(), 1, ColonyDataTypes.ColonyRole.Root), "korporatio-caller-not-root");
211+
require(stakes[_stakeId].cancelledAt == UINT256_MAX, "korporatio-stake-cancelled");
212+
213+
stakes[_stakeId].cancelledAt = block.timestamp;
214+
215+
emit ApplicationHashSubmitted(_stakeId, _ipfsHash);
216+
}
217+
218+
// View
219+
220+
function getNumStakes() external view returns (uint256) {
221+
return numStakes;
222+
}
223+
224+
function getStakeFraction() external view returns (uint256) {
225+
return stakeFraction;
226+
}
227+
228+
function getClaimDelay() external view returns (uint256) {
229+
return claimDelay;
230+
}
231+
232+
function getStake(uint256 _id) external view returns (Stake memory stake) {
233+
return stakes[_id];
234+
}
235+
}

migrations/9_setup_extensions.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const VotingReputation = artifacts.require("./VotingReputation");
1515
const VotingReputationMisalignedRecovery = artifacts.require("./VotingReputationMisalignedRecovery");
1616
const TokenSupplier = artifacts.require("./TokenSupplier");
1717
const Whitelist = artifacts.require("./Whitelist");
18+
const Korporatio = artifacts.require("./Korporatio");
1819

1920
const Resolver = artifacts.require("./Resolver");
2021
const EtherRouter = artifacts.require("./EtherRouter");
@@ -53,4 +54,5 @@ module.exports = async function (deployer, network, accounts) {
5354
await addExtension(colonyNetwork, "TokenSupplier", "TokenSupplier", [TokenSupplier]);
5455
await addExtension(colonyNetwork, "IVotingReputation", "VotingReputation", [VotingReputation, VotingReputationMisalignedRecovery]);
5556
await addExtension(colonyNetwork, "Whitelist", "Whitelist", [Whitelist]);
57+
await addExtension(colonyNetwork, "Korporatio", "Korporatio", [Korporatio]);
5658
};

scripts/check-recovery.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ walkSync("./contracts/").forEach((contractName) => {
5353
"contracts/extensions/EvaluatedExpenditure.sol",
5454
"contracts/extensions/StakedExpenditure.sol",
5555
"contracts/extensions/FundingQueue.sol",
56+
"contracts/extensions/Korporatio.sol",
5657
"contracts/extensions/OneTxPayment.sol",
5758
"contracts/extensions/ReputationBootstrapper.sol",
5859
"contracts/extensions/StreamingPayments.sol",

scripts/check-storage.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ walkSync("./contracts/").forEach((contractName) => {
3333
"contracts/extensions/FundingQueue.sol",
3434
"contracts/extensions/ColonyExtension.sol",
3535
"contracts/extensions/ColonyExtensionMeta.sol",
36+
"contracts/extensions/Korporatio.sol",
3637
"contracts/extensions/OneTxPayment.sol",
3738
"contracts/extensions/ReputationBootstrapper.sol",
3839
"contracts/extensions/StreamingPayments.sol",

test-smoke/colony-storage-consistent.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,8 @@ contract("Contract Storage", (accounts) => {
149149
console.log("miningCycleStateHash:", miningCycleStateHash);
150150
console.log("tokenLockingStateHash:", tokenLockingStateHash);
151151

152-
expect(colonyNetworkStateHash).to.equal("0x2d9b33d6c639d46a7c9b73e5e488cc624886105a574d05c3e465c6e6da27f75f");
153-
expect(colonyStateHash).to.equal("0x54a0edcb2097270bd95d610dc827869cc827241d131461f58788f7c3257ca151");
152+
expect(colonyNetworkStateHash).to.equal("0x7539cecc0ff5cc09e32b43de9d7972ad2b4fc876942783481dcbe2905682837f");
153+
expect(colonyStateHash).to.equal("0xa316afd674b96f4efb00be8622278ed30e15765e23b9dee4b93cc355c56018da");
154154
expect(metaColonyStateHash).to.equal("0x15fab25907cfb6baedeaf1fdabd68678d37584a1817a08dfe77db60db378a508");
155155
expect(miningCycleStateHash).to.equal("0x632d459a2197708bd2dbde87e8275c47dddcdf16d59e3efd21dcef9acb2a7366");
156156
expect(tokenLockingStateHash).to.equal("0x30fbcbfbe589329fe20288101faabe1f60a4610ae0c0effb15526c6b390a8e07");

0 commit comments

Comments
 (0)