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

Touchup/streamlined arg2 #209

Merged
merged 24 commits into from
Dec 2, 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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bananapus/core",
"version": "0.0.36",
"version": "0.0.37",
"license": "MIT",
"repository": {
"type": "git",
Expand Down
24 changes: 17 additions & 7 deletions src/JBMultiTerminal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {IAllowanceTransfer} from "@uniswap/permit2/src/interfaces/IAllowanceTran
import {IPermit2} from "@uniswap/permit2/src/interfaces/IPermit2.sol";

import {JBPermissioned} from "./abstract/JBPermissioned.sol";
import {IJBCashOutTerminal} from "./interfaces/IJBCashOutTerminal.sol";
import {IJBController} from "./interfaces/IJBController.sol";
import {IJBDirectory} from "./interfaces/IJBDirectory.sol";
import {IJBFeelessAddresses} from "./interfaces/IJBFeelessAddresses.sol";
Expand All @@ -24,7 +25,6 @@ import {IJBPermissioned} from "./interfaces/IJBPermissioned.sol";
import {IJBPermissions} from "./interfaces/IJBPermissions.sol";
import {IJBPermitTerminal} from "./interfaces/IJBPermitTerminal.sol";
import {IJBProjects} from "./interfaces/IJBProjects.sol";
import {IJBCashOutTerminal} from "./interfaces/IJBCashOutTerminal.sol";
import {IJBRulesets} from "./interfaces/IJBRulesets.sol";
import {IJBSplitHook} from "./interfaces/IJBSplitHook.sol";
import {IJBSplits} from "./interfaces/IJBSplits.sol";
Expand All @@ -38,9 +38,9 @@ import {JBRulesetMetadataResolver} from "./libraries/JBRulesetMetadataResolver.s
import {JBAccountingContext} from "./structs/JBAccountingContext.sol";
import {JBAfterPayRecordedContext} from "./structs/JBAfterPayRecordedContext.sol";
import {JBAfterCashOutRecordedContext} from "./structs/JBAfterCashOutRecordedContext.sol";
import {JBCashOutHookSpecification} from "./structs/JBCashOutHookSpecification.sol";
import {JBFee} from "./structs/JBFee.sol";
import {JBPayHookSpecification} from "./structs/JBPayHookSpecification.sol";
import {JBCashOutHookSpecification} from "./structs/JBCashOutHookSpecification.sol";
import {JBRuleset} from "./structs/JBRuleset.sol";
import {JBSingleAllowance} from "./structs/JBSingleAllowance.sol";
import {JBSplit} from "./structs/JBSplit.sol";
Expand Down Expand Up @@ -215,12 +215,15 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
/// @dev This total surplus only includes tokens that the project accepts (as returned by
/// `accountingContextsOf(...)`).
/// @param projectId The ID of the project to get the current total surplus of.
/// @param accountingContexts The accounting contexts to use to calculate the surplus. Pass an empty array to use
/// all of the project's accounting contexts.
/// @param decimals The number of decimals to include in the fixed point returned value.
/// @param currency The currency to express the returned value in terms of.
/// @return The current surplus amount the project has in this terminal, in terms of `currency` and with the
/// specified number of decimals.
function currentSurplusOf(
uint256 projectId,
JBAccountingContext[] memory accountingContexts,
uint256 decimals,
uint256 currency
)
Expand All @@ -232,7 +235,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
return STORE.currentSurplusOf({
terminal: address(this),
projectId: projectId,
accountingContexts: _accountingContextsOf[projectId],
accountingContexts: accountingContexts.length != 0 ? accountingContexts : _accountingContextsOf[projectId],
decimals: decimals,
currency: currency
});
Expand Down Expand Up @@ -340,6 +343,14 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
return PROJECTS.ownerOf(projectId);
}

/// @notice The primary terminal of a project for a token.
/// @param projectId The ID of the project to get the primary terminal of.
/// @param token The token to get the primary terminal of.
/// @return The primary terminal of the project for the token.
function _primaryTerminalOf(uint256 projectId, address token) internal view returns (IJBTerminal) {
return DIRECTORY.primaryTerminalOf({projectId: projectId, token: token});
}

//*********************************************************************//
// ---------------------- external transactions ---------------------- //
//*********************************************************************//
Expand Down Expand Up @@ -564,7 +575,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
// Otherwise, if a project is specified, make a payment to it.
} else if (split.projectId != 0) {
// Get a reference to the terminal being used.
IJBTerminal terminal = DIRECTORY.primaryTerminalOf({projectId: split.projectId, token: token});
IJBTerminal terminal = _primaryTerminalOf({projectId: split.projectId, token: token});

// The project must have a terminal to send funds to.
if (terminal == IJBTerminal(address(0))) {
Expand Down Expand Up @@ -796,7 +807,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
if (startIndex >= numberOfHeldFees) return;

// Keep a reference to the terminal that'll receive the fees.
IJBTerminal feeTerminal = DIRECTORY.primaryTerminalOf({projectId: _FEE_BENEFICIARY_PROJECT_ID, token: token});
IJBTerminal feeTerminal = _primaryTerminalOf({projectId: _FEE_BENEFICIARY_PROJECT_ID, token: token});

// Calculate the number of iterations to perform.
if (startIndex + count > numberOfHeldFees) count = numberOfHeldFees - startIndex;
Expand Down Expand Up @@ -1924,8 +1935,7 @@ contract JBMultiTerminal is JBPermissioned, ERC2771Context, IJBMultiTerminal {
});
} else {
// Get the terminal that'll receive the fee if one wasn't provided.
IJBTerminal feeTerminal =
DIRECTORY.primaryTerminalOf({projectId: _FEE_BENEFICIARY_PROJECT_ID, token: token});
IJBTerminal feeTerminal = _primaryTerminalOf({projectId: _FEE_BENEFICIARY_PROJECT_ID, token: token});

// Process the fee.
_processFee({
Expand Down
42 changes: 22 additions & 20 deletions src/JBTerminalStore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {IJBDirectory} from "./interfaces/IJBDirectory.sol";
import {IJBPrices} from "./interfaces/IJBPrices.sol";
import {IJBRulesetDataHook} from "./interfaces/IJBRulesetDataHook.sol";
import {IJBRulesets} from "./interfaces/IJBRulesets.sol";
import {IJBTerminal} from "./interfaces/IJBTerminal.sol";
import {IJBTerminalStore} from "./interfaces/IJBTerminalStore.sol";
import {JBFixedPointNumber} from "./libraries/JBFixedPointNumber.sol";
import {JBCashOuts} from "./libraries/JBCashOuts.sol";
Expand All @@ -16,9 +17,9 @@ import {JBSurplus} from "./libraries/JBSurplus.sol";
import {JBAccountingContext} from "./structs/JBAccountingContext.sol";
import {JBBeforePayRecordedContext} from "./structs/JBBeforePayRecordedContext.sol";
import {JBBeforeCashOutRecordedContext} from "./structs/JBBeforeCashOutRecordedContext.sol";
import {JBCashOutHookSpecification} from "./structs/JBCashOutHookSpecification.sol";
import {JBCurrencyAmount} from "./structs/JBCurrencyAmount.sol";
import {JBPayHookSpecification} from "./structs/JBPayHookSpecification.sol";
import {JBCashOutHookSpecification} from "./structs/JBCashOutHookSpecification.sol";
import {JBRuleset} from "./structs/JBRuleset.sol";
import {JBTokenAmount} from "./structs/JBTokenAmount.sol";

Expand Down Expand Up @@ -173,24 +174,24 @@ contract JBTerminalStore is IJBTerminalStore {
/// @dev The returned amount in terms of the specified `terminal`'s base currency.
/// @dev The returned amount is represented as a fixed point number with the same amount of decimals as the
/// specified terminal.
/// @param terminal The terminal that would be cashed out from. If `useTotalSurplus` is true, this is ignored.
/// @param projectId The ID of the project whose tokens would be cashed out.
/// @param accountingContexts The accounting contexts of the surplus terminal tokens that would be reclaimed
/// @param cashOutCount The number of tokens that would be cashed out, as a fixed point number with 18 decimals.
/// @param terminals The terminals that would be cashed out from. If this is the zero address, surplus within all
/// the
/// project's terminals are considered.
/// @param accountingContexts The accounting contexts of the surplus terminal tokens that would be reclaimed. Pass
/// an empty array to use all of the project's accounting contexts.
/// @param decimals The number of decimals to include in the resulting fixed point number.
/// @param currency The currency that the resulting number will be in terms of.
/// @param cashOutCount The number of tokens that would be cashed out, as a fixed point number with 18 decimals.
/// @param useTotalSurplus Whether the total surplus should be summed across all of the project's terminals. If
/// false, only the `terminal`'s surplus is used.
/// @return The amount of surplus terminal tokens that would be reclaimed by cashing out `cashOutCount`
/// tokens.
function currentReclaimableSurplusOf(
address terminal,
uint256 projectId,
uint256 cashOutCount,
IJBTerminal[] calldata terminals,
JBAccountingContext[] calldata accountingContexts,
uint256 decimals,
uint256 currency,
uint256 cashOutCount,
bool useTotalSurplus
uint256 currency
)
external
view
Expand All @@ -201,16 +202,15 @@ contract JBTerminalStore is IJBTerminalStore {
JBRuleset memory ruleset = RULESETS.currentOf(projectId);

// Get the current surplus amount.
// If `useTotalSurplus` is true, use the total surplus across all terminals. Otherwise, get the `terminal`'s
// surplus.
uint256 currentSurplus = useTotalSurplus
? JBSurplus.currentSurplusOf({
projectId: projectId,
terminals: DIRECTORY.terminalsOf(projectId),
decimals: decimals,
currency: currency
})
: _surplusFrom(terminal, projectId, accountingContexts, ruleset, decimals, currency);
// If a terminal wasn't provided, use the total surplus across all terminals. Otherwise,
// get the `terminal`'s surplus.
uint256 currentSurplus = JBSurplus.currentSurplusOf({
projectId: projectId,
terminals: terminals.length != 0 ? terminals : DIRECTORY.terminalsOf(projectId),
accountingContexts: accountingContexts,
decimals: decimals,
currency: currency
});

// If there's no surplus, nothing can be reclaimed.
if (currentSurplus == 0) return 0;
Expand Down Expand Up @@ -283,6 +283,7 @@ contract JBTerminalStore is IJBTerminalStore {
return JBSurplus.currentSurplusOf({
projectId: projectId,
terminals: DIRECTORY.terminalsOf(projectId),
accountingContexts: new JBAccountingContext[](0),
decimals: decimals,
currency: currency
});
Expand Down Expand Up @@ -507,6 +508,7 @@ contract JBTerminalStore is IJBTerminalStore {
? JBSurplus.currentSurplusOf({
projectId: projectId,
terminals: DIRECTORY.terminalsOf(projectId),
accountingContexts: new JBAccountingContext[](0),
decimals: accountingContext.decimals,
currency: accountingContext.currency
})
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/IJBMultiTerminal.sol
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IJBCashOutTerminal} from "./IJBCashOutTerminal.sol";
import {IJBDirectory} from "./IJBDirectory.sol";
import {IJBFeeTerminal} from "./IJBFeeTerminal.sol";
import {IJBPayoutTerminal} from "./IJBPayoutTerminal.sol";
import {IJBPermitTerminal} from "./IJBPermitTerminal.sol";
import {IJBProjects} from "./IJBProjects.sol";
import {IJBCashOutTerminal} from "./IJBCashOutTerminal.sol";
import {IJBRulesets} from "./IJBRulesets.sol";
import {IJBSplits} from "./IJBSplits.sol";
import {IJBTerminal} from "./IJBTerminal.sol";
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/IJBRulesetDataHook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

import {JBBeforePayRecordedContext} from "./../structs/JBBeforePayRecordedContext.sol";
import {JBBeforeCashOutRecordedContext} from "./../structs/JBBeforeCashOutRecordedContext.sol";
import {JBPayHookSpecification} from "./../structs/JBPayHookSpecification.sol";
import {JBCashOutHookSpecification} from "./../structs/JBCashOutHookSpecification.sol";
import {JBPayHookSpecification} from "./../structs/JBPayHookSpecification.sol";

/// @notice Data hooks can extend a terminal's core pay/cashout functionality by overriding the weight or memo. They can
/// also specify pay/cashout hooks for the terminal to fulfill, or allow addresses to mint a project's tokens on-demand.
Expand Down
10 changes: 9 additions & 1 deletion src/interfaces/IJBTerminal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,15 @@ interface IJBTerminal is IERC165 {
view
returns (JBAccountingContext memory);
function accountingContextsOf(uint256 projectId) external view returns (JBAccountingContext[] memory);
function currentSurplusOf(uint256 projectId, uint256 decimals, uint256 currency) external view returns (uint256);
function currentSurplusOf(
uint256 projectId,
JBAccountingContext[] memory accountingContexts,
uint256 decimals,
uint256 currency
)
external
view
returns (uint256);

function addAccountingContextsFor(uint256 projectId, JBAccountingContext[] calldata accountingContexts) external;
function addToBalanceOf(
Expand Down
11 changes: 6 additions & 5 deletions src/interfaces/IJBTerminalStore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ pragma solidity ^0.8.0;
import {IJBDirectory} from "./IJBDirectory.sol";
import {IJBPrices} from "./IJBPrices.sol";
import {IJBRulesets} from "./IJBRulesets.sol";
import {IJBTerminal} from "./IJBTerminal.sol";
import {JBAccountingContext} from "./../structs/JBAccountingContext.sol";
import {JBPayHookSpecification} from "./../structs/JBPayHookSpecification.sol";
import {JBCashOutHookSpecification} from "./../structs/JBCashOutHookSpecification.sol";
import {JBPayHookSpecification} from "./../structs/JBPayHookSpecification.sol";
import {JBRuleset} from "./../structs/JBRuleset.sol";
import {JBTokenAmount} from "./../structs/JBTokenAmount.sol";

Expand Down Expand Up @@ -46,14 +47,14 @@ interface IJBTerminalStore {
external
view
returns (uint256);

function currentReclaimableSurplusOf(
address terminal,
uint256 projectId,
uint256 cashOutCount,
IJBTerminal[] calldata terminals,
JBAccountingContext[] calldata accountingContexts,
uint256 decimals,
uint256 currency,
uint256 tokenCount,
bool useTotalSurplus
uint256 currency
)
external
view
Expand Down
10 changes: 9 additions & 1 deletion src/libraries/JBSurplus.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.17;

import {IJBTerminal} from "../interfaces/IJBTerminal.sol";
import {JBAccountingContext} from "../structs/JBAccountingContext.sol";

/// @notice Surplus calculations.
library JBSurplus {
Expand All @@ -10,13 +11,15 @@ library JBSurplus {
/// the project's payout limits.
/// @param projectId The ID of the project to get the total surplus for.
/// @param terminals The terminals to look for surplus within.
/// @param accountingContexts The accounting contexts to use to calculate the surplus.
/// @param decimals The number of decimals that the fixed point surplus result should include.
/// @param currency The currency that the surplus result should be in terms of.
/// @return surplus The total surplus of a project's funds in terms of `currency`, as a fixed point number with the
/// specified number of decimals.
function currentSurplusOf(
uint256 projectId,
IJBTerminal[] memory terminals,
JBAccountingContext[] memory accountingContexts,
uint256 decimals,
uint256 currency
)
Expand All @@ -29,7 +32,12 @@ library JBSurplus {

// Add the current surplus for each terminal.
for (uint256 i; i < numberOfTerminals; i++) {
surplus += terminals[i].currentSurplusOf(projectId, decimals, currency);
surplus += terminals[i].currentSurplusOf({
projectId: projectId,
accountingContexts: accountingContexts,
decimals: decimals,
currency: currency
});
}
}
}
16 changes: 16 additions & 0 deletions test/TestCashOut.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.6;

import /* {*} from */ "./helpers/TestBaseWorkflow.sol";
import {JBCashOuts} from "../src/libraries/JBCashOuts.sol";

// Projects can issue a token, be paid to receieve claimed tokens, burn some of the claimed tokens, cash out the rest
// of
Expand Down Expand Up @@ -119,6 +120,18 @@ contract TestCashOut_Local is TestBaseWorkflow {
// Fuzz 1 to full balance cash out.
_tokenAmountToCashOut = bound(_tokenAmountToCashOut, 1, _beneficiaryTokenBalance);

JBAccountingContext[] memory _tokensContext = new JBAccountingContext[](1);
_tokensContext[0] = JBAccountingContext({
token: JBConstants.NATIVE_TOKEN,
decimals: 18,
currency: uint32(uint160(JBConstants.NATIVE_TOKEN))
});

// Get the expected gross per a different view.
uint256 _grossPerReclaimable = jbTerminalStore().currentReclaimableSurplusOf(
_projectId, _tokenAmountToCashOut, new IJBTerminal[](0), _tokensContext, 18, _tokensContext[0].currency
);

// Test: cash out.
vm.prank(_beneficiary);
uint256 _nativeReclaimAmt = _terminal.cashOutTokensOf({
Expand All @@ -143,6 +156,9 @@ contract TestCashOut_Local is TestBaseWorkflow {
JBConstants.MAX_CASH_OUT_TAX_RATE
);

// Ensure currentReclaimable is correct.
assertEq(_grossCashedOut, _grossPerReclaimable);

// Compute the fee taken.
uint256 _fee = _grossCashedOut - mulDiv(_grossCashedOut, 1_000_000_000, 25_000_000 + 1_000_000_000); // 2.5% fee

Expand Down
Loading
Loading