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

feat:oracle proper implementation #227

Merged
merged 30 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6cdd158
change numbers
0xCardinalError Oct 24, 2023
0f2c6cb
change values of oracle params
0xCardinalError Oct 24, 2023
fc3e5a8
apply fixes to tests, partial fixing
0xCardinalError Oct 24, 2023
f00d6e1
apply fixes to tests, partial fixing
0xCardinalError Oct 24, 2023
2662598
fix oracle tests
0xCardinalError Oct 24, 2023
78e2c5d
raise initailChunk value, change price1
0xCardinalError Oct 24, 2023
2ebad53
change how oracle calculate, trying to solve bigNumber problems with …
0xCardinalError Oct 25, 2023
515d53f
use previous
0xCardinalError Oct 25, 2023
096bd8a
fix tooling, remove obsolete code as there is no skipped rounds
0xCardinalError Oct 25, 2023
d9be7ca
latest
0xCardinalError Oct 25, 2023
7835728
refine oracle tests, use bitwise operator for rounding
0xCardinalError Oct 25, 2023
ffde55c
match names and format with tests
0xCardinalError Oct 25, 2023
83e1d87
fix wrong var
0xCardinalError Oct 25, 2023
938a875
upscale and add private price for proper calculations
0xCardinalError Oct 26, 2023
d7c696c
working oracle tests
0xCardinalError Oct 26, 2023
e2d1a76
fix for lints
0xCardinalError Oct 26, 2023
044f094
remove logs
0xCardinalError Oct 26, 2023
b6f792f
add minimalPrice var
0xCardinalError Oct 26, 2023
4633587
add minimalPrice var
0xCardinalError Oct 26, 2023
059285a
change order
0xCardinalError Oct 26, 2023
e3172d1
give better var name
0xCardinalError Oct 26, 2023
da7b833
remove logs
0xCardinalError Oct 26, 2023
9ac2fe1
cleanup
0xCardinalError Oct 26, 2023
fd4e2f0
deploy new Oracle and Redis
0xCardinalError Oct 26, 2023
6132702
update type
0xCardinalError Oct 27, 2023
47d2c8e
fix parentheses
0xCardinalError Oct 27, 2023
6d00ad8
remove 2 variables
0xCardinalError Oct 28, 2023
2fc366f
rename and keep currentPrice as default public
0xCardinalError Oct 28, 2023
0dbea3a
rine tooling, add missing skipped rounds checks
0xCardinalError Oct 29, 2023
a820eca
minimum price fix
0xCardinalError Oct 30, 2023
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: 1 addition & 1 deletion deploy/main/000_deploy_token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const func: DeployFunction = async function ({ deployments, getNamedAccounts })
} else {
log('Using already deployed token at', token.address);
}

log('----------------------------------------------------');
};

Expand Down
96 changes: 52 additions & 44 deletions deployments/pretestnet/PriceOracle.json

Large diffs are not rendered by default.

136 changes: 68 additions & 68 deletions deployments/pretestnet/Redistribution.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ const config: HardhatUserConfig = {
runOnCompile: false,
},
gasReporter: {
enabled: true,
enabled: false,
currency: 'USD',
gasPriceApi: 'https://api.gnosisscan.io/api?module=proxy&action=eth_gasPrice', // https://docs.gnosischain.com/tools/oracles/gas-price
token: 'GNO',
Expand Down
70 changes: 43 additions & 27 deletions src/PriceOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,15 @@ contract PriceOracle is AccessControl {
uint64 public lastAdjustedRound;

// The minimum price allowed
uint32 public minimumPrice = 1024;
uint32 public minimumPriceUpscaled = 24000 << 10; // we upscale it by 2^10

// The priceBase to modulate the price
uint32 public priceBase = 514155;
uint32 public priceBase = 524288;

// The current price is the atomic unit.
uint32 public currentPrice = minimumPrice;
uint64 public currentPriceUpScaled = minimumPriceUpscaled;

// Constants used to modulate the price, see below usage
uint32[9] public increaseRate = [514191, 514182, 514173, 514164, 514155, 514146, 514137, 514128, 514119];
uint32[9] public changeRate = [524324, 524315, 524306, 524297, 524288, 524279, 524270, 524261, 524252];

// Role allowed to update price
bytes32 public immutable PRICE_UPDATER_ROLE;
Expand Down Expand Up @@ -76,18 +75,19 @@ contract PriceOracle is AccessControl {
if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) {
revert CallerNotAdmin();
}
uint32 _currentPrice = _price;
uint32 _minimumPrice = minimumPrice;

//enforce minimum price
if (_currentPrice < _minimumPrice) {
_currentPrice = _minimumPrice;
uint64 _currentPriceUpScaled = _price << 10;
uint64 _minimumPriceUpscaled = minimumPriceUpscaled;

// Enforce minimum price
if (_currentPriceUpScaled < _minimumPriceUpscaled) {
_currentPriceUpScaled = _minimumPriceUpscaled;
}
currentPrice = _currentPrice;
currentPriceUpScaled = _currentPriceUpScaled;

// Price in postagestamp is set at 256 so we need to upcast it
postageStamp.setPrice(uint256(_currentPrice));
emit PriceUpdate(_currentPrice);
postageStamp.setPrice(uint256(currentPrice()));
emit PriceUpdate(currentPrice());
}

function adjustPrice(uint16 redundancy) external {
Expand All @@ -99,49 +99,49 @@ contract PriceOracle is AccessControl {
uint16 usedRedundancy = redundancy;
uint64 currentRoundNumber = currentRound();

// price can only be adjusted once per round
// Price can only be adjusted once per round
if (currentRoundNumber <= lastAdjustedRound) {
revert PriceAlreadyAdjusted();
}
// redundancy may not be zero
// Redundancy may not be zero
if (redundancy == 0) {
revert UnexpectedZero();
}

// enforce maximum considered extra redundancy
// Enforce maximum considered extra redundancy
uint16 maxConsideredRedundancy = targetRedundancy + maxConsideredExtraRedundancy;
if (redundancy > maxConsideredRedundancy) {
usedRedundancy = maxConsideredRedundancy;
}

uint32 _currentPrice = currentPrice;
uint32 _minimumPrice = minimumPrice;
uint64 _currentPriceUpScaled = currentPriceUpScaled;
uint64 _minimumPriceUpscaled = minimumPriceUpscaled;
uint32 _priceBase = priceBase;

// Set the number of rounds that were skipped
uint64 skippedRounds = currentRoundNumber - lastAdjustedRound - 1;

// We first apply the increase/decrease rate for the current round
uint32 ir = increaseRate[usedRedundancy];
_currentPrice = (ir * _currentPrice) / _priceBase;
uint32 _changeRate = changeRate[usedRedundancy];
_currentPriceUpScaled = (_changeRate * _currentPriceUpScaled) / _priceBase;

// If previous rounds were skipped, use MAX price increase for the previous rounds
if (skippedRounds > 0) {
ir = increaseRate[0];
_changeRate = changeRate[0];
for (uint64 i = 0; i < skippedRounds; i++) {
_currentPrice = (ir * _currentPrice) / _priceBase;
_currentPriceUpScaled = (_changeRate * _currentPriceUpScaled) / _priceBase;
}
}

// Enforce minimum price
if (_currentPrice < _minimumPrice) {
_currentPrice = _minimumPrice;
if (_currentPriceUpScaled < _minimumPriceUpscaled) {
_currentPriceUpScaled = _minimumPriceUpscaled;
}
currentPrice = _currentPrice;

postageStamp.setPrice(_currentPrice);
currentPriceUpScaled = _currentPriceUpScaled;
lastAdjustedRound = currentRoundNumber;
emit PriceUpdate(_currentPrice);
postageStamp.setPrice(uint256(currentPrice()));
emit PriceUpdate(currentPrice());
}
}

Expand Down Expand Up @@ -172,4 +172,20 @@ contract PriceOracle is AccessControl {
// it results 4.4724801e+14 years to run this game
return uint64(block.number / uint256(ROUND_LENGTH));
}

/**
* @notice Return the price downscaled
*/
function currentPrice() public view returns (uint32) {
// We downcasted to uint32 and bitshift it by 2^10
return uint32((currentPriceUpScaled) >> 10);
}

/**
* @notice Return the price downscaled
*/
function minimumPrice() public view returns (uint32) {
// We downcasted to uint32 and bitshift it by 2^10
return uint32((minimumPriceUpscaled) >> 10);
}
}
3 changes: 1 addition & 2 deletions src/Redistribution.sol
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,7 @@ contract Redistribution is AccessControl, Pausable {
uint8 private penaltyMultiplierNonRevealed = 2;

// alpha=0.097612 beta=0.0716570 k=16
uint256 private sampleMaxValue =
1284401000000000000000000000000000000000000000000000000000000000000000000;
uint256 private sampleMaxValue = 1284401000000000000000000000000000000000000000000000000000000000000000000;

// The reveal of the winner of the last round.
Reveal public winner;
Expand Down
30 changes: 20 additions & 10 deletions test/PostageStamp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@ const errors = {
};

describe('PostageStamp', function () {
let minimumPrice: number;
describe('when deploying contract', function () {
beforeEach(async function () {
await deployments.fixture();
const priceOracle = await ethers.getContract('PriceOracle');
minimumPrice = await priceOracle.minimumPrice();
});

it('should have minimum bucket depth set to 16', async function () {
Expand Down Expand Up @@ -88,13 +91,18 @@ describe('PostageStamp', function () {
let postageStampStamper: Contract, token: Contract, priceOracle: Contract;
let batch: Batch;
let batchSize: number, transferAmount: number;
const price0 = 1024;
let minimumPrice: number;
let price0: number;
let setPrice0Block: number;

beforeEach(async function () {
await deployments.fixture();
const postageStamp = await ethers.getContract('PostageStamp', deployer);
await postageStamp.setMinimumValidityBlocks(0);
const priceOracle = await ethers.getContract('PriceOracle');
minimumPrice = await priceOracle.minimumPrice();
price0 = minimumPrice;

const priceOracleRole = await read('PostageStamp', 'PRICE_ORACLE_ROLE');
await execute('PostageStamp', { from: deployer }, 'grantRole', priceOracleRole, oracle);
});
Expand Down Expand Up @@ -239,6 +247,7 @@ describe('PostageStamp', function () {
);
const batch1 = computeBatchId(stamper, nonce1);
expect(batch1).equal(await postageStampStamper.firstBatchId());
const blocksElapsed2 = (await getBlockNumber()) - setPrice0Block;

const nonce2 = '0x0000000000000000000000000000000000000000000000000000000000001236';
await postageStampStamper.createBatch(
Expand All @@ -251,15 +260,17 @@ describe('PostageStamp', function () {
);

const batch2 = computeBatchId(stamper, nonce2);
expect(batch1).equal(await postageStampStamper.firstBatchId());
expect(batch2).not.equal(await postageStampStamper.firstBatchId());
expect(batch2).equal(await postageStampStamper.firstBatchId());
expect(batch1).not.equal(await postageStampStamper.firstBatchId());

const stamp = await postageStampStamper.batches(batch2);
const expectedNormalisedBalance2 = initialPaymentPerChunk2 + blocksElapsed2 * price0;

const stamp = await postageStampStamper.batches(batch1);
expect(stamp[0]).to.equal(stamper);
expect(stamp[1]).to.equal(batch.depth);
expect(stamp[2]).to.equal(batch.bucketDepth);
expect(stamp[3]).to.equal(batch.immutable);
expect(stamp[4]).to.equal(expectedNormalisedBalance1);
expect(stamp[4]).to.equal(expectedNormalisedBalance2);
});

it('should transfer the token', async function () {
Expand Down Expand Up @@ -621,15 +632,16 @@ describe('PostageStamp', function () {
let postageStamp: Contract, token: Contract, priceOracle: Contract;
let batch: Batch;
let batchSize: number, transferAmount: number;
const price0 = 1024;
let setPrice0Block: number, buyStampBlock: number;
let topupAmountPerChunk: number;

const initialBatchBlocks = 10;
const topupAmountPerChunk = 1024;

beforeEach(async function () {
postageStamp = await ethers.getContract('PostageStamp', stamper);
token = await ethers.getContract('TestToken', deployer);
priceOracle = await ethers.getContract('PriceOracle', deployer);
topupAmountPerChunk = minimumPrice;

setPrice0Block = await getBlockNumber();
await priceOracle.setPrice(price0);
Expand Down Expand Up @@ -751,7 +763,6 @@ describe('PostageStamp', function () {
let postageStamp: Contract, priceOracle: Contract;
let batch: Batch;
let batchSize: number, transferAmount: number;
const price0 = 1024;
let setPrice0Block: number, buyStampBlock: number;
const initialBatchBlocks = 100;
const newDepth = 18;
Expand Down Expand Up @@ -852,7 +863,7 @@ describe('PostageStamp', function () {
});

it('should compute correct balance if outpayments changed since creation', async function () {
const newPrice = 2048;
const newPrice = 2 * minimumPrice;
await priceOracle.setPrice(newPrice);

const remainingBalanceNextBlock = parseInt(await postageStamp.remainingBalance(batch.id)) - newPrice * 1;
Expand Down Expand Up @@ -1018,7 +1029,6 @@ describe('PostageStamp', function () {
let batch0Size: number, transferAmount0: number;
let batch1Size: number, transferAmount1: number;
let batch2Size: number, transferAmount2: number;
const price0 = 1024;
const initialBatch0Blocks = 10;
const initialBatch1Blocks = 10;
const initialBatch2Blocks = 200;
Expand Down
Loading