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

Implement IOracle to SortedOracles & add FeeCurrencyDirectory to devchain #10993

Merged
merged 10 commits into from
May 16, 2024
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
8 changes: 6 additions & 2 deletions packages/protocol/contractPackages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ export const SOLIDITY_08_PACKAGE = {
proxiesPath: '/', // Proxies are still with 0.5 contracts
// Proxies shouldn't have to be added to a list manually
// https://github.com/celo-org/celo-monorepo/issues/10555
contracts: ['GasPriceMinimum'],
proxyContracts: ['GasPriceMinimumProxy'],
contracts: ['GasPriceMinimum', 'FeeCurrencyDirectory'],
proxyContracts: [
'GasPriceMinimumProxy',
'FeeCurrencyDirectoryProxy',
'MentoFeeCurrencyAdapterV1',
],
truffleConfig: 'truffle-config0.8.js',
} satisfies ContractPackage
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity >=0.5.13 <0.9.0;

/// Possibly not final version
interface IOracle {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pragma solidity ^0.5.13;

import "../Proxy.sol";

/* solhint-disable-next-line no-empty-blocks */
contract FeeCurrencyDirectoryProxy is Proxy {}
37 changes: 25 additions & 12 deletions packages/protocol/contracts/stability/SortedOracles.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import "../common/FixidityLib.sol";
import "../common/Initializable.sol";
import "../common/linkedlists/AddressSortedLinkedListWithMedian.sol";
import "../common/linkedlists/SortedLinkedListWithMedian.sol";
import "../../contracts-0.8/common/interfaces/IOracle.sol";

/**
* @title SortedOracles
Expand Down Expand Up @@ -319,6 +320,29 @@ contract SortedOracles is ISortedOracles, ICeloVersionedContract, Ownable, Initi
return rates[token].getElements();
}

/**
* @notice Returns the exchange rate for a specified token.
* @param token The token for which the exchange rate is being retrieved.
* @return uint256 The exchange rate for the specified token.
* @return uint256 The denominator for the exchange rate.
*/
function getExchangeRate(
address token
) external view returns (uint256 numerator, uint256 denominator) {
(numerator, denominator) = medianRate(token);
}

/**
* @notice Returns the storage, major, minor, and patch version of the contract.
* @return Storage version of the contract.
* @return Major version of the contract.
* @return Minor version of the contract.
* @return Patch version of the contract.
*/
function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
return (1, 1, 4, 0);
}

/**
* @notice Returns the median of the currently stored rates for a specified rateFeedId.
* @dev Please note that this function respects the equivalentToken mapping, and so may
Expand All @@ -327,7 +351,7 @@ contract SortedOracles is ISortedOracles, ICeloVersionedContract, Ownable, Initi
* @return uint256 The median exchange rate for rateFeedId (fixidity).
* @return uint256 denominator
*/
function medianRate(address token) external view returns (uint256, uint256) {
function medianRate(address token) public view returns (uint256, uint256) {
EquivalentToken storage equivalentToken = equivalentTokens[token];
if (equivalentToken.token != address(0)) {
(uint256 equivalentMedianRate, uint256 denominator) = medianRateWithoutEquivalentMapping(
Expand All @@ -339,17 +363,6 @@ contract SortedOracles is ISortedOracles, ICeloVersionedContract, Ownable, Initi
return medianRateWithoutEquivalentMapping(token);
}

/**
* @notice Returns the storage, major, minor, and patch version of the contract.
* @return Storage version of the contract.
* @return Major version of the contract.
* @return Minor version of the contract.
* @return Patch version of the contract.
*/
function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
return (1, 1, 3, 0);
}

/**
* @notice Sets the report expiry parameter.
* @param _reportExpirySeconds The number of seconds before a report is considered expired.
Expand Down
20 changes: 12 additions & 8 deletions packages/protocol/lib/compatibility/verify-bytecode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '@celo/protocol/lib/bytecode'
import { verifyProxyStorageProof } from '@celo/protocol/lib/proxy-utils'
import { ProposalTx } from '@celo/protocol/scripts/truffle/make-release'
import { ZERO_ADDRESS } from '@celo/protocol/test/constants'
import { BuildArtifacts } from '@openzeppelin/upgrades'
import { ProxyInstance, RegistryInstance } from 'types'
import Web3 from 'web3'
Expand All @@ -24,7 +25,7 @@ let ignoredContracts = [
]

interface VerificationContext {
artifacts: BuildArtifacts
artifacts: BuildArtifacts[]
libraryAddresses: LibraryAddresses
registry: RegistryInstance
governanceAddress: string
Expand Down Expand Up @@ -76,8 +77,8 @@ export const getProposedProxyAddress = (contract: string, proposal: ProposalTx[]
return relevantTx.args[1]
}

const getSourceBytecodeFromArtifacts = (contract: string, artifacts: BuildArtifacts): string =>
stripMetadata(artifacts.getArtifactByName(contract).deployedBytecode)
const getSourceBytecodeFromArtifacts = (contract: string, artifacts: BuildArtifacts[]): string =>
stripMetadata(artifacts.map(a => a.getArtifactByName(contract)).find(a => a).deployedBytecode)

const getSourceBytecode = (contract: string, context: VerificationContext): string =>
getSourceBytecodeFromArtifacts(contract, context.artifacts)
Expand Down Expand Up @@ -110,7 +111,6 @@ const dfsStep = async (queue: string[], visited: Set<string>, context: Verificat
throw new Error(`Proposed ${contract}Proxy does not match compiled proxy bytecode`)
}

console.log(`Proxy deployed at ${proxyAddress} matches ${contract}Proxy (bytecode and storage)`)
}

// check implementation deployment
Expand All @@ -124,6 +124,10 @@ const dfsStep = async (queue: string[], visited: Set<string>, context: Verificat
implementationAddress = ensureLeading0x(context.libraryAddresses.addresses[contract])
} else {
const proxyAddress = await context.registry.getAddressForString(contract)
if (proxyAddress === ZERO_ADDRESS) {
console.log(`Contract ${contract} is not in registry - skipping bytecode verification`)
return;
}
const proxy = await context.Proxy.at(proxyAddress) // necessary await
implementationAddress = await proxy._getImplementation()
}
Expand Down Expand Up @@ -166,7 +170,7 @@ const assertValidProposalTransactions = (proposal: ProposalTx[]) => {
}

const assertValidInitializationData = (
artifacts: BuildArtifacts,
artifacts: BuildArtifacts[],
proposal: ProposalTx[],
web3: Web3,
initializationData: InitializationData
Expand All @@ -182,7 +186,7 @@ const assertValidInitializationData = (
)
}

const contract = artifacts.getArtifactByName(contractName)
const contract = artifacts.map(a => a.getArtifactByName(contractName)).find(a => a)
const initializeAbi = contract.abi.find(
(abi: any) => abi.type === 'function' && abi.name === 'initialize'
)
Expand Down Expand Up @@ -216,7 +220,7 @@ const assertValidInitializationData = (
*/
export const verifyBytecodes = async (
contracts: string[],
artifacts: BuildArtifacts,
artifacts: BuildArtifacts[],
registry: RegistryInstance,
proposal: ProposalTx[],
Proxy: Truffle.Contract<ProxyInstance>,
Expand All @@ -228,7 +232,7 @@ export const verifyBytecodes = async (
assertValidProposalTransactions(proposal)
assertValidInitializationData(artifacts, proposal, _web3, initializationData)

const compiledContracts = artifacts.listArtifacts().map((a) => a.contractName)
const compiledContracts = Array.prototype.concat.apply([], artifacts.map(a => a.listArtifacts())).map((a) => a.contractName)

if (version > 9) {
ignoredContracts = [...ignoredContracts, ...ignoredContractsV9]
Expand Down
7 changes: 4 additions & 3 deletions packages/protocol/lib/registry-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export enum CeloContractName {
FeeCurrencyWhitelist = 'FeeCurrencyWhitelist',
Freezer = 'Freezer',
GasPriceMinimum = 'GasPriceMinimum',
FeeCurrencyDirectory = 'FeeCurrencyDirectory',
GoldToken = 'GoldToken',
Governance = 'Governance',
GovernanceSlasher = 'GovernanceSlasher',
Expand All @@ -52,10 +53,10 @@ export const usesRegistry = [
CeloContractName.StableToken,
]

export const hasEntryInRegistry: ContractPackage[]= [
export const hasEntryInRegistry: ContractPackage[] = [
{
name: "default",
contracts:[
contracts: [
CeloContractName.Accounts,
CeloContractName.Attestations,
CeloContractName.BlockchainParameters,
Expand All @@ -78,7 +79,7 @@ export const hasEntryInRegistry: ContractPackage[]= [
{
...MENTO_PACKAGE,
// not all Mentro contracts are supposed to be in the Registry
contracts:[
contracts: [
CeloContractName.Exchange,
CeloContractName.GrandaMento,
CeloContractName.Reserve,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { ArtifactsSingleton } from '@celo/protocol/lib/artifactsSingleton'
import { CeloContractName } from '@celo/protocol/lib/registry-utils'
import {
deploymentForCoreContract,
getDeployedProxiedContract,
} from '@celo/protocol/lib/web3-utils'
import { SortedOraclesInstance, StableTokenInstance } from '@celo/protocol/types/typechain-mento'
import { FeeCurrencyDirectoryInstance } from 'types/08'
import { MENTO_PACKAGE, SOLIDITY_08_PACKAGE } from '../contractPackages'

const initializeArgs = async (): Promise<any[]> => {
return []
}

module.exports = deploymentForCoreContract<FeeCurrencyDirectoryInstance>(
web3,
artifacts,
CeloContractName.FeeCurrencyDirectory,
initializeArgs,
async (feeCurrencyDirectory: FeeCurrencyDirectoryInstance, _web3: Web3, networkName: string) => {
const sortedOracles = await getDeployedProxiedContract<SortedOraclesInstance>(
'SortedOracles',
artifacts
)

for (const token of ['StableToken', 'StableTokenEUR', 'StableTokenBRL']) {
const stableToken: StableTokenInstance =
await getDeployedProxiedContract<StableTokenInstance>(
token,
ArtifactsSingleton.getInstance(MENTO_PACKAGE)
)
console.log(
'setting currency config for',
token,
'with address',
stableToken.address,
'and adapter address',
sortedOracles.address,
'on network',
networkName
)
await feeCurrencyDirectory.setCurrencyConfig(stableToken.address, sortedOracles.address, 1)
}

console.log(
'Fee currency directory deployed and registered!!!',
feeCurrencyDirectory.address,
networkName
)
},
SOLIDITY_08_PACKAGE
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"FeeCurrencyDirectory": []
}
6 changes: 5 additions & 1 deletion packages/protocol/scripts/truffle/verify-bytecode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ const argv = require('minimist')(process.argv.slice(2), {
})

const artifactsDirectory = argv.build_artifacts ? argv.build_artifacts : './build/contracts'
const artifacts08Directory = argv.build_artifacts08
? argv.build_artifacts08
: './build/contracts-0.8'
const branch = (argv.branch ? argv.branch : '') as string
const network = argv.network ?? 'development'
const proposal = argv.proposal ? readJsonSync(argv.proposal) : []
Expand All @@ -48,9 +51,10 @@ module.exports = async (callback: (error?: any) => number) => {

const registry = await Registry.at(celoRegistryAddress)
const buildArtifacts = getBuildArtifacts(artifactsDirectory)
const artifacts08 = getBuildArtifacts(artifacts08Directory)
const libraryAddresses = await verifyBytecodes(
Object.keys(CeloContractName),
buildArtifacts,
[buildArtifacts, artifacts08],
registry,
proposal,
Proxy,
Expand Down
3 changes: 3 additions & 0 deletions packages/protocol/test-sol/stability/SortedOracles.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,11 @@ contract RemoveOracle is SortedOraclesTest {

sortedOracle.removeOracle(aToken, oracleAccount, 0);
(uint256 newMedianRate, uint256 newNumOfRates) = sortedOracle.medianRate(aToken);
(uint256 exchangeRate, uint256 exchangeRateDenominator) = sortedOracle.getExchangeRate(aToken);
assertEq(originalMedianRate, newMedianRate);
assertEq(originalNumOfRates, newNumOfRates);
assertEq(exchangeRate, newMedianRate);
assertEq(exchangeRateDenominator, FIXED1);
}

function test_ShouldNotDecreaseTheNumberOfTimestamps_WhenThereIsASingleReportLeft() public {
Expand Down
Loading
Loading