Skip to content

Commit

Permalink
wip: contracts compiling
Browse files Browse the repository at this point in the history
working to get existing tests passing again
  • Loading branch information
topocount committed Jan 13, 2025
1 parent 9a5e41f commit 46f0a78
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 6 deletions.
9 changes: 9 additions & 0 deletions packages/evm/contracts/budgets/ABudget.sol
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ abstract contract ABudget is ACloneable, Receiver, RBAC {
/// @return The amount of assets reconciled
function reconcile(bytes calldata data_) external virtual returns (uint256);

/// @notice Add more funds to an incentive
/// @param data_ The data for the transfer (amount, token address, token ID, etc.)
/// @param boostId The boost containing the incentive
/// @param incentiveId The index of the incentive in the incentives array
/// @dev The boost's protocol fee is is transferred from the budget to BoostCore
function topUp(bytes calldata data_, uint256 boostId, uint256 incentiveId) external payable virtual;

function _transferFungible(address asset_, address to_, uint256 amount_) internal virtual;

/// @inheritdoc ACloneable
function supportsInterface(bytes4 interfaceId) public view virtual override(ACloneable) returns (bool) {
return interfaceId == type(ABudget).interfaceId || super.supportsInterface(interfaceId);
Expand Down
9 changes: 9 additions & 0 deletions packages/evm/contracts/budgets/AManagedBudget.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,20 @@ import {ABudget} from "contracts/budgets/ABudget.sol";
import {ACloneable} from "contracts/shared/ACloneable.sol";
import {AIncentive} from "contracts/incentives/AIncentive.sol";
import {IClaw} from "contracts/shared/IClaw.sol";
import {IReadCore} from "contracts/shared/IReadCore.sol";

/// @title Abstract Managed ABudget
/// @notice A minimal budget implementation that simply holds and distributes tokens (ERC20-like and native)
/// @dev This type of budget supports ETH, ERC20, and ERC1155 assets only
abstract contract AManagedBudget is ABudget, IERC1155Receiver {
IReadCore internal core;

/// @notice set BoostCore interface during initialization
/// @param _core the address of BoostCore the Budget will interact with
function _setCore(IReadCore _core) internal onlyInitializing {
core = _core;
}

/// @notice Get the total amount of ERC1155 assets allocated to the budget, including any that have been distributed
/// @param asset_ The address of the asset
/// @param tokenId_ The ID of the token
Expand Down
3 changes: 0 additions & 3 deletions packages/evm/contracts/budgets/AManagedBudgetWithFees.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ import {IClaw} from "contracts/shared/IClaw.sol";
/// @notice A minimal budget implementation that simply holds and distributes tokens (ERC20-like and native)
/// @dev This type of budget supports ETH, ERC20, and ERC1155 assets only
abstract contract AManagedBudgetWithFees is AManagedBudget {
/// @dev the core contract used to get boost creator info
BoostCore internal core;

/// @dev The management fee percentage (in basis points, i.e., 100 = 1%)
uint256 public managementFee;

Expand Down
39 changes: 38 additions & 1 deletion packages/evm/contracts/budgets/ManagedBudget.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import {ABudget} from "contracts/budgets/ABudget.sol";
import {ACloneable} from "contracts/shared/ACloneable.sol";
import {AIncentive} from "contracts/incentives/AIncentive.sol";
import {IClaw} from "contracts/shared/IClaw.sol";
import {IReadCore} from "contracts/shared/IReadCore.sol";
import {BoostLib} from "contracts/shared/BoostLib.sol";
import {IToppable} from "contracts/shared/IToppable.sol";

/// @title Managed ABudget
/// @notice A minimal budget implementation with RBAC that simply holds and distributes tokens (ERC20-like and native)
Expand All @@ -24,6 +27,7 @@ contract ManagedBudget is AManagedBudget, ReentrancyGuard {
/// @notice The payload for initializing a ManagedBudget
struct InitPayload {
address owner;
IReadCore core;
address[] authorized;
uint256[] roles;
}
Expand All @@ -45,6 +49,7 @@ contract ManagedBudget is AManagedBudget, ReentrancyGuard {
function initialize(bytes calldata data_) public virtual override initializer {
InitPayload memory init_ = abi.decode(data_, (InitPayload));
_initializeOwner(init_.owner);
_setCore(init_.core);
for (uint256 i = 0; i < init_.authorized.length; i++) {
_setRoles(init_.authorized[i], init_.roles[i]);
}
Expand Down Expand Up @@ -171,6 +176,38 @@ contract ManagedBudget is AManagedBudget, ReentrancyGuard {
return true;
}

/// @inheritdoc ABudget
function topUp(bytes calldata data_, uint256 boostId, uint256 incentiveId) external payable virtual override {
Transfer memory request = abi.decode(data_, (Transfer));

BoostLib.Boost memory boost = core.getBoost(boostId);
if (request.target != address(boost.incentives[incentiveId])) revert BoostError.Unauthorized();

if (request.assetType == AssetType.ERC20 || request.assetType == AssetType.ETH) {
FungiblePayload memory payload = abi.decode(request.data, (FungiblePayload));
uint256 feeAmount = payload.amount * boost.protocolFee;
_distributedFungible[request.asset] += feeAmount;
_transferFungible(request.asset, address(core), feeAmount);
if (request.assetType == AssetType.ERC20) {
request.asset.safeApprove(request.target, payload.amount);
} else if (request.assetType == AssetType.ETH) {
if (msg.value != payload.amount) {
revert InvalidAllocation(request.asset, payload.amount);
}
}
IToppable(request.target).topup(payload.amount);
} else if (request.assetType == AssetType.ERC1155) {
ERC1155Payload memory payload = abi.decode(request.data, (ERC1155Payload));

uint256 avail = IERC1155(request.asset).balanceOf(address(this), payload.tokenId);
if (payload.amount > avail) {
revert InsufficientFunds(request.asset, avail, payload.amount);
}

_transferERC1155(request.asset, request.target, payload.tokenId, payload.amount, payload.data);
}
}

/// @inheritdoc ABudget
/// @notice Disburses assets from the budget to multiple recipients
/// @param data_ The packed array of {Transfer} requests
Expand Down Expand Up @@ -246,7 +283,7 @@ contract ManagedBudget is AManagedBudget, ReentrancyGuard {
/// @param amount_ The amount of the asset to transfer
/// @dev This function is used to transfer assets from the budget to a given recipient (typically an incentive contract)
/// @dev If the destination address is the zero address, or the transfer fails for any reason, this function will revert
function _transferFungible(address asset_, address to_, uint256 amount_) internal virtual nonReentrant {
function _transferFungible(address asset_, address to_, uint256 amount_) internal virtual override nonReentrant {
// Increment the total amount of the asset distributed from the budget
if (to_ == address(0)) revert TransferFailed(asset_, to_, amount_);
if (amount_ > available(asset_)) {
Expand Down
4 changes: 3 additions & 1 deletion packages/evm/contracts/budgets/ManagedBudgetWithFees.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {AERC20Incentive} from "contracts/incentives/AERC20Incentive.sol";
import {AERC20VariableIncentive} from "contracts/incentives/AERC20VariableIncentive.sol";
import {AIncentive} from "contracts/incentives/AIncentive.sol";
import {IClaw} from "contracts/shared/IClaw.sol";
import {IReadCore} from "contracts/shared/IReadCore.sol";

/// @title Managed ABudget
/// @notice A minimal budget implementation with RBAC that simply holds and distributes tokens (ERC20-like and native)
Expand Down Expand Up @@ -51,7 +52,8 @@ contract ManagedBudgetWithFees is AManagedBudgetWithFees, ManagedBudget {
}

if (init_.authorized.length == 0) revert("no core contract set");
core = BoostCore(init_.authorized[0]);
address _core = init_.authorized[0];
_setCore(IReadCore(_core));

managementFee = init_.managementFee;
emit ManagementFeeSet(init_.managementFee);
Expand Down
7 changes: 6 additions & 1 deletion packages/evm/contracts/budgets/VestingBudget.sol
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,18 @@ contract VestingBudget is AVestingBudget, ReentrancyGuard {
return 0;
}

/// @inheritdoc ABudget
function topUp(bytes calldata, uint256, uint256) external payable virtual override {
revert BoostError.NotImplemented();
}

/// @notice Transfer assets to the recipient
/// @param asset_ The address of the asset
/// @param to_ The address of the recipient
/// @param amount_ The amount of the asset to transfer
/// @dev This function is used to transfer assets from the budget to a given recipient (typically an incentive contract)
/// @dev If the destination address is the zero address, or the transfer fails for any reason, this function will revert
function _transferFungible(address asset_, address to_, uint256 amount_) internal virtual nonReentrant {
function _transferFungible(address asset_, address to_, uint256 amount_) internal virtual override nonReentrant {
// Increment the total amount of the asset distributed from the budget
if (to_ == address(0)) revert TransferFailed(asset_, to_, amount_);
if (amount_ > available(asset_)) {
Expand Down
11 changes: 11 additions & 0 deletions packages/evm/contracts/shared/IReadCore.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.24;

import {BoostLib} from "contracts/shared/BoostLib.sol";

interface IReadCore {
/// @notice Get a Boost by index
/// @param index The index of the Boost
/// @return The Boost at the specified index
function getBoost(uint256 index) external view returns (BoostLib.Boost memory);
}

0 comments on commit 46f0a78

Please sign in to comment.