Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env-modify
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PROD_MNEMONIC=
ETHERSCAN_API_KEY=
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Generated files
build
dist
.idea
.DS_Store

### Emacs ##
*~
Expand Down
2 changes: 1 addition & 1 deletion contracts/UFragments.sol
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ contract UFragments is ERC20Detailed, Ownable {
}

function initialize(address owner_) public override initializer {
ERC20Detailed.initialize("Ampleforth", "AMPL", uint8(DECIMALS));
ERC20Detailed.initialize("Ampleforth Fork", "AMPLFORK", uint8(DECIMALS));
Ownable.initialize(owner_);

rebasePausedDeprecated = false;
Expand Down
5 changes: 3 additions & 2 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ require('./scripts/deploy')
require('./scripts/upgrade')

export default {
defaultNetwork: 'sepolia',
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY,
},
Expand All @@ -30,8 +31,8 @@ export default {
ganache: {
url: 'http://127.0.0.1:8545',
},
goerli: {
url: `https://eth-goerli.g.alchemy.com/v2/${process.env.ALCHEMY_SECRET}`,
sepolia: {
url: `https://ethereum-sepolia.rpc.subquery.network/public`,
accounts: {
mnemonic:
process.env.PROD_MNEMONIC || Wallet.createRandom().mnemonic.phrase,
Expand Down
7 changes: 4 additions & 3 deletions scripts/deploy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { BigNumber, utils, constants } from 'ethers'
import { task } from 'hardhat/config'
import { Interface } from '@ethersproject/abi'
import { getImplementationAddress } from '@openzeppelin/upgrades-core'

import {
Expand Down Expand Up @@ -69,6 +68,7 @@ task('deploy:amplforce:testnet', 'Deploy ampleforth contract suite for testnet')
RATE_REPORT_EXPIRATION_SEC,
RATE_REPORT_DELAY_SEC,
RATE_MIN_PROVIDERS,
1 // TODO - NEEDS ELABORATION
Copy link
Member

Choose a reason for hiding this comment

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

where is this value coming from?

1 sounds for me like the base for CPI/inflation. Without having any further context.

Copy link
Member Author

@Jo-Chris Jo-Chris Jun 17, 2024

Choose a reason for hiding this comment

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

I was just adding it to make it run, as current constructor is defined that way.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hence, the comment

)
console.log('Market oracle to:', marketOracle.address)

Expand All @@ -78,6 +78,7 @@ task('deploy:amplforce:testnet', 'Deploy ampleforth contract suite for testnet')
CPI_REPORT_EXPIRATION_SEC,
CPI_REPORT_DELAY_SEC,
CPI_MIN_PROVIDERS,
1 // TODO - NEEDS ELABORATION
)
console.log('CPI oracle to:', cpiOracle.address)

Expand All @@ -86,8 +87,8 @@ task('deploy:amplforce:testnet', 'Deploy ampleforth contract suite for testnet')
hre,
'UFragmentsPolicy',
deployer,
'initialize(address,address,uint256)',
[owner, ampl.address, INITIAL_CPI.toString()],
Copy link
Member

Choose a reason for hiding this comment

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

why don't we have the initial CPI?

Copy link
Member Author

Choose a reason for hiding this comment

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

needs more investigation; initialize() function only provides two vals right now

'initialize(address,address)',
[owner, ampl.address],
)
const policyImpl = await getImplementationAddress(
hre.ethers.provider,
Expand Down
2 changes: 1 addition & 1 deletion scripts/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export async function verify(
console.log('Verification failed:', e)
console.log('Execute the following')
console.log(
`yarn hardhat run verify:verify --address ${address} --constructor-arguments "${JSON.stringify(
`ryarn hardhat run verify:verify --address ${address} --network sepolia --constructor-arguments "${JSON.stringify(
constructorArguments,
).replace(/"/g, '\\"')}"`,
)
Expand Down
56 changes: 56 additions & 0 deletions test-explanation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Ampleforth Explained

## Contracts


Ampleforth on Mainnet

| Name |Address |
|----------------|-------------------------------|
| ERC-20 Token | 0xD46bA6D942050d489DBd938a2C909A5d5039A161 |
| Supply Policy | 0x1B228a749077b8e307C5856cE62Ef35d96Dca2ea |
| Orchestrator | 0x6fb00a180781e75f87e2b690af0196baa77c7e7c |
| Market Oracle | 0x99c9775e076fdf99388c029550155032ba2d8914 |
| CPI Oracle | 0x2A18bfb505b49AED12F19F271cC1183F98ff4f71 |
| WAMPL | 0xEDB171C18cE90B633DB442f2A6F72874093b49Ef |


#### ERC-20 Contract
The AMPL Contract implements the basic ERC20 interface and has one additional function. If `supplyDelta` is positive, new tokens are added to existing holders. If negative, tokens are removed. Instead of triggering transactions, Ampleforth balances are internally represented by a hidden internal denomination. Fore more information, check the Whitepaper. Rebase function: `rebase(uint256 epoch, int256 supplyDelta)`

#### Supply Policy
The Supply Policy Contract has a single external function, also called `rebase()`, this is not to be confused with the rebase method in the Ampleforth ERC-20 Contract. This `rebase()` method is publicly callable by anyone, but will only execute at most once every 24 hours. Opening this method up, helps to remove us as a necessary central party in the system’s execution. If we fail to call `rebase()` for any reason, others are free to make that call in our place. The rebase() method first queries the Market Oracle to get the current price. If the price is within `priceThreshold` of the target price, no supply policy change is applied. Otherwise, the absolute `supplyDelta` is equal to `(price-target)*totalSupply/target`. For example, if Amples are trading for $1.15, the absolute `totalSupply` increase will be 15%. Next, it applies a “rebase reaction lag” to dampen the supply change. At launch, the reaction lag will be 30 days. Finally, the Ampleforth ERC-20 token is instructed to adjust its supply by the dampened value. Continuing with the example above, the dampened increase would be (15% / 30 days) = 0.5% per day. Due to the unpredictability of when transactions get mined into a block, and because at least 24 hours must pass before a rebase executes, there will always be slightly more than 24 hours between rebases. This means that, even though our rebase time is 24hrs, the rebase call will “drift” slightly over time. Based on our measurements on Ethereum’s Rinkeby testnet, we expect this drift to be about 1 hour per year. So if rebase calls execute at 0:00 UTC time on Jan 1st, they would execute 1:00 UTC a year later. A public countdown timer to the next allowable rebase operation each day is displayed on the Ampleforth Protocol dashboard.

#### Market Oracle
The Market Oracle Contract provides data from the outside world to be used by the Supply Policy Contract. Specifically, it returns the 24-hour volume-weighted Ample Price from exchanges. At launch, oracle will have a trusted whitelist of sources and the price is calculated as the median of the sources.
1. Only whitelisted addresses can provide market data.
2. A market report must exist on-chain publicly for at least 1 hour before it can be used by the supply policy.
3. A market report will expire on-chain if a new report is not provided before 6 hours elapse.


## Ampleforth Fork Deployment

| Component | Address |
|---------------------------|---------------------------------------------------|
| Deployer | 0x08150bAB13edC834FD5b436C9416dC849f410C66 |
| UFragments deployed to | 0x0Df6D221DbB5cabAc86777E9FF6B455a1b2cFAD4 |
| Implementation | 0x86B1c1eD8E4161eAbE7c78D182ef16b9b49c9146 |
| Market oracle to | 0x15a98688AB4274C578d19874D5Cf3B2991d08A31 |
| CPI oracle to | 0x6b06Eb8f79457bC036d1a50e4bDcbeBD7AdD50c4 |
Copy link
Member

Choose a reason for hiding this comment

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

and these oracles are they also part of AMPL and to be forkable with the same license or how does this work?

Copy link
Member

Choose a reason for hiding this comment

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

bc we need to use a custom data feed most likely then

Copy link
Member Author

Choose a reason for hiding this comment

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

is everything within the same repository

Copy link
Member

Choose a reason for hiding this comment

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

ok cool stuff, the better we understand the oracle part the better! Since that will be the part we will need to change!

| UFragmentsPolicy to | 0x75296Fae0b5e3dF0bBd8D29732555E883dFF84cA |
| Implementation | 0xe44b1ab41c56140B195E66DC9F0F2a264885F015 |
| Orchestrator deployed to | 0xAF6e88fF6FFF8E18822ecA4422Cf0013CA241940 |
| Admin/Provider wallet | 0x054cf8e459bE39D29436c77B094DD62b73968DA4 |
| Transferring ownership to | 0x054cf8e459bE39D29436c77B094DD62b73968DA4 |




### How Ampleforth works

- **Equilibrium 1:** Alice has 1 Ample worth $1.
- **Demand Increases:** Alice has 1 Ample worth $2.
- **Equilibrium 2:** Alice has 2 Amples each worth $1.

Whether Alice holds 1 Ample worth $2 or 2 Amples each worth $1, makes no difference in terms of net balance. The difference is the Ampleforth protocol directly propagates price information to each token owner through the count in their token balances. By expanding to and contracting from coin holders directly, a given user’s percent ownership remains fixed unless the user chooses to sell or buy more.