Skip to content

Commit 6655f36

Browse files
committed
feat: add StreamWeightActor with unanimousNoHold governance and tests
Assisted-by: Claude:claude-sonnet-4-6
1 parent d9bce85 commit 6655f36

3 files changed

Lines changed: 396 additions & 0 deletions

File tree

src/StreamWeightActor.sol

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// SPDX-License-Identifier: Apache-2.0 OR MIT
2+
pragma solidity ^0.8.36;
3+
4+
import {FVMRewards} from "./lib/FVMRewards.sol";
5+
import {DistributionKind, PendingOp, WeightRecord} from "./lib/FVMRewardTypes.sol";
6+
import {OwnersLibrary} from "./lib/Owners.sol";
7+
import {UnanimousGovernance} from "./lib/UnanimousGovernance.sol";
8+
import {IsASafe} from "./lib/IsASafe.sol";
9+
10+
contract StreamWeightActor is UnanimousGovernance {
11+
using IsASafe for address;
12+
using OwnersLibrary for address;
13+
14+
constructor(address owner1, address owner2) {
15+
owner1.isProbablyASafe();
16+
owner2.isProbablyASafe();
17+
18+
owner1.addOwner();
19+
owner2.addOwner();
20+
}
21+
22+
function registerStream(
23+
uint64 id,
24+
WeightRecord calldata record,
25+
DistributionKind kind,
26+
address writer,
27+
uint64 activationEpoch
28+
) external unanimousNoHold(keccak256(msg.data)) {
29+
// hold enforced in f02
30+
FVMRewards.registerStream(id, record, kind, writer, activationEpoch);
31+
}
32+
33+
function removeStream(uint64 id) external unanimousNoHold(keccak256(msg.data)) {
34+
// hold enforced in f02
35+
FVMRewards.removeStream(id);
36+
}
37+
38+
function setWeightRecords(uint64[] memory ids, WeightRecord[] calldata records)
39+
external
40+
unanimousNoHold(keccak256(msg.data))
41+
{
42+
// hold enforced in f02
43+
FVMRewards.setWeightRecords(ids, records);
44+
}
45+
46+
function setDistribution(uint64 id, DistributionKind kind, address writer)
47+
external
48+
unanimousNoHold(keccak256(msg.data))
49+
{
50+
// hold enforced in f02
51+
FVMRewards.setDistribution(id, kind, writer);
52+
}
53+
54+
function cancelPending(uint64 id, PendingOp op) external {
55+
// any owner can immediately cancel any pending operation
56+
require(msg.sender.isOwner());
57+
FVMRewards.cancelPending(id, op);
58+
}
59+
60+
function replaceOwner(address prevOwner, address newOwner) external unanimousNoHold(keccak256(msg.data)) {
61+
newOwner.isProbablyASafe();
62+
prevOwner.removeOwner();
63+
newOwner.addOwner();
64+
}
65+
}

src/lib/UnanimousGovernance.sol

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,34 @@ contract UnanimousGovernance {
6464
}
6565
}
6666

67+
modifier unanimousNoHold(bytes32 taskId) {
68+
PendingTaskInfo storage taskInfo = PendingTaskLibrary.getTasksSlot()[taskId];
69+
PendingTask memory loaded = taskInfo.task;
70+
OwnerSet allOwners = OwnersLibrary.getAllOwners();
71+
72+
// approve
73+
require(msg.sender.isOwner(), NotOwner(msg.sender));
74+
OwnerSet ownerBit = msg.sender.asOwnerSet();
75+
if (loaded.modified == UNSUBMITTED) {
76+
emit Submitted(taskId);
77+
} else {
78+
require(loaded.approvals & ownerBit == EMPTY_SET, AlreadyApproved());
79+
}
80+
loaded.modified = currentEpoch();
81+
loaded.approvals = loaded.approvals | ownerBit;
82+
83+
// store result
84+
emit Approved(taskId, msg.sender);
85+
if (loaded.approvals & allOwners == allOwners) {
86+
delete taskInfo.task;
87+
// execute now
88+
_;
89+
} else {
90+
// wait
91+
taskInfo.task = loaded;
92+
}
93+
}
94+
6795
/// @param taskId The identifier of the pending task to reject
6896
function _veto(bytes32 taskId) internal {
6997
// load

0 commit comments

Comments
 (0)