Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

optimism deployment #1

Merged
merged 8 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
128 changes: 102 additions & 26 deletions packages/hardhat/contracts/Stream.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@ contract Stream is AccessControl {
address builder;
}

struct BuilderGrantData {
uint256 grantId;
uint8 grantNumber;
}

mapping(uint256 => GrantStream) public grantStreams;
uint256 public nextGrantId = 1;

mapping(address => uint256[]) public builderGrants;
mapping(address => BuilderGrantData[]) public builderGrants;

// uint256 public constant FULL_STREAM_UNLOCK_PERIOD = 180; // 3 minutes
uint256 public constant FULL_STREAM_UNLOCK_PERIOD = 2592000; // 30 days
uint256 public constant DUST_THRESHOLD = 1000000000000000; // 0.001 ETH

Expand All @@ -33,13 +37,25 @@ contract Stream is AccessControl {
uint8 stageNumber
);
event AddGrant(uint256 indexed grantId, address indexed to, uint256 amount);
event ReinitializeGrant(
uint256 indexed grantId,
address indexed to,
uint256 amount
);
event MoveGrantToNextStage(
uint256 indexed grantId,
address indexed to,
uint256 amount,
uint8 grantNumber,
uint8 stageNumber
);
event ReinitializeNextStage(
uint256 indexed grantId,
address indexed builder,
uint256 amount,
uint8 grantNumber,
uint8 stageNumber
);
event UpdateGrant(
uint256 indexed grantId,
address indexed to,
Expand All @@ -59,6 +75,7 @@ contract Stream is AccessControl {
error InsufficientStreamFunds();
error FailedToSendEther();
error PreviousAmountNotFullyWithdrawn();
error AlreadyWithdrawnFromGrant();

constructor(address[] memory _initialOwners) {
_setRoleAdmin(OWNER_ROLE, OWNER_ROLE);
Expand Down Expand Up @@ -92,7 +109,29 @@ contract Stream is AccessControl {
uint256 _cap,
uint8 _grantNumber
) public onlyRole(OWNER_ROLE) returns (uint256) {
uint256 grantId = nextGrantId++;
// check if grantStream with same grantNumber already exists
uint256 existingGrantId;
BuilderGrantData[] memory existingBuilderGrants = builderGrants[
_builder
];
for (uint i = 0; i < existingBuilderGrants.length; i++) {
GrantStream memory existingGrant = grantStreams[
existingBuilderGrants[i].grantId
];
if (existingGrant.grantNumber == _grantNumber) {
if (existingGrant.cap != existingGrant.amountLeft) {
revert AlreadyWithdrawnFromGrant();
}
existingGrantId = existingBuilderGrants[i].grantId;
break;
}
}

// update existing grant or create new one
uint256 grantId = existingGrantId != 0
? existingGrantId
: nextGrantId++;

grantStreams[grantId] = GrantStream({
cap: _cap,
last: block.timestamp,
Expand All @@ -101,8 +140,18 @@ contract Stream is AccessControl {
stageNumber: 1,
builder: _builder
});
builderGrants[_builder].push(grantId);
emit AddGrant(grantId, _builder, _cap);

if (existingGrantId == 0) {
builderGrants[_builder].push(
BuilderGrantData({
grantId: grantId,
grantNumber: _grantNumber
})
);
emit AddGrant(grantId, _builder, _cap);
} else {
emit ReinitializeGrant(grantId, _builder, _cap);
}
return grantId;
}

Expand All @@ -113,28 +162,43 @@ contract Stream is AccessControl {
GrantStream storage grantStream = grantStreams[_grantId];
if (grantStream.cap == 0) revert NoActiveStream();

if (grantStream.amountLeft > DUST_THRESHOLD)
revert PreviousAmountNotFullyWithdrawn();

if (grantStream.amountLeft > 0) {
(bool sent, ) = payable(grantStream.builder).call{
value: grantStream.amountLeft
}("");
if (!sent) revert FailedToSendEther();
// If amountLeft equals cap, reinitialize with same stage number
if (grantStream.amountLeft == grantStream.cap) {
grantStream.cap = _cap;
grantStream.last = block.timestamp;
grantStream.amountLeft = _cap;
// Stage number remains the same
emit ReinitializeNextStage(
_grantId,
grantStream.builder,
_cap,
grantStream.grantNumber,
grantStream.stageNumber
);
} else {
if (grantStream.amountLeft > DUST_THRESHOLD)
revert PreviousAmountNotFullyWithdrawn();

if (grantStream.amountLeft > 0) {
(bool sent, ) = payable(grantStream.builder).call{
value: grantStream.amountLeft
}("");
if (!sent) revert FailedToSendEther();
}

grantStream.cap = _cap;
grantStream.last = block.timestamp;
grantStream.amountLeft = _cap;
grantStream.stageNumber += 1;

emit MoveGrantToNextStage(
_grantId,
grantStream.builder,
_cap,
grantStream.grantNumber,
grantStream.stageNumber
);
}

grantStream.cap = _cap;
grantStream.last = block.timestamp;
grantStream.amountLeft = _cap;
grantStream.stageNumber += 1;

emit MoveGrantToNextStage(
_grantId,
grantStream.builder,
_cap,
grantStream.grantNumber,
grantStream.stageNumber
);
}

function updateGrant(
Expand Down Expand Up @@ -210,6 +274,18 @@ contract Stream is AccessControl {
emit RemoveOwner(owner, msg.sender);
}

function getGrantIdByBuilderAndGrantNumber(
address _builder,
uint8 _grantNumber
) public view returns (uint256) {
for (uint256 i = 0; i < builderGrants[_builder].length; i++) {
if (builderGrants[_builder][i].grantNumber == _grantNumber) {
return builderGrants[_builder][i].grantId;
}
}
return 0;
}

receive() external payable {}

fallback() external payable {}
Expand Down
Loading