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

Update Readme to be more user facing #44

Merged
merged 5 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
110 changes: 110 additions & 0 deletions HARDHAT_DEV_NOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# periodicRewardsInjector

## Intro
The ChildChainGaugeInjector is designed to manage weekly injections of non-bal tokens into Child Chain layer zero gauges based on a predefined keeper using chainlink keepers.
It is meant to be deployed for a single ERC20 reward token, but can manage any number of gauges for that token.

It allows the configured admin to define a list of schedules, and then can be operated by [Chainlink Automation](https://automation.chain.link/).

Methods exists to add new schedules without implicating the already running schedules for a gauge.

The contract also includes functionality for the owner to sweep ERC20 tokens and gas tokens in order to allow the contract to be easily decommissioned should there be any issues or it is no longer needed.


### The Child Chain Gauge runs on weekly epochs:

- Only the defined distributor for a given token may inject rewards.
- The injector uses changes to period_finish on the gauge contract to understand epochs and runs once per epoch as early as possible.
petrovska-petro marked this conversation as resolved.
Show resolved Hide resolved

This contract is intended to operate as the distributor, and has functionality to return distributorship to the owner

### The watchlist

The injector runs using a watch list. The watch list is defined as the tuple of [gaugeAddress, amountPerPeriod, maxPeriods, doNotStartBeforeTimestamp].

For every streamer address, assuming a sufficent token balance, the injector will inject the specified amounts each epoch until it has done so maxPeriods time.

It's possible to add new recipients and configurations without altering or including the old ones (difference to v1).

This list is defined by calling the function `addRecipients(streamerAddresses, amountsPerPeriod, maxPeriods, doNotStartBeforeTimestamp)` on the deployed injector.
Tritium-VLK marked this conversation as resolved.
Show resolved Hide resolved


### Balances
The injector uses ERC20 balances in the injector contract to pay rewards. The upkeeps will not run if there is not enough tokens in the contract to satisfy all currently due injections.

The following usage pattern can be followed to maintain proper balances at all times:

#### When setting schedule
- Transfer the exact amount required for the entire program (all streams, all amounts, all periods)
- Use `addRecipients(streamerAddresses, amountsPerPeriod, maxPeriods, doNotStartBeforeTimestamp)`


#### To abort a schedule midway through or reset
- Use `removeRecipients(recipients)` to one or multiple configurations from the list.
- Use `sweep(token)` to transfer any remaining tokens back to the owner.
- Now you can use the normal process to set a new schedule.

## Deployment and operations

### Dependancies/environment setup
This repo requires hardhat to work.

#### Install
```
npm install
```

Make sure you have npx installed.

```
npm install -g npx
```

#### Add .env
As the injector is integrated and works with existing gauges, the local hardhat environment forks the current Polygon network.
To do that it requires an alchemy key. If you would like to verify your contracts. Please add an API Key for Etherscan for each network.

```
ALCHEMY_KEY=XXX
ETHERSCAN_POLYGON_API_KEY=XXX
PRIVATE_KEY=XXX
```

#### Run tests
```
npx hardhat test
```

#### Adding new networks
You can add new networks in hardhat.config.js under the network tab.

### Deploying an injector
You can either deploy an injector using an already deployed factory in [scripts/deployInjectorWithFactory.js](./scripts/deployInjectorWithFactory.js) or you can deploy the injector on your own [scripts/deployInjector.js](./scripts/deployInjector.js).
You will need to edit it and change the following

- update ADMIN_ADDRESS to point to the address that should admin the injector
- update UPKEEP_CALLER_ADDRESS to point to the address of the chainlink registry keeper who will be calling this address. You can find the Chainlink registry addresses here: [Chainlink Docs](https://docs.chain.link/chainlink-automation/supported-networks/#configurations)
- update TOKEN_ADDRESS to be the token you want to be handled by this contract (note that the Balancer Maxi's must whitelist a token on a gauge before it can be distributed).
- update MIN_WAIT_PERIOD if needed. Default is 6 days. This is the minimum wait period for injections for an address between funding (for security)

Once everything looks good run `npx hardhat run scripts/deployInjectorWithFactory.js --network <network name>` or `npx hardhat run scripts/deployInjector.js --network <network name>`.

This should deploy the contract and return the deployed address. Write it down/check it on etherscan and make sure it is there.

Now verify the contract with `npx hardhat verify --network <network name> <DEPLOYED_ADDRESS>`.

For example `npx hardhat verify --network polygon 0xb7aCdc1Ae11554dfe98aA8791DCEE0F009155D5e`.


#### Accepting Admin
Ownership of the injector is accepted by running acceptOwnership() on the contract from an address that has been granted ownership by the prior owner.
If the owner is an EOA, that address can use etherscan.


#### Registering the upkeep with chainlink
Registering a chainlink upkeep involves paying some money into the chainlink registrar. After that, chainlink will check
the contract each block to see if it is ready to run. When it signifies it is, it will run the specified call data and execute the transfer and notify.
Note that as part of this process some LINK must be paid into the upkeep contract. For sidechains, 3 LINK should usually be enough. These steps assume the specified link is sitting in the multisig where the payload is executed.

The resulting payload should register the upkeep. You can then find your registed upkeep by going to [Chainlink automation dashboard](https://automation.chain.link/arbitrum). Select the chain you deployed on. Then scroll down to recent upkeeps. The name you specified should show up at or near the top of that list. Click on it.
Write down that link and/or the upkeep id. This is the page where you can monitor your link balance. To topup, connect to this dapp with wallet connect and use the top-up action to send in more link. You can also stop the automation and recover deposited and unspent link this way.
141 changes: 54 additions & 87 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,110 +1,77 @@
# periodicRewardsInjector
## Child Chain Gauge Injector V2

## Intro
The ChildChainGaugeInjector is designed to manage weekly injections of non-bal tokens into Child Chain layer zero gauges based on a predefined keeper using chainlink keepers.
It is meant to be deployed for a single ERC20 reward token, but can manage any number of gauges for that token.
The ChildChainGaugeInjectorV2 was built to encapsulate over a year of learnings that came from operating Injector V1 in
the wild. The primary goal of this contract is to provide a more flexible and robust system for scheduling a steady
stream of single token rewards to ChildChainGauges.

It allows the configured admin to define a list of schedules, and then can be operated by [Chainlink Automation](https://automation.chain.link/).
The contract is designed to be a distributor for the ChildChainGauge, and has functionality to return distributorship to
the owner. The owner is also able to sweep all funds.

Methods exists to add new schedules without implicating the already running schedules for a gauge.
In such, this contract is not at all intended to be an onchain promise, but more of a way to automate the distribution
of rewards to the ChildChainGauge. The contract is designed to be operated by a Chainlink Keeper, and the owner is able
to add new schedules without implicating the already running schedules for a gauge. It can easily be used with other
keepers that adapt to the chainlink interface.

The contract also includes functionality for the owner to sweep ERC20 tokens and gas tokens in order to allow the contract to be easily decommissioned should there be any issues or it is no longer needed.
The primary changes in this contract from V1 are:

- Modular configuration, the owner can adjust 1 schedule at a time instead of always overwriting the whole list.
- More safeguards to enable the owner to prevent accidental scheduling mistakes therefore overspending budgets in the
injector.
- maxInjectionAmount: Don't inject more than this in a single tx ever.
- maxInjectionAmountPerPeriod: Do not allow schedule changes that would lead the sum of all active schedules for one
period to exceed this amount.
- maxTotalDue: Do not allow schedule changes that would lead the sum of all active schedules for all remaining
periods to exceed this amount.

### The Child Chain Gauge runs on weekly epochs:
## Deploying an injector using the factory

- Only the defined distributor for a given token may inject rewards.
- The injector uses changes to period_finish on the gauge contract to understand epochs and runs once per epoch as early as possible.
Go to the factory contract on the chain you need on etherscan, and call createInjector with the following parameters:

This contract is intended to operate as the distributor, and has functionality to return distributorship to the owner
| Parameter | Description |
|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| keeperAddress[] | A list of addresses that can trigger a due injection. To start perhaps add your EOA, can include zero address in list to allow anyone to upkeep. |
| minWaitPeriodSeconds | A gauge should only be ready every 7 days. This is a safeguard against something that should never happen, by default set to 6 days or 518400 |
| injectTokenAddress | An Injector runs on a single token. Specify which one here. For multiple tokens use multiple injectors |
| maxInjectionAmount | The maximum amount of tokens that can be injected in a single transaction. Set it to something sane for your token/budget or 0 for no limit. This is to prevent catostrophic scehduling mistakes |
| owner | The owner of the injector. This address can add and remove schedules, and sweep tokens. Can be changed, if you're not sure set to your EOA. |

### The watchlist
## Configuring the global settings of the injector

The injector runs using a watch list. The watch list is defined as the tuple of [gaugeAddress, amountPerPeriod, maxPeriods, doNotStartBeforeTimestamp].
All the settings above can be changed above by clearly marked setter functions in the contract.

For every streamer address, assuming a sufficent token balance, the injector will inject the specified amounts each epoch until it has done so maxPeriods time.
In addition, there are setters for the following global settings, which default to 0 (which means no limit). Note that
the limits below, which apply when setting schedules only will not be respected if a limit lowered, but the schedules
already in place violates it:

It's possible to add new recipients and configurations without altering or including the old ones (difference to v1).
| Parameter | Description |
|--------------------------|----------------------------------------------------------------------------------------------------------------------------------------|
| MaxGlobalAmountPerPeriod | A new program will not allowed to be added, if it would increase the total amount spent of all active programs in the a single period. |
| MaxTotalDue | A new program will not allowed to be added, if it would increase the total amount spent of all active programs in all periods. |

This list is defined by calling the function `addRecipients(streamerAddresses, amountsPerPeriod, maxPeriods, doNotStartBeforeTimestamp)` on the deployed injector.
## Programming the Injector

The injector is intended to be used on Balancer gauges that already have a reward token configured with the injector set
as distributor. The Balancer Maxis can help you configure this.

### Balances
The injector uses ERC20 balances in the injector contract to pay rewards. The upkeeps will not run if there is not enough tokens in the contract to satisfy all currently due injections.
The injector supports adding/overwriting one or more programs to the schedule at a time using add recipients:

The following usage pattern can be followed to maintain proper balances at all times:
| Parameter | Description |
|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| recipients | A list of gauges that should be added or overwritten each with these settings. Note that if a gauge already has a program in scheduled in this injector, it will be overwritten. The new program will run for the total number of rounds specified in maxPeriods below. |
| amountPerPeriod | The amount of tokens that should be injected to the gauge each period. Note that if the injector already has a schedule from one of the listed gauges, it will be overwritten. |
| maxPeriods | The number of periods that the program should run. |
| doNotStartBeforeTimestamp | The earliest time that the program should start. The injector will only fire when it is able to, and there is no currently streaming rewards of that token on the gauge |

#### When setting schedule
- Transfer the exact amount required for the entire program (all streams, all amounts, all periods)
- Use `addRecipients(streamerAddresses, amountsPerPeriod, maxPeriods, doNotStartBeforeTimestamp)`
removeRecipients can be called with a list of recipients to remove their schedules from the injector and abort any
furture scheduled payments.

## What else

#### To abort a schedule midway through or reset
- Use `removeRecipients(recipients)` to one or multiple configurations from the list.
- Use `sweep(token)` to transfer any remaining tokens back to the owner.
- Now you can use the normal process to set a new schedule.
There are good comments, and most of the other functions are pretty self explanitory.

## Deployment and operations
## Still to write

### Dependancies/environment setup
This repo requires hardhat to work.
- Explain a bit more about how balancer gauges work and the basic concept of this injector. Check v1 docs
- Chainlink setup guide

#### Install
```
npm install
```

Make sure you have npx installed.

```
npm install -g npx
```

#### Add .env
As the injector is integrated and works with existing gauges, the local hardhat environment forks the current Polygon network.
To do that it requires an alchemy key. If you would like to verify your contracts. Please add an API Key for Etherscan for each network.

```
ALCHEMY_KEY=XXX
ETHERSCAN_POLYGON_API_KEY=XXX
PRIVATE_KEY=XXX
```

#### Run tests
```
npx hardhat test
```

#### Adding new networks
You can add new networks in hardhat.config.js under the network tab.

### Deploying an injector
You can either deploy an injector using an already deployed factory in [scripts/deployInjectorWithFactory.js](./scripts/deployInjectorWithFactory.js) or you can deploy the injector on your own [scripts/deployInjector.js](./scripts/deployInjector.js).
You will need to edit it and change the following

- update ADMIN_ADDRESS to point to the address that should admin the injector
- update UPKEEP_CALLER_ADDRESS to point to the address of the chainlink registry keeper who will be calling this address. You can find the Chainlink registry addresses here: [Chainlink Docs](https://docs.chain.link/chainlink-automation/supported-networks/#configurations)
- update TOKEN_ADDRESS to be the token you want to be handled by this contract (note that the Balancer Maxi's must whitelist a token on a gauge before it can be distributed).
- update MIN_WAIT_PERIOD if needed. Default is 6 days. This is the minimum wait period for injections for an address between funding (for security)

Once everything looks good run `npx hardhat run scripts/deployInjectorWithFactory.js --network <network name>` or `npx hardhat run scripts/deployInjector.js --network <network name>`.

This should deploy the contract and return the deployed address. Write it down/check it on etherscan and make sure it is there.

Now verify the contract with `npx hardhat verify --network <network name> <DEPLOYED_ADDRESS>`.

For example `npx hardhat verify --network polygon 0xb7aCdc1Ae11554dfe98aA8791DCEE0F009155D5e`.


#### Accepting Admin
Ownership of the injector is accepted by running acceptOwnership() on the contract from an address that has been granted ownership by the prior owner.
If the owner is an EOA, that address can use etherscan.


#### Registering the upkeep with chainlink
Registering a chainlink upkeep involves paying some money into the chainlink registrar. After that, chainlink will check
the contract each block to see if it is ready to run. When it signifies it is, it will run the specified call data and execute the transfer and notify.
Note that as part of this process some LINK must be paid into the upkeep contract. For sidechains, 3 LINK should usually be enough. These steps assume the specified link is sitting in the multisig where the payload is executed.

The resulting payload should register the upkeep. You can then find your registed upkeep by going to [Chainlink automation dashboard](https://automation.chain.link/arbitrum). Select the chain you deployed on. Then scroll down to recent upkeeps. The name you specified should show up at or near the top of that list. Click on it.
Write down that link and/or the upkeep id. This is the page where you can monitor your link balance. To topup, connect to this dapp with wallet connect and use the top-up action to send in more link. You can also stop the automation and recover deposited and unspent link this way.
Loading
Loading