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

Misc: ops-scripts, metadata, forwarders #1678

Merged
merged 5 commits into from
Sep 18, 2023
Merged
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
4 changes: 2 additions & 2 deletions packages/ethereum-contracts/ops-scripts/deploy-framework.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,8 @@ module.exports = eval(`(${S.toString()})({skipArgv: true})`)(async function (
if (governanceInitializationRequired) {
const accounts = await web3.eth.getAccounts();
const trustedForwarders = [];
if (config.biconomyForwarder) {
trustedForwarders.push(config.biconomyForwarder);
if (config.trustedForwarders) {
trustedForwarders.push(...config.trustedForwarders);
}
if (config.cfaFwd) {
trustedForwarders.push(config.cfaFwd);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const {
* (overriding env: SKIP_TOKENS_FILE) - defaults to "./upgrade_skip_tokens.json"
* @param {string} options.outputFile Name of file where to log addresses of tokens (to be) updated
* (overriding env: OUTPUT_FILE)
* @param {string} options.superTokenLogic override address for the logic to upgrade to instead of the canonical one
* (overriding env: SUPER_TOKEN_LOGIC
*
* Usage: npx truffle exec ops-scripts/gov-upgrade-super-token-logic.js : ALL | {SUPER_TOKEN_ADDRESS} ...
*/
Expand All @@ -33,7 +35,7 @@ module.exports = eval(`(${S.toString()})()`)(async function (
options = {}
) {
console.log("======== Upgrade super token logic ========");
let {protocolReleaseVersion, skipTokensFile, dryRun, outputFile} = options;
let {protocolReleaseVersion, skipTokensFile, dryRun, outputFile, superTokenLogic} = options;

console.log("protocol release version:", protocolReleaseVersion);
dryRun = dryRun || process.env.DRY_RUN !== undefined;
Expand All @@ -59,13 +61,14 @@ module.exports = eval(`(${S.toString()})()`)(async function (
outputFile = outputFile || process.env.OUTPUT_FILE;
console.log("output file: ", outputFile);

superTokenLogic = superTokenLogic || process.env.SUPER_TOKEN_LOGIC;

const sf = new SuperfluidSDK.Framework({
...extractWeb3Options(options),
version: protocolReleaseVersion,
additionalContracts: [
"Ownable",
"IMultiSigWallet",
"ISafe",
"SuperfluidGovernanceBase",
"Resolver",
"UUPSProxiable",
Expand All @@ -75,84 +78,20 @@ module.exports = eval(`(${S.toString()})()`)(async function (
});
await sf.initialize();

const {UUPSProxiable, ISuperToken} = sf.contracts;
const canonicalSuperTokenLogic = await getCanonicalSuperTokenLogic(sf);
console.log(`current canonical super token logic: ${canonicalSuperTokenLogic}`);

const superTokenFactory = await sf.contracts.ISuperTokenFactory.at(
await sf.host.getSuperTokenFactory.call()
);
let tokensToBeUpgraded = (args.length === 1 && args[0] === "ALL") ?
await getTokensToBeUpgraded(sf, canonicalSuperTokenLogic, skipTokens) :
Array.from(args);

let tokensToBeChecked;
const maxItems = parseInt(process.env.MAX_ITEMS) || 1000;
const skipItems = parseInt(process.env.SKIP_ITEMS) || 0;
if (args.length === 1 && args[0] === "ALL") {
tokensToBeChecked = (
await sf.subgraphQuery(`{
tokenStatistics(first: ${maxItems}, skip: ${skipItems}) {
token {
id
}
}
}`)
).tokenStatistics.map((i) => i.token.id);
} else {
tokensToBeChecked = Array.from(args);
}
console.log(`${tokensToBeUpgraded.length} tokens to be upgraded)`);

console.log(`Got ${tokensToBeChecked.length} candidates`);
if (tokensToBeChecked.length >= maxItems) {
console.warn("### There's more items than returned by the query");
}
const superTokenLogicAddr = superTokenLogic !== undefined ?
superTokenLogic :
canonicalSuperTokenLogic;

const latestSuperTokenLogic = await superTokenFactory.getSuperTokenLogic();
console.log("Latest SuperToken logic address", latestSuperTokenLogic);

// before applying skip list
let tokensToMaybeBeUpgraded = (
await async.mapLimit(
tokensToBeChecked,
MAX_REQUESTS,
async (superTokenAddress) => {
const superToken = await ISuperToken.at(superTokenAddress);
try {
const symbol = await superToken.symbol();
if ((await superToken.getHost()) !== sf.host.address) {
throw new Error(
"Super token is from a different universe"
);
}
const superTokenLogic = await (
await UUPSProxiable.at(superTokenAddress)
).getCodeAddress();

if (superTokenLogic === ZERO_ADDRESS) {
console.log(
`SuperToken@${superToken.address} (${symbol}) is likely a not initalized proxy`
);
} else if (latestSuperTokenLogic !== superTokenLogic) {
console.log(
`SuperToken@${superToken.address} (${symbol}) logic needs upgrade from ${superTokenLogic}`
);
return superTokenAddress;
} else {
console.log(
`SuperToken@${superToken.address} (${symbol}) logic is up to date`
);
return undefined;
}
} catch {
console.warn(
`[WARN] SuperToken@${superToken.address} is smelly`
);
return undefined;
}
}
)
).filter((i) => typeof i !== "undefined");

console.log(`${tokensToMaybeBeUpgraded.length} tokens to maybe be upgraded (before applying skip list)`);

const tokensToBeUpgraded = tokensToMaybeBeUpgraded.filter(
(item) => !skipTokens.map(e => e.toLowerCase()).includes(item.toLowerCase()));
console.log("SuperToken logic to update to:", superTokenLogicAddr);

if (tokensToBeUpgraded.length > 0) {
console.log(`${tokensToBeUpgraded.length} tokens to be upgraded`);
Expand All @@ -168,21 +107,25 @@ module.exports = eval(`(${S.toString()})()`)(async function (
`*** Batch ${offset/batchSize+1} | upgrading ${batch.length} super tokens: ${JSON.stringify(batch, null, 2)}`
);
if (!dryRun) {
await sendGovernanceAction(sf, (gov) =>
gov.batchUpdateSuperTokenLogic(sf.host.address, batch)
);
// a non-canonical logic address can be provided in an extra array (batchUpdateSuperTokenLogic is overloaded)
const govAction = superTokenLogic !== undefined ?
(gov) => gov.batchUpdateSuperTokenLogic(sf.host.address, batch, [...new Array(batch.length)].map(e => superTokenLogicAddr)) :
(gov) => gov.batchUpdateSuperTokenLogic(sf.host.address, batch)

await sendGovernanceAction(sf, govAction);

console.log("checking if 2nd run needed");
// When first updating to the version adding native flow NFTs, this needs to be run twice
console.log("checking if 2nd run needed...");
try {
const beaconST = await ISuperToken.at(batch[0]);
const beaconST = await sf.contracts.ISuperToken.at(batch[0]);
const cofAddr = await beaconST.CONSTANT_OUTFLOW_NFT();
if (cofAddr === ZERO_ADDRESS) {
console.log("running upgrade again for NFT initialization...");
console.log("...running upgrade again for NFT initialization...");
// the first time it is to get the code to initialize the NFT proxies there
// the second time is to actually execute that code in updateCode
await sendGovernanceAction(sf, (gov) =>
gov.batchUpdateSuperTokenLogic(sf.host.address, batch)
);
await sendGovernanceAction(sf, govAction);
} else {
console.log("...not needed");
}
} catch (e) {
console.log(`failed to read constantOutflowNFT addr: ${e.toString()}`);
Expand All @@ -191,4 +134,76 @@ module.exports = eval(`(${S.toString()})()`)(async function (
}
}
}
});
});

// returns the current canonical SuperToken logic of the SF deployment
async function getCanonicalSuperTokenLogic(sf) {
const superTokenFactory = await sf.contracts.ISuperTokenFactory.at(
await sf.host.getSuperTokenFactory.call()
);
return superTokenFactory.getSuperTokenLogic();
}

// gets a list of tokens (addresses) to be upgraded
// starts from the list of all SuperTokens returned by the subgraph,
// from there filters out those
// - having a different host
// - not being a proxy or not having a logic address
// - already pointing to the latest logic
// - in the skip list (e.g. because not managed by SF gov)
async function getTokensToBeUpgraded(sf, canonicalSuperTokenLogic, skipList) {
const maxItems = parseInt(process.env.MAX_ITEMS) || 1000;
const skipItems = parseInt(process.env.SKIP_ITEMS) || 0;

const candidateTokens = (await sf.subgraphQuery(`{
tokens(where: {isSuperToken: true}, first: ${maxItems}, skip: ${skipItems}) {
id
}
}`)).tokens.map((i) => i.id);

console.log(`Got ${candidateTokens.length} candidates`);
if (candidateTokens.length >= maxItems) {
console.warn("### There's more items than returned by the query");
}

return (await async.mapLimit(
candidateTokens,
MAX_REQUESTS,
async (superTokenAddress) => {
const superToken = await sf.contracts.ISuperToken.at(superTokenAddress);
try {
const symbol = await superToken.symbol();
if ((await superToken.getHost()) !== sf.host.address) {
throw new Error(
"Super token is from a different universe"
);
}
const superTokenLogic = await (
await sf.contracts.UUPSProxiable.at(superTokenAddress)
).getCodeAddress();

if (superTokenLogic === ZERO_ADDRESS) {
console.log(
`SuperToken@${superToken.address} (${symbol}) is likely an uninitalized proxy`
);
} else if (canonicalSuperTokenLogic !== superTokenLogic) {
console.log(
`SuperToken@${superToken.address} (${symbol}) logic needs upgrade from ${superTokenLogic}`
);
return superTokenAddress;
} else {
console.log(
`SuperToken@${superToken.address} (${symbol}) logic is up to date`
);
return undefined;
}
} catch {
console.warn(
`[WARN] SuperToken@${superToken.address} is smelly`
);
return undefined;
}
}
)).filter((i) => typeof i !== "undefined")
.filter((item) => !skipList.map(e => e.toLowerCase()).includes(item.toLowerCase()));
}
8 changes: 7 additions & 1 deletion packages/ethereum-contracts/ops-scripts/libs/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,13 @@ async function setResolver(sf, key, value) {
sf.resolver.address
);
const nrAdmins = (await ac.getRoleMemberCount(ADMIN_ROLE)).toNumber();
const resolverAdmin = await ac.getRoleMember(ADMIN_ROLE, nrAdmins - 1);
const resolverAdmin = nrAdmins > 0 ?
await ac.getRoleMember(ADMIN_ROLE, nrAdmins - 1):
await (async () => {
// This is for eth-goerli (and maybe other networks too)
console.log(`!!! resolver.getRoleMemberCount() returned 0. Trying account[0] as resolver admin.`);
return (await web3.eth.getAccounts())[0];
})();

const adminType = process.env.RESOLVER_ADMIN_TYPE
|| await autodetectAdminType(sf, resolverAdmin);
Expand Down
24 changes: 6 additions & 18 deletions packages/ethereum-contracts/ops-scripts/libs/getConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,24 @@ const sfMetadata = require("@superfluid-finance/metadata");

module.exports = function getConfig(chainId) {

/*
* REFERENCES:
* - https://docs.biconomy.io/misc/contract-addresses
*/

const EXTRA_CONFIG = {
// here go the trusted forwarders which aren't part of the framework contracts

// Local Testing
4447: {
// for local testing (truffle internal ganache and TestEnvironment)
// this is a fake forwarder address, it is to test the deployment script
biconomyForwarder: "0x3075b4dc7085C48A14A5A39BBa68F58B19545971",
trustedForwarders: ["0x3075b4dc7085C48A14A5A39BBa68F58B19545971"],
},
5777: {
// for local testing (external ganache)
// this is a fake forwarder address, it is to test the deployment script
biconomyForwarder: "0x3075b4dc7085C48A14A5A39BBa68F58B19545971",
trustedForwarders: ["0x3075b4dc7085C48A14A5A39BBa68F58B19545971"],
},
6777: {
// for coverage testing
// this is a fake forwarder address, it is to test the deployment script
biconomyForwarder: "0x3075b4dc7085C48A14A5A39BBa68F58B19545971",
},

// Ethereum Goerli Testnet
5: {
biconomyForwarder: "0x3075b4dc7085C48A14A5A39BBa68F58B19545971",
},

// Polygon Mumbai Testnet
80001: {
biconomyForwarder: "0x2B99251eC9650e507936fa9530D11dE4d6C9C05c",
trustedForwarders: ["0x3075b4dc7085C48A14A5A39BBa68F58B19545971"],
},

// Celo Mainnet
Expand Down Expand Up @@ -62,6 +49,7 @@ module.exports = function getConfig(chainId) {
nativeTokenSymbol: sfNw?.nativeTokenSymbol || "ETH",
metadata: sfNw,
resolverAddress: global?.process.env.RESOLVER_ADDRESS || sfNw?.contractsV1?.resolver,
trustedForwarders: sfNw?.trustedForwarders,
...EXTRA_CONFIG[chainId]
};
};
Loading
Loading