Safety protocols

In addition to protection against external attacks, the Geminon protocol contracts incorporate protection against internal attacks, which are attacks that could be carried out by a malicious team member or an attacker who gains control of the protocol keys. All the administrative functions of the GLP whose malicious use may have an impact on the funds held by the contract, are protected with additional security systems.

Parameter changes

The basic parameters of a pool can only be changed by the contract owner. The functions involved have some additional security mechanisms:

Minting and redemption fees (setMintFee() / setRedeemFee())

Allows you to change the base commission that the pool charges users. Malicious access to these functions does not present significant risks, so the only additional security measure is that their maximum value is limited to 0.5%.

Pool weight (setPoolWeight())

Allows you to change the target weight of the pool, which influences the weight ratio which is a component of the token mint and burn ratios. Malicious use of the feature would not have a significant impact. It incorporates several additional checks:

  • The new weight cannot be zero.

  • The weight cannot be increased if migration or deletion of the pool has been requested.

  • The difference between the new objective and the previous one cannot be greater than 5%.

  • The difference between the new target and the current pool weight cannot be greater than 10%.

Infrastructure changes

The infrastructure of a pool is made up of other Geminon or external protocol contracts with which the pool interacts for its operation. Only the owner can access these features, but since these are important features, they all have security timelocks.

The contract change timelock system requires two steps: a first transaction in which the contract address change request is made and the new contract address is specified using the requestAddressChange() function, which starts the counter of the lock time, and a second transaction that verifies that the lock time has elapsed (several days or weeks) and applies the changes. The contract owner can cancel the request at that time. This system guarantees that all changes are public and the characteristics of the new contracts can be observed before they become operational.

Change the price feed (applyPriceFeedChange())

The price feeder is a contract on the Chainlink network that provides the price of the collateral in dollars. This price is used informatively for user transactions and in calculating the relative weights of the pools, which in turn influence the token minting and burning ratios. An unauthorized change would have a moderate impact on the protocol, although it would not put user funds at risk, so an intermediate lock is used.

Protected by a timelock of 7 days.

Change the stablecoin minter (applySCMinterChange())

The stablecoin minter can ask for GEX even GLP tokens if they run out of liquidity to service stablecoin redemptions. Although the redemption function is protected (see below), it is considered that the introduction of a malicious contract in the role of minting stablecoins would present a high risk to the funds of a LPG, so a long block is used.

Protected by a 30-day timelock.

Oracle Change (applyOracleChange())

The protocol oracle (not to be confused with the pool's internal oracle) performs important functions in the management and coordination of the different protocol contracts. It is also involved in certain security checks, as well as providing GEX token prices to other contracts. It is considered a critical function of the protocol, so a long lock is used.

Protected by a 30-day timelock.

Change the lender contract (applyLenderChange())

The protocol was designed with the idea that the loan agreement (still under development) could partially utilize the LPG funds increasing the capital efficiency of the protocol. For this reason, a function was left enabled that would allow these loans to be made. Previously, it is necessary to register the address of the loan contract in the GLP. This function is considered critical to the security of the protocol, so a long lock is used.

Protected by a 30-day timelock.

Migration / removal of the pool

Geminon pools do not use liquidity providers, so all liquidity is owned by the protocol and cannot be withdrawn. However, there could be situations in the future where it is necessary to change the liquidity to a new contract: discovery of vulnerabilities, updates to the protocol, changes in accepted collateral, etc. To cover these eventualities, procedures were designed that allowed collateral to be moved to a new pool (migration) or manually withdrawn (elimination). Both procedures are obviously critical from the perspective of the security of the funds and are therefore protected by the most complex security procedures in the entire protocol. The processes are slightly different for each:

Migration

The migration procedure requires three steps:

  1. Request the pool address change in the oracle contract with the requestAddressChange() function, which initiates a 7-day temporary block.

  2. Request in the pool contract to start the migration procedure with the requestMigration() function. This initiates a 30-day timelock. Additionally, several requirements must be met in order to execute the function:

    • There can be no other pool migration or removal requested, neither from the target pool nor from another pool on the network.

    • The Geminon oracle address cannot be null, the pool must have been connected to the protocol oracle.

    • At least 30 days must have passed since the pool was connected to the oracle.

    • The pool migration request must be registered in the oracle from 7 days before.

    • The target weight of the pool has to be set below 5%.

    • The current weight of the pool's collateral in the network must be less than 5%.

    • Minting of GEX tokens in the pool is paused and cannot be resumed if the deletion request is not cancelled.

  3. Perform pool migration using the migratePool() function. This function performs several additional checks:

    • The pool migration must be requested in the pool for at least 30 days.

    • The pool migration must be requested in the oracle contract.

    • The Geminon oracle address cannot be null, the pool must have been connected to the protocol oracle.

    • At least 60 days must have passed since the pool was connected to the oracle.

    • The target weight of the pool has to be set below 2%.

    • The current weight of the pool's collateral in the network must be less than 2%.

The migration procedure automatically transfers all collateral and GEX tokens contained in the migrated pool to the new pool. In this procedure, the funds are managed internally by the protocol contracts.

Removal

The removal procedure requires three steps, and is more restrictive than the migration procedure in terms of maximum collateral weights required. The rest of the requirements are identical:

  1. Request the pool address change in the oracle contract with the requestRemoveAddress() function, which initiates a 7-day temporary block.

  2. Request in the pool contract to start the migration procedure with the requestRemove() function. This initiates a 30-day timelock. Additionally, several requirements must be met in order to execute the function:

    • There can be no other pool migration or removal requested, neither from the target pool nor from another pool on the network.

    • The Geminon oracle address cannot be null, the pool must have been connected to the protocol oracle.

    • At least 30 days must have passed since the pool was connected to the oracle.

    • The pool migration request must be registered in the oracle from 7 days before.

    • The target weight of the pool has to be set below 5%.

    • The current weight of the pool's collateral in the network must be less than 5%.

    • Minting of GEX tokens in the pool is paused and cannot be resumed if the deletion request is not cancelled.

  3. Perform pool migration using the migratePool() function. This function performs several additional checks:

    • The pool migration must be requested in the pool for at least 30 days.

    • The pool migration must be requested in the oracle contract.

    • The Geminon oracle address cannot be null, the pool must have been connected to the protocol oracle.

    • At least 60 days must have passed since the pool was connected to the oracle.

    • The target weight of the pool has to be set below 1%.

    • The current weight of the pool's collateral in the network must be less than 1%.

Unlike migration, the pool deletion procedure transfers the remaining funds from the pool to the contract owner, who must manually convert them to another type of collateral and reintegrate them into another protocol pool. For this reason, the pool is required to contain less than 1% of all protocol collateral to allow for removal. Despite all security measures, this procedure requires trust and should not be carried out except in extreme circumstances.

Protocol functions

Pause / resume minting (pauseMint() / unpauseMint())

These functions allow you to pause and resume the minting function of the GEX token in the pool. Token redemption cannot be paused. Only the owner can call these functions. The resume cannot be performed if pool migration or removal is requested.

Match Balances (matchBalances())

Allows you to make the internal GEX token and collateral balances of the pool match the balance of the respective tokens in the contract address of the pool. This function is used to recover mistakenly sent tokens directly to the contract. Only the owner can use the function. As an additional security measure to avoid sudden price variations, the function requires that the difference between the internal balance of the pool and the actual number of tokens that the address contains is less than 1%.

Bailout of the stablecoin minter (bailoutMinter())

This feature allows the minter contract to receive GEX tokens from the pool in case it does not have enough liquidity to redeem stablecoin from users. Since it reduces the balance of GEX tokens in the pool, it has the effect of increasing the price of the token. The function can be called manually by the contract owner, or it can be called automatically by the contract minter. For the transaction to not roll back, several conditions must be met:

  • The SC Minter contract must be registered in the pool that receives the request.

  • The Geminon oracle must be registered in the pool for more than 30 days.

  • The SC Minter contract must be registered in the Geminon oracle for more than 7 days.

  • The minter's contract must have less than 5% of the GEX tokens in the pool balance.

  • The maximum amount that the pool can give up is 5% of its GEX token balance.

Collateral loan (lendCollateral())

This feature allows the loan contract to use a portion of the collateral from a pool to deliver an overcollateralized loan. The collateral of the loan must be a valid collateral of the LPG of the network, so that even in case of liquidation of the borrower the collateral can be returned to the pool. The function alone can be called by the loan contract, and requires many conditions:

  • The loan contract must be registered in the pool that receives the request.

  • The Geminon oracle must be registered in the pool for more than 30 days.

  • The loan contract must be registered in the Geminon oracle for more than 7 days.

  • The SC Minter contract must be registered in the pool that receives the request.

  • Migration or removal of the pool may not have been requested.

  • The total cumulative value of the pool's loans cannot be greater than 5% of the total value of the GEX tokens locked in protocol contracts.

  • The maximum amount that the pool can cede is 25% of its collateral balance.

The most restrictive requirement is 5% of the value of GEX tokens locked in other contracts, usually in the stablecoins minter. This requirement will be the one that habitually limits the use of capital from the pools for loans.

Last updated