Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

This repository contains the tokenomics part of Autonolas onchain-protocol contracts.

A graphical overview is available here:
A graphical overview is available [here](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/docs/flowchart.md).

![architecture](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/docs/On-chain_architecture_v5.png)
For reference purposes only, an older version of the general Autonolas architecture is available [here](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/docs/On-chain_architecture_v5.png).

An overview of the Autonolas tokenomics model is provided [here](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/docs/Autonolas_tokenomics_audit.pdf). A description of the tokenomics contracts related to Olas staking is provided [here](https://github.com/valory-xyz/autonolas-tokenomics/blob/main/docs/StakingSmartContracts.pdf).

Expand Down
2 changes: 1 addition & 1 deletion audits/internal7/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ It zeroid withheldAmount = amount - normalizedAmount;
They need to be given equal rights (OwnerOnly).
To discussion!
```
[]
[x] Fixed
43 changes: 36 additions & 7 deletions contracts/staking/DefaultTargetDispenserL2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ abstract contract DefaultTargetDispenserL2 is IBridgeErrors {

/// @dev Processes the data received from L1.
/// @param data Bytes message data sent from L1.
function _processData(bytes memory data) internal {
function _processData(bytes memory data) internal returns (uint256 totalAmount) {

@kupermind kupermind Jun 23, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since proposed deposited amounts could be further cut off by the StakingFactory verification and result in more withheldAmount-s, let's compute the total amount that is deposited.

// Reentrancy guard
if (_locked > 1) {
revert ReentrancyGuard();
Expand Down Expand Up @@ -198,6 +198,9 @@ abstract contract DefaultTargetDispenserL2 is IBridgeErrors {
emit AmountWithheld(target, targetWithheldAmount);
}

// Update total to-be-deposited amount
totalAmount += amount;
Comment on lines +212 to +213

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add up to the total amount to-be-deposited


uint256 olasBalance = IToken(olas).balanceOf(address(this));
// Check the OLAS balance and the contract being unpaused
if (olasBalance >= amount && localPaused == 1) {
Expand Down Expand Up @@ -329,14 +332,31 @@ abstract contract DefaultTargetDispenserL2 is IBridgeErrors {
/// - Token transfer succeeds, message fails: call this function;
/// - Token transfer fails, message succeeds: re-send OLAS to the contract (separate vote).
/// @param data Bytes message data that was not delivered from L1.
function processDataMaintenance(bytes memory data) external {
/// @param updateWithheldAmount True, if withheld amount update is required.
function processDataMaintenance(bytes memory data, bool updateWithheldAmount) external {
// Check for the contract ownership
if (msg.sender != owner) {
revert OwnerOnly(msg.sender, owner);
}

// Process the data
_processData(data);
// Process the data and calculate deposited amounts
uint256 totalAmount = _processData(data);

// Update withheld amount
if (updateWithheldAmount) {
uint256 localWithheldAmount = withheldAmount;

// Check for overflow
if (totalAmount > localWithheldAmount) {
revert Overflow(totalAmount, localWithheldAmount);
}

// Update withheld amount
localWithheldAmount -= totalAmount;
withheldAmount = localWithheldAmount;

emit WithheldAmountUpdated(localWithheldAmount);
Comment on lines +342 to +369

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calculate total amount being deposited from the balance of this contract. If the balance is used that is recorded in withheldAmount value, then it's the exact amount we need to subtract from withheldAmount.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure why there should be an explicit calculation here, we had this implemented in such a way the DAO needs to take care to add correct numbers. Let's sync tomorrow on this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I approve this, since we discussed and converged on this approach

}

emit StakingMaintenanceDataProcessed(data);
}
Expand All @@ -350,6 +370,11 @@ abstract contract DefaultTargetDispenserL2 is IBridgeErrors {
}
_locked = 2;

// Check for the contract ownership
if (msg.sender != owner) {
revert OwnerOnly(msg.sender, owner);
}
Comment on lines +384 to +387

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding owner check as suggested by the audit.


// Pause check
if (paused == 2) {
revert Paused();
Expand Down Expand Up @@ -401,9 +426,13 @@ abstract contract DefaultTargetDispenserL2 is IBridgeErrors {
_locked = 1;
}

/// @dev Updates withheld amount manually by the DAO in order to account for `processDataMaintenance()` amounts.
/// @notice The amount here must correspond to the exact withheldAmount minus the accumulation of all the previous
/// unique amounts deposited via `processDataMaintenance()` function execution.
/// @dev Updates withheld amount manually by the DAO in order to:
/// [1] Account for not recorded `processDataMaintenance()` amounts;
/// [2] Withheld amount update after balance migration to a new contract.
/// @notice The amount here must correspond to:
/// [1] The exact withheldAmount minus the accumulation of all the previous
/// unique amounts deposited via `processDataMaintenance()` function execution;
/// [2] Final OLAS balance of this contract address.
/// @param amount Updated withheld amount.
function updateWithheldAmountMaintenance(uint256 amount) external {
// Check the contract ownership
Expand Down
60 changes: 60 additions & 0 deletions docs/flowchart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Tokenomics Flowchart

```mermaid
graph TD
%% Tokenomics
subgraph tokenomics [Tokenomics]
Treasury[Treasury]
Dispenser[Dispenser]
DonatorBlacklist[DonatorBlacklist]
Tokenomics[Tokenomics]
Depository[Depository]
GenericBondCalculator[Generic Bond Calculator]
DepositProcessorL1[DepositProcessorL1]
TargetDispenserL2[TargetDispenserL2]
end

subgraph governance [Governance]
OLAS_Token[OLAS Token]
Timelock@{ shape: div-rect, label: "Timelock" }
veOLAS[veOLAS]
end

subgraph registries [Registries]
AgentRegistry[Agent and Component Registry]
ServiceRegistry[Service Registry]
StakingProxy[StakingProxy]
end

LP_Token[LP Token]
Owner([OLAS or LP Token owner])
OwnerAgent[[Component or Agent Owner]]
AnyWallet([Any Wallet or Contract])

AnyWallet-->|depositServiceDonationETH|Treasury
DepositProcessorL1==>|bridge: tokens, message|TargetDispenserL2
Depository-->|calculatePayoutOLAS|GenericBondCalculator
Depository-->|reserveAmountForBondProgram, refundFromBondProgram|Tokenomics
Depository-->|depositTokenForOLAS|Treasury
Depository-->|transfer|OLAS_Token
Dispenser-->|claimOwnerIncentives, claimStakingIncentives|Tokenomics
Dispenser-->|sendMessage|DepositProcessorL1
Dispenser-->|withdrawToAccount|Treasury
GenericBondCalculator-->|getLastIDF|Tokenomics
Owner-->|deposit, redeem|Depository
OwnerAgent-->|claimOwnerRewards|Dispenser
TargetDispenserL2-->|deposit|StakingProxy
Timelock-->|changeOwner|Dispenser
Timelock-->|changeOwner|Tokenomics
Timelock-->|changeOwner, create, close|Depository
Timelock-->|changeOwner, withdraw, enableToken, disableToken|Treasury
Treasury<-->|trackServiceDonation, rebalanceTreasury|Tokenomics
Tokenomics-->|ownerOf, totalSupply|AgentRegistry
Tokenomics-->|getComponentIdsOfServiceId, getAgentIdsOfServiceId|ServiceRegistry
Tokenomics-->|inflationRemainder, totalSupply|OLAS_Token
Tokenomics-->|getVotes|veOLAS
Tokenomics-->|isDonatorBlacklisted|DonatorBlacklist
Treasury-->|drain|ServiceRegistry
Treasury-->|transferFrom|LP_Token
Treasury-->|mint, transfer|OLAS_Token
```
2 changes: 1 addition & 1 deletion scripts/audit_chains/audit_contracts_setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ async function main() {
"mainnet": "scripts/deployment/globals_mainnet.json",
"polygon": "scripts/deployment/staking/polygon/globals_polygon_mainnet.json",
"gnosis": "scripts/deployment/staking/gnosis/globals_gnosis_mainnet.json",
"arbitrumOne": "scripts/deployment/staking/arbitrum/globals_arbitrum_one.json",
"arbitrumOne": "scripts/deployment/staking/arbitrum/globals_arbitrum_mainnet.json",
"optimistic": "scripts/deployment/staking/optimistic/globals_optimistic_mainnet.json",
"base": "scripts/deployment/staking/base/globals_base_mainnet.json",
"celo": "scripts/deployment/staking/celo/globals_celo_mainnet.json",
Expand Down
9 changes: 7 additions & 2 deletions test/StakingBridging.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,11 +416,11 @@ describe("StakingBridging", async () => {
// Process data maintenance by the owner
const payload = ethers.utils.defaultAbiCoder.encode(["address[]", "uint256[]", "bytes32"],
[[stakingTarget], [stakingIncentive * 2], batchHash]);
await arbitrumTargetDispenserL2.processDataMaintenance(payload);
await arbitrumTargetDispenserL2.processDataMaintenance(payload, false);

// Try to do it not from the owner
await expect(
arbitrumTargetDispenserL2.connect(signers[1]).processDataMaintenance("0x")
arbitrumTargetDispenserL2.connect(signers[1]).processDataMaintenance("0x", false)
).to.be.revertedWithCustomError(arbitrumDepositProcessorL1, "OwnerOnly");

// Try to redeem, but there are no funds
Expand Down Expand Up @@ -677,6 +677,11 @@ describe("StakingBridging", async () => {
// Pause the L2 contract
await gnosisTargetDispenserL2.pause();

// Trying to sync withheld tokens not by the owner
await expect(
gnosisTargetDispenserL2.connect(signers[1]).syncWithheldAmount("0x")
).to.be.revertedWithCustomError(gnosisTargetDispenserL2, "OwnerOnly");

// Trying to sync withheld tokens when paused
await expect(
gnosisTargetDispenserL2.syncWithheldAmount("0x")
Expand Down
Loading