Giter Club home page Giter Club logo

rbips's Introduction

rbips's People

Contributors

gabririgo avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

gabririgo

rbips's Issues

Prevent pool creation with a rogue token

Summary

Pool creation does not fail when a standard wallet or a smart contract that does not implement decimals() is used as the base token.

Motivation

Pool creation should be allowed only with correct initialization. Otherwise, the name is reserved in the registry and the pool cannot be used. This is relevant for users trying to deploy a pool with the same name and address on multiple chains.

Specification

The call IERC20(initParams.baseToken).decimals() will fail silently if the target address does not implement the method. Therefore, the following part of the code will be skipped, which is the pool initialization. In order to guarantee that the pool is initialized correctly, we have to use a try/catch statement and revert with an error. It is not important to revert with the message error as the pool proxy initializePool() call will fail with POOL_INITIALIZATION_FAILED_ERROR without catching the revert reason for gas optimizations.

The decimals initialization should not make an assertion when the token is base currency as we define 18 decimals. The token assertion should be moved in the try/catch statement and decimals should be defined case by case instead of initially set to 18 and overwritten if different.

Notes

Github issue
Proposed implementation

Refactor safe approve method

Summary

Refactor the safe approve internal method _safeApprove(...args) to avoid the use of low-level calls.

Motivation

A refactoring of the safe approve method has the scope of:

  1. avoiding the use of low-level calls
  2. using a set of more explicit try/catch statements to improve readability
  3. allowing to exclude edge scenarios without having to make implicit/non-linear assumptions
  4. excluding the target token not being a smart contract in an alternative way

Specification

function _safeApprove(address token, address spender, uint256 amount) internal {
  try IToken(token).approve(spender, amount) returns (bool success) {
    assert(success);
  } catch {
    try IToken(token).approve(spender, amount) {

    } catch { revert(); }
  }
}

Rationale

Using a try/catch statement we will be able to have the transaction revert in case the approve call fails silently. While a silent failure does not cause negative side effects to the protocol (the swap transaction would revert with error), we will be able to exclude that the approval target token is a not smart contract or does not implement the method as expected. As a result, we can remove the assertion of the target token being a smart contract, which will result in net gas efficiency (will cost just slightly more in general).

Notes

  • An initial implementation has been proposed here.
  • As Uniswap is launching v4 sometime in Q1 2024, it would be ideal to have this proposal combined with the future proposal to support the new release.

Incentivize GRG network effect through staking

Summary

Incentivize GRG holding by non-pool operators through staking and operators sharing pop rewards.

Motivation

Currently, GRG is a token targeted for token operators, who are required to hold certain amounts in order to unlock premium features. Normal GRG holders do not have a monetary incentive in holding the token unless they want to become an operator.

Specification

Give the pool operator the possibility of creating staking pools, then letting the users stake. Calculate GRG holding for slashing condition calculations based on staked GRGs instead of on pool operators' GRG balance.

Rationale

The proposed model would share the pool operators' pool reward with the pool's stakers. Furthermore, the current GRG-based slashing condition would incentivize network effects pushed from the pool operator's ability to leverage on community-staked tokens in order to meet the theoretical maximum reward ratio.

Notes

This RBIP becomes particularly relevant with the growth in unitary value of GRG, as the emerging pools operators will be able to leverage on the community for maximizing their rewards, while their pools are still small.

Rigoblock V3

Summary

Deploy a lightweight, upgradable V3 protocol.

Motivation

New techniques allow for lightweight, proxy-based smart pools. These can save 95% of the deployment cost. With gas optimizations, operating a pool will not be more gas-expensive than v2 pools. Deterministic deployment allows for same pool address on different chains, allowing for cross-chain pools.

Specification

  • proxy-based deployment
  • deterministic deployment
  • deterministic storage slots
  • split implementation code in mixins for easier auditability
  • better handling of owner vs user actions

Notes

Rigoblock V3 has been deployed.

Decentralize rewards from RigoBlock DAO to RigoBlock applications

Summary

The RigoBlock protocol is designed with a continuous rewards+funding mechanism to the RigoBlock DAO based on a percentage of network fees/rewards. In the proposed RBIP, such rewards go directly to the RigoBlock appplications' DAOs and just as a small fraction of it to the RigoBlock DAO.

Motivation

The current RigoBlock incentives system is without any doubt decentralized. However, the process of the RigoBlock DAO collecting a share of the rewards coming from the RigoBlock token pools and then redistributing/reallocating to the network's contributors poses a conflicts-of-interests risk at the DAO level. While the system is elegantly designed in principle, the empirically observed flaws in other DAOs' decentralized governance highlight how removing the possibility of human abuse of the system might be a superior solution.

Specification

From a practical point of view, this would mean the rewards flow directly to the most successful applications' developers instead of going to the RigoBlock DAO and then being discretionally allocated to the applications' developers.

Proposed implementation 1:
Each RigoBlock application has a unique address associated with it, which is the so-called "Factory" contract. Each factory smart contract, on top, has the address record of its own DAO. A fee/reward split on the RigoBlock protocol gets sent to the applications factory or the application factory's DAO address directly instead of being sent to the RigoBlock DAO and only then being allocated to the applications' developers. The required change will add a marginal cost of gas to the involved transactions, and some protocol extensions will have to be upgraded.

Proposed implementation 2:
Enforce a smart contract rule at the RigoBlock DAO level which would transfer the rewards to the developers based on pre-defined rules. While this requires some work at the governance level, the advantage is that the underlying protocol does not need to be upgraded.

Rationale

To keep the system pure and incorruptible, by reducing reliance on the core, which is today's biggest flaw of allegedly decentralized governance systems.

Governance implementation upgrade

Summary

Upgrade the governance implementation by means of an onchain governance voting to support new features.

Motivation

RPC providers' designs make it impossible to access historical events on some chains. The alleged reason is a degraded performance of nodes, which indicates that the log feature while saving marginal gas cost on the transaction, will constitute a perpetual burden on the dapp unless its own nodes are run. Since we are using the proposal logs to retrieve the proposal description, we could store the description in the proposal struct. In order to make this not too much gas intensive, it could be an ipfs content (even though with ipfs, by design, it is always possible that such description be lost forever). Notice the length of the description string will change between proposals, which is not a big deal as a string will always use its own storage slot with the length of the string. Since this requires a governance implementation upgrade in the governance proxy, it is a good opportunity to implement some other minor fixes.

Specification

  • governance quorum upgrade
    assert past failed proposal not executable by storing quorum in proposal struct
  • add methods in governance
    - add proposer in proposal (will be able to cancel)
    - add cancel method (if proposer does not hold votes)
    - add queue method (should understand if we want this as it's just one extra call)
  • store proposal description in proposal struct
  • upgrade Rigoblock governance implementation
  • L2 ZK governance: do not require staking quorum on L2, run L2s from L1, or from another L2 (this could be split into a separate upgrade for L2s/sidechains, as the timeline is also a bit constrained by the reliability of the L1-L2 messaging bridges.

Rationale

Retrieve proposal description for display even on chains where historical logs are not available, which will also reduce rpc calls on the interface as historical logs for proposals will not need to be queried and kept in sync. The same result will be achieved by implementing a proposals list endpoint and by reading the proposal description from there, which is ok as onchain governance should not experience very frequent proposals.
Currently, a past proposal that has qualified majority but did not reach quorum could theoretically become executable in the future, should the governance decide to lower the quorum below the one reached by such a past proposal. Storing the quorum in the proposal would allow for keeping quorum upgrade implementations as are now, while at the same time guaranteeing that a past failed proposal cannot become executable.
L2 relay-message-base governance would allow to deploy infinitely on each chain. This is especially relevant for L3s. Currently, we are live on 6 networks and the more networks get added, the more tokens need to be locked in governance, which becomes more difficult as (besides rewards tokens that go entirely to network contributors) total supply is finite. This means that, theoretically, we could end in a situation where a governance takeover on an L2 results in the takeover of the staking proxy and the unclaimed rewards (user's tokens are never at risk as they are stored in the non-upgradable GRG Vault contract), which could lead to a cascade of attacks on the other L2s, ending up in an attack on L1. This is an extremely unrealistic scenario in the current deployments as the thresholds are particularly high, but it implies the ability to support new chains is limited. In order to overcome this, managing the L2 governance from L1 would fix the issue. Obviously, the messaging bridge in this context will have dominance, and in a case like the Multichain takedown, the L2 governance would become unusable. It's a low-priority task as there are pros and cons to evaluate.
Adding new methods to governance will bring it on pair with Openzeppelin governance tools.

Notes

DEX aggregator adapter

Summary

Implement a DEX aggregator adapter for allowing pools to swap to source liquidity from multiple sources at the same time.

Motivation

With the fragmentation of onchain liquidity among multiple liquidity sources, while Uniswap still maintains the lion's share of liquidity, it is desirable to allow users to use DEX aggregators, which simplify sourcing the best price.

Specification

  • implement an aggregator adapter (0x and 1inch possible solutions)
  • the adapter should have the same specs as the Uniswap adapter, i.e.
    • set infinite allowance before swap
    • assert target token is governance-whitelisted
    • remove allowance after swap without clearing storage for efficiency.
  • add adapter to authority (requires onchain governance vote)
  • whitelist methods

Subsequently, the swap functionality should be supported on the interface by means of a custom hook and allowing the pool operator to select/deselect aggregator API vs. uniswap API calldata source.

Notes

Support Uniswap V3

Summary

Support Uniswap V3 alongside Uniswap V2 as a liquidity source.

Motivation

As liquidity is migrating from Uniswap V2 to Uniswap V3, it looks appropriate for RigoBlock to supporting the further source of liquidity.

Specification

RigoBlock supports Uniswap V2 through AUniswapV2. A similar adapter should be created and plugged into the RigoBlock protocol in order to pull from Uniswap V3 liquidity. A further adapter is required, as liquidity providing in Uniswap V3 is now managed through NonfungiblePositionManager.sol.

Rationale

Just as with the Uniswap V2 adapter, the Uniswap V3 adapter should mirror all methods implemented in the Uniswap V3 periphery, so that external applications can bundle encoded Uniswap RPC calls to be routed through RigoBlock pools.

Notes

Uniswap V3 periphery contracts
AUniswapV2

Proxy initialization reentrancy fix

Summary

Pool initialization can be reentered.

Motivation

Since during proxy initialization an arbitrary external contract is called, the method could potentially be reentered.

Specification

A non-reentrant modifier should be added to the proxy factory contracts to avoid potential side effects. Since this requires upgrading the factories, we could alternatively apply the modifier to the initialize method in the implementations, where the external contract is called.
The new modifier should use EIP-1553 - transient storage.

Should also check if we want to just use a low-level staticcall when calling an untrusted external contract to read data, as during the initialization.

Transient storage in reentrancy lock modifiers

Summary

Rewrite non-reentrant modifier using new temporary storage opcodes.

Motivation

A non-reentrant modifier writes a boolean (or uint) to storage before execution and clears it after execution ends to prevent reentrancy attacks. This has a cost of 20k - 5k = 15k gas for each modifier.
The new transient storage opcodes introduced by EIP-1153 (going live on 13 March 2024) will allow writing to temporary storage at the same cost as accessing storage (i.e., 100 gas), which will lead to an ~15k gas savings per modifier, which is even more significant for nested modifiers. At the end of the modifier, we must remember to clear temporary storage to prevent unexpected results.

Specification

TBD.

Rationale

Reduce the gas cost of non-reentrant modifiers.

Notes

EIP-1153.

Withdraw pool-owned tokens

Summary

To allow a smart pool holder to burn pool tokens and receive an owned token other than the base token.

Motivation

The feature is very important as it allows a user to withdraw/burn tokens even when a smart pool does not hold enough balance. This prevents abuse from the pool operator, as the holder can choose whether to withdraw an amount of base token or an amount of the smart pool's owned token/contract position.
This feature is conditional to the implementation of RBIP-35.

Specification

A new method is added to the Actions sub-contract

function withdrawWithTokens(uint256 amountIn, uint256 amountOutMin, address contract, bytes32 positionId)

where positionId is an optional parameter, used when a position is withdrawn.
The feature could initially only allow withdrawing owned tokens, and therefore be implemented as

function withdrawWithTokens(uint256 amountIn, uint256 amountOutMin, address tokenAddress)

A holder will have the ability to select a token to withdraw, how many smart pool tokens to burn and a minimum of received tokens. The protocol will evaluate the position through the oracles extension and apply the spread/markup. The last holder will not be applied a markup.
Sufficient tests should be developed, to assert the system cannot be abused. As a general rule, when implementing this feature, the default smart pool holding period in the implementation should be set to 1 day (currently 1 block).

This feature could be implemented without modifications to the interface in the burn method by automatically sending another token if the base token balance is not enough to cover the withdrawal request. In this case, the attack surface is smaller, as any attacker would have to wait for the pool operator to allocate previously received base tokens to manipulate the oracle, which would make the attack ineffective. In this case, the protocol would rank owned assets by ETH value, and start withdrawing from a bigger balance first. This way, an attacker could not select the asset to withdraw, but the system would choose automatically.

As with RBIP-35, we'd prefer this feature be implemented as a library rather than as an extension, so be part of the core instead of being a moving component. To reduce the size of the implementation, the method should be added to the Actions sub-contract, with a direct call (no forwarding to self, which would otherwise execute as view since write calls to the extensions are restricted to the pool owner) to the custom extension. In this context, we would like to prevent a whitelister from updating the selector mapping and restrict this permission to the governance only.

Staking implementation improvements

Summary

Implement some improvements on the staking system.

Motivation

The moveStake method does not allow moving from one pool to another in 1 single transaction, which it should. Requires staking implementation upgrade in the staking proxy. In the current staking system, a pool gets initialized in a specific epoch to participate to incentives, then is finalized at the end of the epoch. This requires two calls and all participating pools must be finalized before the 2nd next epoch. In order to save some gas, the logic could be amended.

Specification

  • query pool data from pool, do not initialize staking pool
  • claim reward during the epoch, without credit reward and later finalize
  • directly move stake from one pool to another (currently requires deactivating and reactivating in 1 batch transaction, will save some gas)

Rationale

Notes

There is reason why the staking system is designed as such, running every 2 weeks makes it manageable from a cost perspective, but worth investigating more.

Maximum bid-offer spread

Summary ( 2-5 Sentences )

Set a maximum bid-offer spread

Motivation

Protocol improvement

Specification

NavVerifier.sol additional check

Prevent governance proxy deploy with rogue strategy contract

Summary

When a proxy is deployed, the input parameters are validated in a strategy contract (which is also an input). The proxy deployment should revert if the strategy contract does not implement the method assertValidInitParams, thus not validating the parameters.

Motivation

While this is an edge case where a user inputs a rogue strategy contract at governance deployment, the end result is that the user won't be able to re-deploy another governance proxy with the same name after realizing the mistake. This is relevant for multi-chain governance proxies. Also, if the user inputs a rogue strategy smart contract address (which must be a smart contract indeed), does not realize the mistake, and transfers ownership of another contract to said governance, no proposal can be made, voted on, and the implementation cannot be upgraded.

Specification

To revert pool initialization without error if IRigoblockGovernanceStrategy.assertValidInitParams(params) does not execute, i.e., also in the case it fails silently (as with a smart contract that does not implement the method). The result can be achieved without assembly or low-level calls by using a try/catch statement.

try IGovernanceStrategy(params.governanceStrategy).assertValidInitParams(params) {

} catch {
   revert StrategyParamsAssertion();
}

Notes

An implementation has been proposed here and includes updates to the ci test suite.

Rigoblock Governance

Summary

Develop the governance to formally own the Rigoblock protocol.

Motivation

One of the goals in the original whitepaper was to have the protocol owned by a decentralized governance.

Specification

The Rigoblock governance will use active staked GRG as voting power. It will be the owner of the Rigoblock protocol smart contracts and each action proposed to the governance will require a qualified majority (2/3) of voting power.

Notes

It has been deployed.

Increase reward factor for drago pool class

This is the suggested template for RigoBlock related issues.

Summary

Increase the reward factor of the Drago pool class.

Motivation

The current ultra-low inflation of the RigoBlock protocol token model is suboptimal for the objective of sufficiently rewarding active participation in the protocol incentives.

Specification

Approve a 10x increase in the reward factor for the Drago pool class in the Inflation.sol governance contract.

Rationale

Give a strong incentive to active participation and higher penalization of passive holding.

Upgrade Proof of Performance

Summary

Proof of Performance should be universal across pools with different base tokens and pool-value agnostic.

Motivation

The Rigoblock V3 protocol uses a new pool registry and in order to support new pools for incentives, the staking implementation requires being upgraded.

Specification

The new staking implementation should use the new registry (which is a deployment constant in the staking implementation, i.e. not upgradable) as a deployment constant.

Notes

It has been implemented.

Cross-chain transactions

Summary

Allow pools to perform cross-chain token bridging transactions.

Motivation

In general, tokens will have different levels of liquidity and different liquidity-providing APRs on different chains, which will open opportunities for pools generating yields. Also, some tokens might be available on a few chains only. Given the possibility of creating arbitrage strategies across chains, it is desirable to be able to transfer tokens from 1 supported chain to another within the same pool.

Specification

A cross-chain bridge adapter should be developed. It should allow interaction with a few selected bridges, or all of them at choice.

Notes

Reduce pop ETH balance slashing factor decay

Summary

Reduce pool ETH balance slashing factor in Proof-of-Performance by 50%.

Motivation

Proof-of-Performance rewards assets and performance of a token pool. The reward is reduced by an exponentially increasing penalization. The current penalization is probably excessive.

Specification

The theoretical maximum can be obtained only if the token pool operator can prove the unitary value of a token pool's token with >80% ETH in the portfolio. Liquidity below 40% already reduces the reward to 20% of the theoretical maximum. A reduction by 50% in the slashing factor would facilitate rewarding more active token pools.

Rationale

While the same rule applies to everyone, hence fair in principle, few pool operators will decide to keep an excessive liquidity in the pool or will want a more long-term allocation to some tokens. While the current system safeguards performance provability, the current thresholds can probably be relaxed by 50% without creating abuse incentives.

Use try/catch statements when interacting with external applications

Summary

Use try/catch statements when interacting with external applications to avoid silent reverts without using assembly.

Motivation

To reduce the use of inline assembly and catch errors in the underlying call.

Specification

TBD.

Notice: Sometimes we read from an external contract with staticcall to ensure we cannot execute write operations. Using a try/catch statement will not always be possible in these instances.

Rationale

TBD.

reduce incentives abuse by using eth as reference.

This is the suggested template for RigoBlock related issues.

Summary

Add additional bindings to proof of performance calculation reward.

Motivation

Proof of performance rewards pools operators based on the value of the pool and, if any, their performance. Given the arbitrary NAV setting by the pool operator in the Drago application, the rewards multiplier for such an application is currently 0. By binding the reward to the Eth in the pool we incentivize the pool operator to maintain sufficient eth in the pool at regular intervals.

Specification

The proof of performance reward is decreased by the ratio between eth in the pool and the pool value. Each such ratio < 1% entails the reward being zero, as a 1% minimum eth liquidity is required to guarantee NAV integrity.

Rationale

Dramatically reduce potential abuse of proof of performance algorithm by setting some additional requirements which make the incentives system more decentralized and less vulnerable.

Notes

ProofOfPerformanceFace.sol needs to be updated as well, in order to include all functions.

Decouple assets and performance components high-watermarking

Summary

Allow proof of performance component to result in positive pop reward even with the pool's unitary value below its high watermark.

Motivation

Once a token pool's unitary value is below its high watermark the resulting pop reward is 0. While this is correct for the performance component so that there is no duplicate reward in this context, the same is not necessarily true for the assets component. The current model could actually create an incentive to excessive risk-taking for getting back above the high watermark.

Specification

Modify Proof-of-Performance calculations as follows:
use an if condition instead of require to reduce gas cost since require in the context not necessarily needed;
if (nav<hwm) -> performanceComponent = 0;

Rationale

Neutralize incentive for excessive risk taking.

Deprecate Token Whitelist

Summary

To deprecate using a governance-controlled token whitelist and allow any token in the smart pools instead.

Motivation

The token whitelist has been introduced to easily allow tracking of pool-owner assets externally, and to limit pool operator abuse when a pool would purchase units of a rogue token, or an interaction with an arbitrary external contract could lead to unintended consequences (i.e., unforeseen reentrancy attacks) on the pool. Uniswap v4 sets a standard for on-chain oracles, which could be used to limit those issues by design. To be able to swap to a rogue token a pool operator would first have to:

  • deploy a rogue token
  • create a Uniswap v4 liquidity pool with a supported oracle hook
  • burn the rogue tokens by feeding into the oracle
  • extend oracle cardinality and execute the minimum number of swaps to be considered valid oracle by Rigoblock

As these actions express rogue behavior, a rogue token cannot be accidentally added to a smart pool. It is pointless restricting the token universe as even with very liquid tokens a pool operator can perform a front-and-back running attack to extract value from an operated smart pool.

Specification

TDB.

Rationale

Allowing universal access to any token, without governance control, using a Rigoblock protocol extension. Removing the need to maintain a token whitelist and storing owned tokens in the smart pools' storages instead. Should cap the maximum number of tokens to 250 and clear owned token mapping when a token is sold completely, to avoid exploding gas costs in mint and burn operations. This is particularly relevant in case a smart pool gets in and out a big number of tokens.

Notes

Uniswap v4 Oracles: link

Represent Pool Proxy as ERC4626

Summary

Pool Proxy inherits ERC4626 public methods and implements them according to Rigoblock specs.

Motivation

ERC2646 provides a standard for vaults that hold tokens. While it is designed for interest-bearing vaults using one token, we could amend the Rigoblock Pool Proxy API to allow easier tracking by blockchain scanners, and possibly stats platforms. Not a top priority as its impact is limited. An interesting advantage is that we could use pre-audited code, therefore reducing the attack surface at the core protocol level.

Specification

TBD.

Rationale

To facilitate exposing smart pools' data on stats platforms, frontends, and blockchain scanners according to broadly accepted standards. To make use of more pre-audited code. the ERC-4626 standard also exposes some methods to withdraw and deposit a specific token in addition to burning and minting with the base token, which would make this RBIP a good complement to RBIP-36.

Notes

ERC-4626 standard
A sample implementation
Openzeppelin's ERC-4626

On ERC-4626 inflation attacks

A project using ERC-4626: website github

Upgrade staking proxy implementation

Summary

Upgrade the staking proxy implementation in the staking system.

Motivation

The Rigoblock V3 protocol uses a new pool registry and in order to support new pools for incentives, the staking implementation requires being upgraded.

Specification

The new staking implementation should use the new registry (which is a deployment constant in the staking implementation, i.e. not upgradable) as a deployment constant.

Notes

It has been implemented.

Automated swap to base token for pool holders

Summary

Upgrade the pool implementation to allow a pool holder to withdraw tokens.

Motivation

When a pool holder sends a burn transaction and the pool does not hold enough base tokens, the transaction will be reverted. In order to prevent this undesired behavior, we want to implement a way for users to exit pools even if the pool does not hold enough liquidity.

Specification

The following two methods should be evaluated and have different implications for their implementation:

  • allow a user to perform an automatic swap of tokens within the pool if the balance is not enough to cover the burn returned amount, for the differential amount (or even the entire amount to save gas). This entails writing a condition that is entitled to directly call the Iniswap adapters (or any other dex adapter) to perform the swap. In this context, the burn transaction will have to include the swap calldata. This method "overwrites" the pool operator's unique permission to swap, but in a scenario where the pool operator is failing to provide enough liquidity.
  • allow a user to burn and receive a token of choice in case liquidity is not enough (or even generally if a user wants to withdraw a different token). This requires an onchain oracle, which is something we really want to avoid using to prevent centralization.

Rationale

Allowing a pool holder to exit a pool even when a pool does not hold enough liquidity in base token.

Notes

Improve self-custody

Summary

The current RBIP improves existing self custody adapter by removing the free tier and adding a flat 1000 GRG pool holding requirement for transferring tokens to self custody and by allowing transferring any ERC20 tokens.

Motivation

Self custody is a feature aimed at facilitating the life of professional market makers, it is therefore unnecessary for traditional traders. Furthermore, it was first introduced as DEXes did not have enough tokens and volume when compared to CEXes. Uniswap, however, offers the ability to swapping almost any token and has volume approaching 1BN$ per day, with ability of becoming AMM LP. Regarding transferring any tokens, must implement safeTransfer to allow safe transfer of any token.

Specification

  • update existing adapter.
  • implement safeTransfer (guarantees data.length of transfer is always 2*32 + 4 bytes).
  • simplified thresholds.

Thresholds

Transfer Amount (ETH) GRG required
[ 0 : 9.8696 [ 98
[ 9.8696 : 31 [ 307
[ 31 : +++ ] 962
Transfer Amount (ERC20) GRG required
any 1000

Develop protocol staking adapter

Summary

Connect the protocol to the GRG staking system.

Motivation

Smart pools that have their own stake require an adapter to communicate with the staking system.

Specification

The adapter should allow the pool to stake to itself.
A "stake" method will be implemented which will batch in one transaction:

  1. Set allowance to GRG transfer proxy
  2. stake and deposit to GRG vault
  3. delegate stake to self.
    An "undelegateStake" and "unstake" methods will be implemented as well to allow the pool to withdraw its own stake.
    A "withdrawDelegatorRewards" method will be developed to allow the pool to withdraw delegator staking rewards while staking.

Notes

It has been implemented.

Store smart pools in registry state

Summary

Store an indexed array of smart pools in the pool registry at pool creation.

Motivation

RPC providers' endpoints do not provide historical logs on some L2s, claiming it would affect node performance. Therefore, in order to display pools on the interface, we provide an endpoint pools.rigoblock.com that returns the pools. Storing the in the registry state will allow retrieving all pools with one single RPC call.

Specification

  • store pools in an indexed mapping
    • mapping(uint256 => Pool) poolsByIndex
    • uint256 poolsLength
    • store new pool at position index in poolsByIndex mapping
  • upgrade registry used by protocol and staking proxy (requires onchain governance vote.

Rationale

The new pools are scraped regularly, but by storing the pools in the registry we could skip logs query and url list update entirely, at an additional 20k gas cost at pool creation, which is acceptable as pool cost creation is less than cost of making 2 onchain swaps.
Storing an indexed mapping and the pools' number allows for avoiding storing a big array, which is going to be expensive to update. Since pools are persistent, we will not find ourselves in a situation where the pool at index is empty, but even if it were it would not cause harm to a call.

Notes

It is still undecided whether this is something worth a registry upgrade.

Autonomous Unitary Value Calculation

Summary

The process of calculating and updating a smart pool's unitary value (used for mint/burn amounts calculations) is now decentralized from the core to the pool operator. The introduction of advanced Geomean Oracles in Uniswap V4 opens the way for implementing a completely autonomous unitary value calculation.

Motivation

The process of updating a pool's unitary value is currently not automated (even though it can be at the smart pool operator's level), not trustless, and not in real-time (as the update requires storing the new value on-chain). Current existing solutions are centralized (i.e., ChainLink and similar), subject to oracle manipulation, and not in real-time (oracles are updated only periodically, i.e., once every 1 hour). The resulting unitary value would be only an estimate and would require further safety measures at the smart pool level to prevent abuse. Furthermore, centralized on-chain Oracle providers do not offer a censorship-resistant system, as they arbitrarily decide what tokens they do support and regularly discontinue support for some tokens.
Uniswap V4, on the other hand, provides a standard for on-chain settlement and a standard for on-chain Oracles. Their Geomean Oracles can be used to estimate unitary value in a precise and accurate way.

Specification

A new extension EUnitaryValue.sol is added to the protocol, which makes a query to the Uniswap V4 Oracle liquidity pool. To find the correct Oracle, the extension will store the Uniswap V4 Oracle hook address, which is the same on all networks, in its bytecode as an immutable. It will then compute the correct token to ETH price by calling function observe(PoolKey calldata key, uint32[] calldata secondsAgos) in two distinct points in time, and then dividing the difference of tickCumulatives by the difference of secondsPerLiquidityCumulativeX128s.
PoolKey is defined as follows:

/// @notice Returns the key for identifying a pool
struct PoolKey {
    /// @notice The lower currency of the pool, sorted numerically
    Currency currency0;
    /// @notice The higher currency of the pool, sorted numerically
    Currency currency1;
    /// @notice The pool swap fee, capped at 1_000_000. The upper 4 bits determine if the hook sets any fees.
    uint24 fee;
    /// @notice Ticks that involve positions must be a multiple of tick spacing
    int24 tickSpacing;
    /// @notice The hooks of the pool
    IHooks hooks;
}

Because in Uniswap V4 only one oracle pool is allowed, the inputs are:

PoolKey (
    currency0: address(0),
    currency1: tokenAddress,
    fee: 0,
    tickSpacing: type(int16).max,
    hooks: Oracle

owned token balances are multiplied by price and summed, then converted to the base token by querying the base token to ETH price.

Pool positions are evaluated from the positions contract, where we either retrieve the aggregate ETH value of positions or extract the individual token components of the positions and sum (subtract in case of debt position) to the pool's token balances.
Notice: when a token balance is sold, the token should be removed from the mapping of tracked tokens. However, if a position owns the same token, we must assert that the token balance can be evaluated when the position is closed. Furthermore, services like DefiLlama and Zapper use the list of owned tokens to evaluate tokens in positions. Technically, it would be ideal to decompose the positions in the underlying tokens and remove a token from the mapping when its balance is null. We also must check what happens in the unrealistic edge scenario where the balance is nill for example due to a positive balance plus an equivalent debt position. In this context, if the token is removed from the mapping, we must ensure that whenever the balance is not null anymore it is correctly tracked.
As a general rule, we should request that no more than 250 tokens and 250 positions be held at a time. While this is not a strict requirement, we want to ensure that the value calculation cost does not explode as a pool buys and sells tokens.

Alternatively, a new library is added to the protocol and inherited by the smart pool implementation. In this case, any further upgrades to the library code will require a pool implementation upgrade (i.e., governance approval + smart pool operator approval).
Ideally we'd want the feature to be implemented as a library to be part of the core instead of the extensions. This will lead to a bigger smart pool implementation contract, which is not huge anyway. While any upgrade to this will require both governance and pool operator approval, it is probably desirable that mint and burn function are not a moving component.

As a general rule, when implementing this feature, the default smart pool holding period in the implementation should be set to 1 day (currently 1 block) unless tests prove the current default is sufficient to prevent oracle manipulation attacks.

This RBIP requires adding a storage slot for owned tokens (plus one for owned positions), as in RBIP-28.

Storage slot for pool owned tokens

Summary

Add a storage slot for pool-owned tokens.

Motivation

Currently owned tokens are retrieved by querying positive balances on the protocol-whitelisted tokens. There is reason to remove the whitelist requirement in the future, in line with the ultimate vision of facilitating earning without using other people’s capital. This would allow a pool to own any token. In that case, it would be helpful to keep track of owned tokens in the pool state.

Specification

  • allocate deterministic storage slot to indexed mapping of owned token addresses
  • allocate deterministic storage slot to number of owned tokens
  • add a token to the mapping when it is first added to the pool
  • remove the token from the mapping when it is removed from the pool (should check whether to leave an empty slot in the mapping or to reorganize the mapping (which could be cost intensive). We can always retrieve the array of tokens by try/catch so that we return the actual length and can have a mapping with empty values).
  • upgrade pool implementation (requires governance onchain voting).

Rationale

Removing the token whitelist would allow a pool to potentially own any token, but it is desirable to have a method that returns all owned tokens.

Notes

NFTs and contract positions (like staking to other applications) could be added to the mapping, but they won't have an address.
Allowing trading any token would allow a pool operator to create a rogue token and empty the pool. This is already possible by routing to a whitelisted token by a route involving a rogue token in the middle, however, doing this would be explicit pool operator rogue behavior.

Use safeApprove in Uniswap adapter

Summary

In order for swapping any tokens, must use safe approve, as to guarantee that data.length is always 3*32 + 4 bytes.

Motivation

A few tokens are problematic when sending transactions from smart contracts. By not encoding the call withing the smart contract, but sending to token as low-level call, the data length binding is guaranteed.

Specification

Implement approve as low-level call instead of token.approve, i.e.:

 tokenAddress.call(abi.encodeWithSelector(SELECTOR, owner, spender, amount))

Introduce max slippage in protocol

Summary

Asset that a swap does not get executed beyond a certain delta from a recent price.

Motivation

If a client sets the wrong uint256 minimumAmountOut parameter in a swap call, the call can be MEV-arbitraged. To prevent the wrong parameter set at an interface level, we can accept a swap execution gas increase and add a check of maximum delta against an oracle price, say 9116 ticks (~2.5x oracle price) just as an example.

Specification

TBD.

Rationale

Improve safety.

Storage slot for sub-accounts

Summary

Allocate a storage slot to sub-accounts.

Motivation

While using a smart contract for interacting with DeFi in a safe way as Rigoblock does is a very effective way of running onchain discretionary token allocation strategies, more complex strategies will require the segregation of tokens. This is particularly relevant for programmatic market makers/traders to limit the risk of their strategies to just portions of their portfolio. Furthermore, this allows keeping the allowance set to one/many DeFi applications / DEXes for maker order strategies, while at the same time having those approvals automatically revoked on the core wallet.

Specification

  • allocating a deterministic storage slot to an indexed mapping of sub-accounts
  • allocating a deterministic storage slot to the number of sub-accounts
  • implement owner methods to activate close approve for each sub-account
  • upgrade pool implementation (requires onchain governance vote)

Notes

This is a very low-priority improvement.

Add governance adapter

Summary

Develop a protocol extension to allow Rigoblock smart pools to interact with the governance.

Motivation

Rigoblock pools own a substantial stake in the staking system, hence votes in the governance. In order for them to be able to participate in governance, a new adapter should be developed, deployed, and added to the protocol.

Specification

Develop a new smart contract AGovernance which allows a smart pool to make a proposal, vote on an existing proposal and execute a successful proposal. The adapter needs to be added to the protocol Authority smart contract. Its methods must be mapped in the same smart contract.

Notes

It has been deployed and added to the protocol.

Upgrade Uniswap adapter

Summary

Upgrade to use uniswap universal router instead of uniswap swap router for swaps.

Motivation

The current swap adapter is affected by 2 bugs: 1) unwrapETH method clashing between swap router and npm contracts and 2) bypass of token whitelist on multi-hop swaps, plus preventing a swap to a whitelisted token when the first pool involves a non-whitelisted token. These fixes require an upgrade of the Uniswap adapter, but since Uniswap has released a universal adapter, it is desirable to use the universal swap router, which simplifies the process of approving swap methods.

Specification

A new Uniswap universal router adapter should be written and deployed. It will support ERC20 tokens only initially. Technically, we want to see if we can use the current uniswap adapter for npm methods, but since the unwrap method calls the uniswap swap router, it will still be affected by the inability to unwrap eth when withdrawing liquidity. In this context, we want to identify whether it is desirable to keep the swap router adapter and the npm adapter separate, but we clearly need to assert that method selectors do not clash.

Notes

RigoBlock/v3-contracts#307

Represent GRG Staking Proxy balances as ERC4626

Summary

Represent GRG staking proxy user balances as ERC4626 to allow easier and better data display by service providers.

Motivation

External applications now cannot see a wallet's staked GRG balance (vault balance plus unclaimed rewards). This requires developing a custom extension to service providers like DefiLlama or Zapper.
ERC4626 provides a standard for vaults, which exposes methods that return the underlying token balance. By implementing this standard, external service providers could display staked GRG in a user's wallet and their $ value. This would be particularly useful for Etherscan display, where it is not possible to develop a custom smart contract position fetcher.

Specification

  • use OpenZeppelin ERC4626 standard;
  • import interface methods;
  • use their implementation;
  • do not implement transfer, transferFrom and approve methods as GRG staked positions are non-transferable.

Notice: assert ERC-4626 inflation attack cannot be executed.

Notes

OpenZeppelin reference code
ERC-4626 inflation attacks

Upgrade to 0x v3 signature verification

Summary

0x v3 passes also the order parameters in the signature verification. The current protocol does not support this feature.

Motivation

In order to comply with 0x v3, the implementation of the new format isValidSignature(...) is required. This allows verifying more conditions within the smart contract.

Specification

Two possibilities:

  • upgrade of the protocol and amendment of isValidSignature function. An upgrade is not required if the aggregate input is accepted by the drago and can be processed within the SigValidator.sol, but in this case SigValidator.sol requires an upgrade.
  • implementation of support for 0x order type "Validator". This requires creating 1 adapter to set the validator contract, plus the validation logic is implemented in the validator contract.

Rationale (if a suggestion is proposed)

Natively support 0x v3.

add slashing condition to pop reward based on GRG pool operator balance

Summary

The proposed improvement slashes the reward based on the amount of GRG tokens a pool operator holds. This has the dual effect of making it exponentially difficult to cheat the system and of creating an incentive for holding/accumulating GRGs.

Motivation

The proposed improvement addresses an edge case where a pool operator can accumulate GRGs by moving ETH from different token pools. By making it exponentially more expensive for the pool operator to accumulate GRGs, we can make the system overall more robust and increase demand for GRG.

Specification

In the ProofOfPerformance.sol contract, once the pop components are calculated, their sum is adjusted by an exponentially decaying factor according to the formula:
y = (1-decay factor)*k^[(1-decay factor)^(n-1)]
and a decay factor of 18%. The exponential curve is approximated by intervals as follows:

% of total supply multiplier
[ 0.05 +++ [ 100%
[ 0.04 0.05 [ 82%
[ 0.03 0.04 [ 20.1%
[ 0.02 0.03 [ 2.9%
[ 0.01 0.02 [ 0.5%
[ 0.00 0.01 [ 0.2%

Revert with error on burn if smart pool does not hold enough base token

Summary

Add a returned error when a burn transaction fails because the pool does not hold enough base tokens to pay expected revenue.

Motivation

Currently, this edge case is handled at a UI level where a user is prevented from burning smart pool tokens when the smart pool does not hold enough base tokens. In this case, the transaction would fail in the underlying token transfer, without a revert error.
By accepting a slightly higher gas cost, since we have to access the underlying token to verify whether the smart pool holds enough balance, we can throw a revert within the burn method. The additional gas cost should only be 100 gas for the balance read, as we need to access the underlying token contract in any case when trying to transfer, plus some computation for calculations.

Specification

Add 1 further assertion here that netRevenue is smaller than new variable poolTokenBalance.

Notes

This RBIP could be made obsolete by either implementing RBIP-36 and partially by EBIP-35.

Allow self-custody

Summary

The current protocol design prevents tokens from being held outside of either the token pools smart contracts or preapproved deposit contracts. The improvement will allow, under certain conditions, for the pool operator to using self-custody solutions.

Motivation

There is a strong demand for cold storage solutions, which are not possible in the current implementation of the protocol. The implementation of self-custody allows for using cold-storage, meeting the traders' requirements. It allows further risk-diversification possibilities, with more complex strategies (arbitrage/hedging/market-making). It provides a bridge with legacy, highly secure service providers and is up to the standards of the industry. It also allows a quick way of implementing integrations with decentralized exchanges, given their short history and continuous breaking changes in their apis.

Specification

  • Implementation into an Drago.sol extension smart contract.
  • The necessary condition is that pool operator holds a minimum GRG amount for certain thresholds
  • threshold levels and amounts required based on pi number.

Rationale (if a suggestion is proposed)

Meet market demand, get in parallel with industry standards, offer more heavy tested storage possibilities, open for off-chain/off-protocol trading by the pools operators.

Thresholds

Transfer Amount (ETH) GRG required
[ 0 : 3.141592 [ 0
[ 3.141592 : 9.8696 [ 98
[ 9.8696 : 31 [ 307
[ 31 : +++ ] 962

Notes

Pi number is an allegory of life. It was chosen as an arbitrary base value to make calculations, reminding the reader of how many complex solutions can be used to approximate the value of pi, with an exponential increase in computation required in relation to precision of the estimate. It is not randomly chosen, as the self custody solution is deemed to be sufficient given the current stage of development and adoption of smart contracts technology.

Deprecate self custody feature

Summary

Remove the unused self-custody feature.

Motivation

The feature was added to provide further flexibility to professional market makers. As the feature never got used and breaks the condition that the pool is the owner of all owned tokens, it does not make sense to keep it. It also adds a point of attack where if the wallet of the pool operator is hacked and the conditions for using the feature are fulfilled, tokens can be transferred out of the pool.

Specification

Remove mapping of self-custody selectors to adapter contract. Remove the self-custody adapter in the authority smart contract.

Rationale

To maintain the integrity of the pool value estimation by the sum of the value of pool-owned tokens.

Notes

Feature code has been removed in this PR

Refactor staking system

Summary

Upgrade the staking proxy implementation in the staking system.

Motivation

The Rigoblock V3 protocol uses a new pool registry and in order to support new pools for incentives, the staking implementation requires being upgraded.

Specification

The new staking implementation should use the new registry (which is a deployment constant in the staking implementation, i.e. not upgradable) as a deployment constant.

Notes

It has been implemented.

Store selectors mapping in pool implementation storage

Summary

Store the selector to adapter address mapping in the pool implementation storage to remove moving parts of the protocol.

Motivation

The biggest downside of implementing an extendable but non-upgradable-extensions flow is that we will very often find ourselves in situations where pools having different implementations will behave differently with external applications. The biggest perk of the current design is that while the core protocol maintains the same APIs across versions and is not expected to change much across versions, the extensions will change as we add and remove support for external applications, therefore having governance-upgradable extensions guarantees all pools use the latest extensions. This is particularly relevant in case of bugs in external applications, where a prompt governance response can safeguard smart pools' assets, with the guarantees of the Rigoblock governance.

Specification

TBD.

Rationale

Storing the mapping in the implementation would save the initial 2100 gas required to warm up the authority contract. It would also remove the extensions as a moving component, thus allowing extending the protocol in a modular and gas-efficient. Lastly, it would allow deprecating the authority contract entirely, thus enabling upgrades only when a pool operator upgrades.

Notes

TBD.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.