Skip to content

Commit 21ae75b

Browse files
committed
Allow funds to be sent directly to domains
1 parent 2e44639 commit 21ae75b

25 files changed

+544
-1
lines changed

.storage-layouts-normalized/contracts/colonyNetwork/ColonyNetwork.sol:ColonyNetwork.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,17 @@
11321132
}
11331133
}
11341134
}
1135+
},
1136+
{
1137+
"contract": "contracts/colonyNetwork/ColonyNetwork.sol:ColonyNetwork",
1138+
"label": "domainReceiverResolverAddress",
1139+
"offset": 0,
1140+
"slot": "50",
1141+
"type": {
1142+
"encoding": "inplace",
1143+
"label": "address",
1144+
"numberOfBytes": "20"
1145+
}
11351146
}
11361147
]
11371148
}

.storage-layouts-normalized/contracts/colonyNetwork/ColonyNetworkAuction.sol:ColonyNetworkAuction.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,17 @@
11321132
}
11331133
}
11341134
}
1135+
},
1136+
{
1137+
"contract": "contracts/colonyNetwork/ColonyNetworkAuction.sol:ColonyNetworkAuction",
1138+
"label": "domainReceiverResolverAddress",
1139+
"offset": 0,
1140+
"slot": "50",
1141+
"type": {
1142+
"encoding": "inplace",
1143+
"label": "address",
1144+
"numberOfBytes": "20"
1145+
}
11351146
}
11361147
]
11371148
}

.storage-layouts-normalized/contracts/colonyNetwork/ColonyNetworkDeployer.sol:ColonyNetworkDeployer.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,17 @@
11321132
}
11331133
}
11341134
}
1135+
},
1136+
{
1137+
"contract": "contracts/colonyNetwork/ColonyNetworkDeployer.sol:ColonyNetworkDeployer",
1138+
"label": "domainReceiverResolverAddress",
1139+
"offset": 0,
1140+
"slot": "50",
1141+
"type": {
1142+
"encoding": "inplace",
1143+
"label": "address",
1144+
"numberOfBytes": "20"
1145+
}
11351146
}
11361147
]
11371148
}

.storage-layouts-normalized/contracts/colonyNetwork/ColonyNetworkENS.sol:ColonyNetworkENS.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,17 @@
11321132
}
11331133
}
11341134
}
1135+
},
1136+
{
1137+
"contract": "contracts/colonyNetwork/ColonyNetworkENS.sol:ColonyNetworkENS",
1138+
"label": "domainReceiverResolverAddress",
1139+
"offset": 0,
1140+
"slot": "50",
1141+
"type": {
1142+
"encoding": "inplace",
1143+
"label": "address",
1144+
"numberOfBytes": "20"
1145+
}
11351146
}
11361147
]
11371148
}

.storage-layouts-normalized/contracts/colonyNetwork/ColonyNetworkExtensions.sol:ColonyNetworkExtensions.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,17 @@
11321132
}
11331133
}
11341134
}
1135+
},
1136+
{
1137+
"contract": "contracts/colonyNetwork/ColonyNetworkExtensions.sol:ColonyNetworkExtensions",
1138+
"label": "domainReceiverResolverAddress",
1139+
"offset": 0,
1140+
"slot": "50",
1141+
"type": {
1142+
"encoding": "inplace",
1143+
"label": "address",
1144+
"numberOfBytes": "20"
1145+
}
11351146
}
11361147
]
11371148
}

.storage-layouts-normalized/contracts/colonyNetwork/ColonyNetworkMining.sol:ColonyNetworkMining.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,17 @@
11321132
}
11331133
}
11341134
}
1135+
},
1136+
{
1137+
"contract": "contracts/colonyNetwork/ColonyNetworkMining.sol:ColonyNetworkMining",
1138+
"label": "domainReceiverResolverAddress",
1139+
"offset": 0,
1140+
"slot": "50",
1141+
"type": {
1142+
"encoding": "inplace",
1143+
"label": "address",
1144+
"numberOfBytes": "20"
1145+
}
11351146
}
11361147
]
11371148
}

.storage-layouts-normalized/contracts/colonyNetwork/ColonyNetworkSkills.sol:ColonyNetworkSkills.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,17 @@
11321132
}
11331133
}
11341134
}
1135+
},
1136+
{
1137+
"contract": "contracts/colonyNetwork/ColonyNetworkSkills.sol:ColonyNetworkSkills",
1138+
"label": "domainReceiverResolverAddress",
1139+
"offset": 0,
1140+
"slot": "50",
1141+
"type": {
1142+
"encoding": "inplace",
1143+
"label": "address",
1144+
"numberOfBytes": "20"
1145+
}
11351146
}
11361147
]
11371148
}

.storage-layouts-normalized/contracts/colonyNetwork/ColonyNetworkStorage.sol:ColonyNetworkStorage.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,17 @@
11321132
}
11331133
}
11341134
}
1135+
},
1136+
{
1137+
"contract": "contracts/colonyNetwork/ColonyNetworkStorage.sol:ColonyNetworkStorage",
1138+
"label": "domainReceiverResolverAddress",
1139+
"offset": 0,
1140+
"slot": "50",
1141+
"type": {
1142+
"encoding": "inplace",
1143+
"label": "address",
1144+
"numberOfBytes": "20"
1145+
}
11351146
}
11361147
]
11371148
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"storage": [
3+
{
4+
"contract": "contracts/common/DomainTokenReceiver.sol:DomainTokenReceiver",
5+
"label": "authority",
6+
"offset": 0,
7+
"slot": "0",
8+
"type": {
9+
"encoding": "inplace",
10+
"label": "contract DSAuthority",
11+
"numberOfBytes": "20"
12+
}
13+
},
14+
{
15+
"contract": "contracts/common/DomainTokenReceiver.sol:DomainTokenReceiver",
16+
"label": "owner",
17+
"offset": 0,
18+
"slot": "1",
19+
"type": {
20+
"encoding": "inplace",
21+
"label": "address",
22+
"numberOfBytes": "20"
23+
}
24+
},
25+
{
26+
"contract": "contracts/common/DomainTokenReceiver.sol:DomainTokenReceiver",
27+
"label": "resolver",
28+
"offset": 0,
29+
"slot": "2",
30+
"type": {
31+
"encoding": "inplace",
32+
"label": "address",
33+
"numberOfBytes": "20"
34+
}
35+
},
36+
{
37+
"contract": "contracts/common/DomainTokenReceiver.sol:DomainTokenReceiver",
38+
"label": "colony",
39+
"offset": 0,
40+
"slot": "3",
41+
"type": {
42+
"encoding": "inplace",
43+
"label": "address",
44+
"numberOfBytes": "20"
45+
}
46+
}
47+
]
48+
}

contracts/colony/ColonyFunding.sol

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { ITokenLocking } from "./../tokenLocking/ITokenLocking.sol";
2323
import { ColonyStorage } from "./ColonyStorage.sol";
2424
import { ERC20Extended } from "./../common/ERC20Extended.sol";
2525
import { IColonyNetwork } from "./../colonyNetwork/IColonyNetwork.sol";
26+
import { DomainTokenReceiver } from "./../common/DomainTokenReceiver.sol";
2627

2728
contract ColonyFunding is
2829
ColonyStorage // ignore-swc-123
@@ -106,6 +107,47 @@ contract ColonyFunding is
106107
emit ColonyFundsClaimed(msgSender(), _token, feeToPay, remainder);
107108
}
108109

110+
function claimDomainFunds(address _token, uint256 _domainId) public stoppable {
111+
require(domainExists(_domainId), "colony-funding-domain-does-not-exist");
112+
address domainTokenReceiverAddress = IColonyNetwork(colonyNetworkAddress)
113+
.checkDomainTokenReceiverDeployed(_domainId);
114+
uint256 fundingPotId = domains[_domainId].fundingPotId;
115+
// It's deployed, so check current balance of pot
116+
uint256 balanceBefore = getFundingPotBalance(fundingPotId, _token);
117+
118+
uint256 claimAmount;
119+
uint256 thisBalanceBefore;
120+
121+
if (_token == address(0x0)) {
122+
claimAmount = address(domainTokenReceiverAddress).balance;
123+
thisBalanceBefore = address(this).balance;
124+
} else {
125+
claimAmount = ERC20Extended(_token).balanceOf(address(domainTokenReceiverAddress));
126+
thisBalanceBefore = ERC20Extended(_token).balanceOf(address(this));
127+
}
128+
129+
fundingPots[fundingPotId].balance[_token] += claimAmount;
130+
131+
// Claim funds
132+
133+
DomainTokenReceiver(domainTokenReceiverAddress).transferToColony(_token);
134+
135+
// Add to funding pot
136+
137+
uint256 balanceAfter = getFundingPotBalance(fundingPotId, _token);
138+
139+
assert(balanceAfter - balanceBefore == claimAmount);
140+
141+
uint256 thisBalanceAfter;
142+
if (_token == address(0x0)) {
143+
thisBalanceAfter = address(this).balance;
144+
} else {
145+
thisBalanceAfter = ERC20Extended(_token).balanceOf(address(this));
146+
}
147+
148+
assert(thisBalanceAfter - thisBalanceBefore == claimAmount);
149+
}
150+
109151
function getNonRewardPotsTotal(address _token) public view returns (uint256) {
110152
return nonRewardPotsTotal[_token];
111153
}

contracts/colony/IColony.sol

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,12 @@ interface IColony is ColonyDataTypes, IRecovery, IBasicMetaTransaction, IMultica
830830
/// @param _token Address of the token, `0x0` value indicates Ether
831831
function claimColonyFunds(address _token) external;
832832

833+
/// @notice Move any funds received by the colony for a specific domain to that domain's pot
834+
/// Currently no fees are taken
835+
/// @param _token Address of the token, `0x0` value indicates Ether
836+
/// @param _domainId Id of the domain
837+
function claimDomainFunds(address _token, uint256 _domainId) external;
838+
833839
/// @notice Get the total amount of tokens `_token` minus amount reserved to be paid to the reputation and token holders as rewards.
834840
/// @param _token Address of the token, `0x0` value indicates Ether
835841
/// @return amount Total amount of tokens in funding pots other than the rewards pot (id 0)

contracts/colonyNetwork/ColonyNetworkDeployer.sol

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
pragma solidity 0.8.25;
2020
pragma experimental "ABIEncoderV2";
2121
import { EtherRouter } from "./../common/EtherRouter.sol";
22+
import { Resolver } from "./../common/Resolver.sol";
2223
import { ColonyAuthority } from "./../colony/ColonyAuthority.sol";
2324
import { IColony } from "./../colony/IColony.sol";
2425
import { ColonyNetworkStorage } from "./ColonyNetworkStorage.sol";
@@ -27,6 +28,8 @@ import { MetaTxToken } from "./../metaTxToken/MetaTxToken.sol";
2728
import { DSAuth, DSAuthority } from "./../../lib/dappsys/auth.sol";
2829
import { ICreateX } from "./../../lib/createx/src/ICreateX.sol";
2930
import { EtherRouterCreate3 } from "./../common/EtherRouterCreate3.sol";
31+
import { IColonyBridge } from "./../bridging/IColonyBridge.sol";
32+
import { DomainTokenReceiver } from "./../common/DomainTokenReceiver.sol";
3033

3134
contract ColonyNetworkDeployer is ColonyNetworkStorage {
3235
address constant CREATEX_ADDRESS = 0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed;
@@ -175,6 +178,94 @@ contract ColonyNetworkDeployer is ColonyNetworkStorage {
175178
// This is intentional, as we want to allow the same Colony to be deployed on different chains
176179
}
177180

181+
function setDomainTokenReceiverResolver(address _resolver) public stoppable auth {
182+
domainReceiverResolverAddress = _resolver;
183+
}
184+
185+
function getDomainTokenReceiverResolver() public view returns (address) {
186+
return domainReceiverResolverAddress;
187+
}
188+
189+
function checkDomainTokenReceiverDeployed(
190+
uint256 _domainId
191+
) public stoppable calledByColony returns (address domainTokenReceiverAddress) {
192+
// Calculate the address the domain should be receiving funds at
193+
domainTokenReceiverAddress = getDomainTokenReceiverAddress(msgSender(), _domainId);
194+
195+
if (!isContract(domainTokenReceiverAddress)) {
196+
// Then deploy the contract
197+
bytes32 salt = getDomainTokenReceiverDeploySalt(msgSender(), _domainId);
198+
address deployedAddress = ICreateX(CREATEX_ADDRESS).deployCreate3AndInit(
199+
salt,
200+
type(EtherRouterCreate3).creationCode,
201+
abi.encodeWithSignature("setOwner(address)", (address(this))),
202+
ICreateX.Values(0, 0)
203+
);
204+
require(
205+
deployedAddress == domainTokenReceiverAddress,
206+
"colony-network-domain-receiver-deploy-wrong-address"
207+
);
208+
}
209+
210+
// Check it's got the right resolver
211+
try EtherRouter(payable(domainTokenReceiverAddress)).resolver() returns (Resolver resolver) {
212+
if (address(resolver) != domainReceiverResolverAddress) {
213+
EtherRouter(payable(domainTokenReceiverAddress)).setResolver(domainReceiverResolverAddress);
214+
}
215+
} catch {
216+
revert("colony-network-domain-receiver-not-etherrouter");
217+
}
218+
219+
// Check it's set up correctly
220+
221+
if (DomainTokenReceiver(domainTokenReceiverAddress).getColonyAddress() != msgSender()) {
222+
DomainTokenReceiver(domainTokenReceiverAddress).setColonyAddress(msgSender());
223+
}
224+
225+
return domainTokenReceiverAddress;
226+
}
227+
228+
function isContract(address addr) internal view returns (bool) {
229+
uint256 size;
230+
assembly {
231+
size := extcodesize(addr)
232+
}
233+
return size > 0;
234+
}
235+
236+
function getDomainTokenReceiverAddress(
237+
address _colony,
238+
uint256 _domainId
239+
) public view returns (address) {
240+
bytes32 salt = getDomainTokenReceiverDeploySalt(_colony, _domainId);
241+
242+
// To get the correct address, we have to mimic the _guard functionality of CreateX
243+
bytes32 guardedSalt = keccak256(abi.encode(bytes32(uint256(uint160(address(this)))), salt));
244+
return ICreateX(CREATEX_ADDRESS).computeCreate3Address(guardedSalt);
245+
}
246+
247+
function getDomainTokenReceiverDeploySalt(
248+
address _colony,
249+
uint256 _domainId
250+
) internal view returns (bytes32) {
251+
// Calculate the address the domain should be receiving funds at
252+
// We only want Colony Networks to be able to deploy to the same address,
253+
// so we use the permissioned deploy protection feature of CreateX, and set
254+
// the first 160 bits of the salt to the address of this contract.
255+
256+
bytes32 salt = bytes32(uint256(uint160(address(this)))) << 96;
257+
258+
bytes32 additionalSalt = keccak256(abi.encode(_colony, _domainId));
259+
// We use the first 88 bits of the additional salt, which is a function of the colony and domainId,
260+
// to add entropy in the last 88 bits of the salt
261+
salt = salt | (additionalSalt >> 168);
262+
// We have set the first 160 bits, and the last 88 bits of the salt
263+
// Note that this leaves byte 21 of the salt as zero (0x00), which disables cross-chain
264+
// redeployment protection in createX.
265+
// This is intentional, as we want to allow the same receiver to be deployed on different chains
266+
return salt;
267+
}
268+
178269
function deployColony(address _tokenAddress, uint256 _version) internal returns (address) {
179270
require(_tokenAddress != address(0x0), "colony-token-invalid-address");
180271
require(colonyVersionResolver[_version] != address(0x00), "colony-network-invalid-version");

contracts/colonyNetwork/ColonyNetworkStorage.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ contract ColonyNetworkStorage is ColonyNetworkDataTypes, DSMath, CommonStorage,
129129
// networkId -> colonyAddress -> updateCount -> update
130130
mapping(uint256 => mapping(address => mapping(uint256 => PendingReputationUpdate))) pendingReputationUpdates; // Storage slot 49
131131

132+
address domainReceiverResolverAddress; // Storage slot 50
132133
// Modifiers
133134

134135
modifier calledByColony() {

0 commit comments

Comments
 (0)