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

Upgrade tests #2318

Open
wants to merge 115 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
07293d2
initial second implementation of rebasing to another account
sparrowDom Oct 30, 2024
048b03f
update to core functionality
sparrowDom Oct 30, 2024
36c599e
add gas fucntion
sparrowDom Nov 3, 2024
05d746e
simplify execute
sparrowDom Nov 3, 2024
28d83f9
simplify mint and burn
sparrowDom Nov 3, 2024
45f476b
initial version of Daniel's yield delegation implementation
sparrowDom Nov 7, 2024
9994263
prettier and linter fixes
naddison36 Nov 7, 2024
4c22467
Add slots to OUSD contract to align with existing deployments
naddison36 Nov 7, 2024
f537b63
Generated new OUSD contract diagrams
naddison36 Nov 7, 2024
5743461
Added deploy scripts for OToken upgrades
naddison36 Nov 7, 2024
68ae87e
Generated new OUSD storage diagram
naddison36 Nov 7, 2024
2dbd19e
Merge remote-tracking branch 'origin/master' into sparrowDom/rebaseEl…
naddison36 Nov 7, 2024
58afd12
some minor bug fixes
sparrowDom Nov 7, 2024
17f121c
Prettier and fix spelling in comments
naddison36 Nov 7, 2024
381d13d
Unit test fixes
naddison36 Nov 7, 2024
4ee1b4b
fix initialise function sigature and visibility of functions
sparrowDom Nov 7, 2024
9a29c45
fix some tests
sparrowDom Nov 7, 2024
47e529f
add explanation for the alternativeCreditsPerToken check
sparrowDom Nov 7, 2024
24f099b
prettier
sparrowDom Nov 7, 2024
22c1cf5
reintroduce the original check
sparrowDom Nov 7, 2024
a5269b8
explicitly call rebaseOpt out if the yield delegating account hasn't …
sparrowDom Nov 8, 2024
e64ab17
add one more test
sparrowDom Nov 8, 2024
68d14bd
add Readme of the token contract logic
sparrowDom Nov 8, 2024
ef7c4ab
force account to be rebasing on yield delegation
sparrowDom Nov 8, 2024
90ec917
add explicit whitelist of allowed states when delegating yield
sparrowDom Nov 11, 2024
2c96306
add more defensive checks where isNonRebasingAccount can not mistanki…
sparrowDom Nov 13, 2024
4bf3360
remove increase/decrease allowance
sparrowDom Nov 13, 2024
5cbcf4c
Update docs with invarients
DanielVF Nov 13, 2024
0ab7bc8
Use safecast for any downcasting (#2306)
sparrowDom Nov 13, 2024
2029659
More invarients around outer functions
DanielVF Nov 13, 2024
5951660
Format invarients
DanielVF Nov 13, 2024
8c126c8
further simplify the code when handling different rebase states
sparrowDom Nov 13, 2024
8c2a358
remove nonreentrant modifiers from the toke code as they are not needed
sparrowDom Nov 13, 2024
d7a303f
allow empty conracts to rebaseOptIn without auto migration
sparrowDom Nov 15, 2024
2b3189f
Transfer unit tests for new token implementation (#2310)
sparrowDom Nov 15, 2024
aa53ea3
More invarients
DanielVF Nov 13, 2024
727e4e9
Correct total supply docs
DanielVF Nov 15, 2024
77d69f1
Transfer unit tests for new token implementation (#2310)
sparrowDom Nov 15, 2024
0cfa352
fix test
sparrowDom Nov 15, 2024
31c8078
remove redundant state checks
sparrowDom Nov 15, 2024
511dcaa
remove overwriting the same value to alternativeCreditsPerToken
sparrowDom Nov 15, 2024
5f63650
add non zero checks in delegation functions
sparrowDom Nov 15, 2024
4e327fa
correct error
sparrowDom Nov 15, 2024
9e9c726
correct some contract view modifiers
sparrowDom Nov 15, 2024
6e1b63e
add a readable error message when allowance is exceeded
sparrowDom Nov 15, 2024
659f294
reducing 2 functions to 1
sparrowDom Nov 15, 2024
f261756
deprecate isUpgraded
sparrowDom Nov 18, 2024
54b7ebe
rename totalSupply
sparrowDom Nov 18, 2024
2b31fd6
improve initialisation checks
sparrowDom Nov 18, 2024
108f0eb
remove gas optimisation that would also allow for errorneously large …
sparrowDom Nov 18, 2024
24865d0
remove underflow checks
sparrowDom Nov 18, 2024
b728d2e
simplify code check for rebaseOptIn and add a test for it
sparrowDom Nov 18, 2024
ba625f0
remove comments
sparrowDom Nov 18, 2024
f8280d1
move the balance and credits query above the rebaseState changes
sparrowDom Nov 18, 2024
ab460b8
use _adjustGlobals function to adjust globals in yield delegation
sparrowDom Nov 18, 2024
c94cd5f
futher simplify the undelegateYield function
sparrowDom Nov 18, 2024
c3684a5
unify the variable names
sparrowDom Nov 18, 2024
9cc74cc
add comment
sparrowDom Nov 18, 2024
2987362
a couple of more places to utilise the _adjustGlobals function
sparrowDom Nov 18, 2024
6b02387
no need this being a separate variable
sparrowDom Nov 18, 2024
6556835
undo bug introduction
sparrowDom Nov 18, 2024
56b11e2
wrong use of msg.sender bug fix
sparrowDom Nov 18, 2024
bbb3f45
function doesn't need to return any values
sparrowDom Nov 19, 2024
e949129
simplify
sparrowDom Nov 19, 2024
a1d3cdc
improve syntax
sparrowDom Nov 19, 2024
504a421
add events for yield delegation
sparrowDom Nov 19, 2024
546695f
remove var init
sparrowDom Nov 19, 2024
62c1045
fix deploy file
sparrowDom Nov 19, 2024
fd45920
add tests to catch possible incorrect rebaseOptIn / rebaseOptOut attr…
sparrowDom Nov 20, 2024
3d03c7b
simplify changeSupply code
sparrowDom Nov 20, 2024
fbb11a9
add storage slot gap
sparrowDom Nov 20, 2024
6d5c745
Comments update
DanielVF Nov 20, 2024
9ded07a
Comments spelling update
DanielVF Nov 20, 2024
2c6bdc2
correct comments
sparrowDom Nov 20, 2024
9436e7c
Merge remote-tracking branch 'origin/sparrowDom/rebaseElsewhere_v2' i…
sparrowDom Nov 20, 2024
f1939db
unify variable names
sparrowDom Nov 20, 2024
57c8733
make credits calculation based of off balance for higher accuracy (in…
sparrowDom Nov 20, 2024
dc803f2
minor gas optimisation
sparrowDom Nov 20, 2024
4893186
correct storage slot amount so it totals to 200
sparrowDom Nov 21, 2024
09bde1b
Improve rebasing supply accuracy V2 (#2314)
sparrowDom Nov 21, 2024
ae51bbd
gas optimisation
sparrowDom Nov 21, 2024
f03deb3
better naming
sparrowDom Nov 21, 2024
db2044a
add a test where multiple rebaseOptIn/OptOut calls do not result in i…
sparrowDom Nov 22, 2024
4495130
add a check for zero address with governanceRebaseOptIn tx
sparrowDom Nov 23, 2024
53db807
Update on rebasing
DanielVF Nov 25, 2024
948014c
add a check for zero address with governanceRebaseOptIn tx
sparrowDom Nov 23, 2024
7d7055c
Merge remote-tracking branch 'origin/sparrowDom/rebaseElsewhere_v2' i…
sparrowDom Nov 25, 2024
01b49a3
make an exception for balance exact non rebasing accounts (StdNonReba…
sparrowDom Nov 25, 2024
e355f3d
add test for the 1e27 cpt token exception
sparrowDom Nov 25, 2024
7636c99
add a test to for creditsBalanceOf and creditsBalanceOfHighres
sparrowDom Nov 25, 2024
da68531
add nonRebasingCreditsPerToken to the test
sparrowDom Nov 25, 2024
1b9d1e3
add auto migration test and revert test for rebaseOptOut
sparrowDom Nov 25, 2024
34021fb
prettier
sparrowDom Nov 26, 2024
57cccba
add tests for missing requires in yield delegation
sparrowDom Nov 26, 2024
24bf72a
simplify code
sparrowDom Nov 26, 2024
f1b5290
revert to the previous implementation of the deprecated function
sparrowDom Nov 26, 2024
b22e9e4
Add the script
shahthepro Nov 18, 2024
03f797f
minor change
sparrowDom Nov 26, 2024
7ae4fbc
finish the balance extraction script
sparrowDom Nov 28, 2024
20f1bd1
add OETH upgrade deployment file
sparrowDom Nov 28, 2024
cba9337
Merge remote-tracking branch 'origin/sparrowDom/rebaseElsewhere_v2' i…
sparrowDom Nov 28, 2024
ec052c3
add basic upgrade tests
sparrowDom Nov 29, 2024
7b76cb8
change license to Business Source License
sparrowDom Nov 29, 2024
dbb3434
prettier
sparrowDom Nov 29, 2024
93545c3
on changeSupply round up in the favour of the protocol
sparrowDom Nov 29, 2024
5b7e2a7
Merge remote-tracking branch 'origin/sparrowDom/rebaseElsewhere_v2' i…
sparrowDom Nov 30, 2024
f9174e5
add Readme on how to perform upgrade tests
sparrowDom Dec 1, 2024
dc854bc
round down when calculating credits from balances
sparrowDom Dec 1, 2024
4d13c09
make fetching squid balances in paralel
sparrowDom Dec 2, 2024
7225364
remove unneeded await
sparrowDom Dec 2, 2024
63ee2ba
Revert "round down when calculating credits from balances"
sparrowDom Dec 2, 2024
6d95c43
add transfers to upgrade tests
sparrowDom Dec 3, 2024
6592a20
Merge remote-tracking branch 'origin/sparrowDom/rebaseElsewhere_v2' i…
sparrowDom Dec 3, 2024
83b05fc
Merge remote-tracking branch 'origin/master' into sparrowDom/upgrade_…
sparrowDom Jan 28, 2025
f04f022
use the more appropriate table
sparrowDom Jan 30, 2025
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
34 changes: 34 additions & 0 deletions contracts/deploy/mainnet/109_ousd_upgrade.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const { deploymentWithGovernanceProposal } = require("../../utils/deploy");

module.exports = deploymentWithGovernanceProposal(
{
deployName: "109_ousd_upgrade",
forceDeploy: false,
forceSkip: false,
reduceQueueTime: true,
deployerIsProposer: false,
proposalId: "",
},
async ({ deployWithConfirmation }) => {
// Deployer Actions
// ----------------

// 1. Deploy new OUSD implementation without storage slot checks
const dOUSD = await deployWithConfirmation("OUSD", [], "OUSD", true);
const cOUSDProxy = await ethers.getContract("OUSDProxy");

// Governance Actions
// ----------------
return {
name: "Upgrade OUSD token contract",
actions: [
// 1. Upgrade the OUSD proxy to the new implementation
{
contract: cOUSDProxy,
signature: "upgradeTo(address)",
args: [dOUSD.address],
},
],
};
}
);
38 changes: 38 additions & 0 deletions contracts/deploy/mainnet/110_oeth_upgrade.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const { deploymentWithGovernanceProposal } = require("../../utils/deploy");

module.exports = deploymentWithGovernanceProposal(
{
deployName: "110_oeth_upgrade",
forceDeploy: false,
forceSkip: false,
reduceQueueTime: true,
deployerIsProposer: false,
proposalId: "",
},
async ({ deployWithConfirmation }) => {
// Deployer Actions
// ----------------
const cOETHProxy = await ethers.getContract("OETHProxy");

// Deploy new version of OETH contract
const dOETHImpl = await deployWithConfirmation("OETH", []);

// Governance Actions
// ----------------
return {
name: "Upgrade OETH token contract\n\
\n\
This upgrade enabled yield delegation controlled by xOGN governance \n\
\n\
",
actions: [
// Upgrade the OETH token proxy contract to the new implementation
{
contract: cOETHProxy,
signature: "upgradeTo(address)",
args: [dOETHImpl.address],
},
],
};
}
);
2 changes: 2 additions & 0 deletions contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"echidna": "yarn run clean && rm -rf echidna-corpus && echidna . --contract Echidna --config echidna-config.yaml",
"compute-merkle-proofs-local": "HARDHAT_NETWORK=localhost node scripts/staking/airDrop.js reimbursements.csv scripts/staking/merkleProofedAccountsToBeCompensated.json && cp scripts/staking/merkleProofedAccountsToBeCompensated.json ../dapp/src/constants/merkleProofedAccountsToBeCompensated.json",
"compute-merkle-proofs-mainnet": "HARDHAT_NETWORK=mainnet node scripts/staking/airDrop.js reimbursements.csv scripts/staking/merkleProofedAccountsToBeCompensated.json && cp scripts/staking/merkleProofedAccountsToBeCompensated.json ../dapp/src/constants/merkleProofedAccountsToBeCompensated.json",
"fetch-pre-upgrade": "node scripts/yield-delegation/fetchAllAddresses.js",
"slither": "yarn run clean && slither . --config-file slither.config.json",
"slither:triage": "yarn run clean && slither . --triage --config-file slither.config.json",
"clean": "rm -rf build crytic-export artifacts cache deployments/local*",
Expand Down Expand Up @@ -94,6 +95,7 @@
"lodash": "^4.17.21",
"mocha": "^10.2.0",
"papaparse": "^5.3.1",
"postgres": "^3.4.5",
"prettier": "^2.3.2",
"prettier-plugin-solidity": "1.0.0-beta.17",
"rollup": "^4.18.0",
Expand Down
66 changes: 66 additions & 0 deletions contracts/scripts/yield-delegation/fetchAllAddresses.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
require("dotenv").config();
const postgres = require("postgres");
const ethers = require("ethers");
const fs = require('fs');

const sql = postgres(process.env.SQUID_DB_URL);

const OETH_ADDRESS = "0x856c4efb76c1d1ae02e20ceb03a2a6a08b0b8dc3";
const OUSD_ADDRESS = "0x2a8e1e676ec238d8a992307b495b45b3feaa5e86";
const SUPER_OETH_ADDRESS = "0xdbfefd2e8460a6ee4955a68582f85708baea60a3";

async function getAddressesAndBalances(oTokenAddress, maxBlockNumber, csvFileName) {
const batchSize = 5000;
let offset = 0;
const allAddresses = [];

const blockSmallerOrEq = blockNumber => sql` AND block_number <= ${ blockNumber }`
while (true) {
console.log(`Running query batchSize: ${batchSize}, offset: ${offset}`);
const batch = await sql`
SELECT b.account, b.balance FROM (
SELECT DISTINCT ON (account) account, balance
FROM erc20_holder
WHERE address = ${oTokenAddress}
ORDER BY account
LIMIT ${batchSize}
OFFSET ${offset}
) b WHERE balance > 0
`;

if (batch.length === 0) break;

batch.forEach((row) => {
allAddresses.push([row.account, row.balance].join(','))
//console.log(`account: ${row.account} balance: ${row.balance} block_number: ${row.block_number}`)
});
offset += batchSize;

console.log(`Processed ${allAddresses.length} unique addresses so far...`);
}

console.log(`Total ${oTokenAddress == OETH_ADDRESS ? "OETH" : "OUSD"} unique addresses found: ${allAddresses.length}`);

// // Write addresses to CSV
const csvContent = allAddresses.join('\n');
fs.writeFileSync(csvFileName, csvContent);
console.log(`Addresses and balances written to ${csvFileName}`);

return allAddresses;
}

async function main() {
const oethAddresses = await getAddressesAndBalances(OETH_ADDRESS, 0, 'oethBalances.csv');
const ousdAddresses = await getAddressesAndBalances(OUSD_ADDRESS, 0, 'ousdBalances.csv');
const soethAddresses = await getAddressesAndBalances(SUPER_OETH_ADDRESS, 0, 'soethBalances.csv');
}

main()
.then(() => {
console.log("Done!");
process.exit(0);
})
.catch((err) => {
console.error(err);
process.exit(1);
});
103 changes: 103 additions & 0 deletions contracts/test/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ const { parseUnits, formatUnits, keccak256, toUtf8Bytes } =
const { BigNumber } = require("ethers");

const addresses = require("../utils/addresses");
const { impersonateAndFund } = require("../utils/signers");
const { decimalsFor, units } = require("../utils/units");
const fs = require('fs');

/**
* Checks if the actual value is approximately equal to the expected value
Expand Down Expand Up @@ -756,6 +758,104 @@ async function differenceInStrategyBalance(
return returnVals;
}

function* chunks(arr, n) {
for (let i = 0; i < arr.length; i += n) {
yield arr.slice(i, i + n);
}
}

async function addActualBalancesToSquidData(squidDataCsvFile, outputFileName, tokenContract) {
// CSV file in format account, balance, blockNumber (balance from squid)
const data = fs.readFileSync(squidDataCsvFile, "utf8").split('\n');
const combinedData = [];
const batchSize = 50;
const chunkedData = [...chunks(data, batchSize)];

for (let i = 0; i < chunkedData.length; i++) {
const data = chunkedData[i];
const balanceOfPromises = [];

for (let j = 0; j < data.length; j++) {
const [account,,] = data[j].split(',');
balanceOfPromises.push(tokenContract.balanceOf(account));
}

await Promise.all(balanceOfPromises).then(values => {
for(let j = 0; j < values.length; j++) {
const [account, balance,] = data[j].split(',')
const onChainBalance = values[j].toString(10)
combinedData.push([account, balance, onChainBalance].join(','))
}
});
console.log(`Inspected ${(i+1) * batchSize} accounts`);
}
const csvContent = combinedData.join('\n');
fs.writeFileSync(outputFileName, csvContent);
}

async function testTransfersOnTokenContract(balancesFile, upgradedTokenContract) {
// CSV file in format account, squidBalance, onChainBalance
const data = fs.readFileSync(balancesFile, "utf8").split('\n');
let transferBalanceMissmatches = 0;
for (let i = 1; i < data.length; i++) {
const [accountPrevious,,] = data[i-1].split(',');
const [account,,] = data[i].split(',');

const balanceSender = await upgradedTokenContract.balanceOf(account);
const balanceReceiver = await upgradedTokenContract.balanceOf(accountPrevious);

if (i % 50 == 0) {
console.log(`Validated transfers of ${i + 1} accounts`);
}

if (balanceSender.lte(BigNumber.from(2))) {
// skip small balances
continue;
}

const accountSigner = await impersonateAndFund(account);
// 1/2 balance
const balanceToTransfer = balanceSender.div(BigNumber.from("2"));
await upgradedTokenContract
.connect(accountSigner)
.transfer(accountPrevious, balanceToTransfer);


const balanceSenderAfter = await upgradedTokenContract.balanceOf(account);
const balanceReceiverAfter = await upgradedTokenContract.balanceOf(accountPrevious);

if (!balanceSender.sub(balanceToTransfer).eq(balanceSenderAfter)) {
transferBalanceMissmatches += 1;
console.log(`Balance miss match ${account} expected to have ${balanceSender.sub(balanceToTransfer).toString(10)} actually has ${balanceSenderAfter.toString(10)}`)
}
if (!balanceReceiver.add(balanceToTransfer).eq(balanceReceiverAfter)) {
transferBalanceMissmatches += 1;
console.log(`Balance miss match ${accountPrevious} expected to have ${balanceReceiver.add(balanceToTransfer).toString(10)} actually has ${balanceReceiverAfter.toString(10)}`)
}
}
console.log(`Accounts with unexpected balances: ${transferBalanceMissmatches}`)
}

async function compareUpgradedContractBalances(balancesFile, upgradedTokenContract) {
// CSV file in format account, squidBalance, onChainBalance
const data = fs.readFileSync(balancesFile, "utf8").split('\n');
let balanceMissmatches = 0;
for (let i = 0; i < data.length; i++) {
const [account,,balanceBefore] = data[i].split(',');
const expectedBalance = BigNumber.from(balanceBefore);
const actualBalance = await upgradedTokenContract.balanceOf(account)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would be better to do this in batches using Promise.all

Copy link
Member Author

Choose a reason for hiding this comment

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

Agreed, I didn't do that in the end because all the storage slots are already cached and this function executes quite quickly


if (i % 50 == 0) {
console.log(`Compared balances of ${i + 1} accounts`);
}
if (!actualBalance.eq(expectedBalance)) {
balanceMissmatches += 1;
console.log(`Balance miss match ${account} balance before upgrade: ${expectedBalance.toString(10)} balance before upgrade: ${actualBalance.toString(10)}`)
}
}
console.log(`Accounts with difference balances: ${balanceMissmatches}`)
}

async function governorArgs({ contract, signature, args = [] }) {
const method = signature.split("(")[0];
const tx = await contract.populateTransaction[method](...args);
Expand Down Expand Up @@ -861,4 +961,7 @@ module.exports = {
differenceInErc20TokenBalance,
differenceInErc20TokenBalances,
differenceInStrategyBalance,
addActualBalancesToSquidData,
compareUpgradedContractBalances,
testTransfersOnTokenContract,
};
Loading
Loading