Skip to content

Commit

Permalink
Merge branch 'master' into soloseng/downtimeslasher-foundry-test
Browse files Browse the repository at this point in the history
  • Loading branch information
soloseng committed Apr 19, 2024
2 parents 9188719 + 7962dc5 commit fcf0387
Show file tree
Hide file tree
Showing 68 changed files with 2,889 additions and 784 deletions.
30 changes: 1 addition & 29 deletions .github/workflows/celo-monorepo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ env:
TERM: dumb
GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.parallel=false -Dorg.gradle.configureondemand=true -Dorg.gradle.jvmargs="-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError"'
# Git Tag for contract release to use
#RELEASE_TAG: ganache-v7-core-contracts.v9
RELEASE_TAG: core-contracts.v10
RELEASE_TAG: core-contracts.v11
# CELO_BLOCKCHAIN_BRANCH_TO_TEST: master
CELO_BLOCKCHAIN_BRANCH_TO_TEST: release/1.7.x

Expand Down Expand Up @@ -151,33 +150,6 @@ jobs:
artifacts_to_cache: ${{ needs.install-dependencies.outputs.artifacts_to_cache }}
- run: yarn run prettify:diff
- run: yarn run lint
general_test:
name: General jest test
runs-on: ['self-hosted', 'monorepo-node18']
needs: install-dependencies
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Sync workspace
uses: ./.github/actions/sync-workspace
with:
artifacts_to_cache: ${{ needs.install-dependencies.outputs.artifacts_to_cache }}
- name: Run Jest Tests
run: |
mkdir -p test-results/jest
# Skipping packages that are tested in a specific job below
yarn run lerna \
--ignore @celo/protocol \
--ignore @celo/celotool \
--ignore @celo/env-tests \
run test
- name: Upload Jest Test Results
uses: actions/upload-artifact@v4
with:
name: Jest Test Results
path: test-results/jest


protocol-test-release:
name: Protocol Test Release
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/protocol-devchain.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
include:
- tag: core-contracts.v9
node-version: 12
- tag: core-contracts.v10
- tag: core-contracts.v11
node-version: 18
steps:
- uses: actions/checkout@v4
Expand Down
10 changes: 2 additions & 8 deletions .github/workflows/protocol_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ jobs:
key: ${{ runner.os }}-foundry-out

- name: Install Foundry
uses: onbjerg/foundry-toolchain@v1
with:
version: nightly
uses: foundry-rs/foundry-toolchain@v1

- name: Install forge dependencies
run: forge install
Expand All @@ -50,10 +48,6 @@ jobs:
# can't use gas limit because some setUp function use more than the limit
run: forge test -vvv --match-path "test-sol/common/*" # --block-gas-limit 50000000

- name: Run tests compatibility
if: success() || failure()
run: forge test -vvv --block-gas-limit 50000000 --match-path "test-sol/compatibility/*"

- name: Run tests governance/network
if: success() || failure()
run: forge test -vvv --block-gas-limit 50000000 --match-path "test-sol/governance/network/*"
Expand Down Expand Up @@ -85,4 +79,4 @@ jobs:
- name: Run Everything just in case something was missed
# can't use gas limit because some setUp function use more than the limit
run: forge test -vvv
run: forge test -vvv
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,4 @@
"@types/bn.js": "4.11.6",
"bignumber.js": "9.0.0"
}
}
}
1 change: 1 addition & 0 deletions packages/celotool/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
},
"devDependencies": {
"@tsconfig/recommended": "^1.0.3",
"@celo/dev-utils":"^0.0.3",
"@celo/protocol": "1.0.2",
"@types/bunyan": "1.8.8",
"@types/chai": "^4.1.3",
Expand Down
1 change: 1 addition & 0 deletions packages/celotool/src/cmds/local_testnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Examples:
* local-testnet --validators 5 --proxies 3 --bootnode
* local-testnet --tx-nodes 2 --light-clients 3
* local-testnet --migrate-to 19 --migration-override '{ "lockedGold": { "unlockingPeriod": 30 } }'
* local-testnet --migrate-to 19 --migration-override ../../node_modules/@celo/dev-utils/lib/migration-override.json
* local-testnet --no-migrate --genesis-override '{ "blockTime": 3, "epoch": 50 }'
Network makeup is configured the --validators, --tx-nodes, --light-clients, and --lightest-client
Expand Down
26 changes: 19 additions & 7 deletions packages/protocol/contracts-0.8/common/GasPriceMinimum.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "../../contracts/common/interfaces/ICeloVersionedContract.sol";
import "../../contracts/common/FixidityLib.sol";
import "./UsingRegistry.sol";
import "../../contracts/stability/interfaces/ISortedOracles.sol";
import "@openzeppelin/contracts8/utils/math/Math.sol";

/**
* @title Stores and provides gas price minimum for various currencies.
Expand Down Expand Up @@ -38,6 +39,7 @@ contract GasPriceMinimum is
FixidityLib.Fraction public adjustmentSpeed;

uint256 public baseFeeOpCodeActivationBlock;
uint256 public constant ABSOLUTE_MINIMAL_GAS_PRICE = 1;

/**
* @notice Sets initialized == true on implementation contracts
Expand All @@ -53,7 +55,7 @@ contract GasPriceMinimum is
* @return Patch version of the contract.
*/
function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
return (1, 2, 0, 0);
return (1, 2, 0, 1);
}

/**
Expand Down Expand Up @@ -150,12 +152,7 @@ contract GasPriceMinimum is
}
}

/**
* @notice Retrieve the current gas price minimum for a currency.
* @param tokenAddress The currency the gas price should be in (defaults to gold).
* @return current gas price minimum in the requested currency
*/
function getGasPriceMinimum(address tokenAddress) external view returns (uint256) {
function _getGasPriceMinimum(address tokenAddress) private view returns (uint256) {
if (
tokenAddress == address(0) ||
tokenAddress == registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID)
Expand All @@ -172,6 +169,21 @@ contract GasPriceMinimum is
}
}

/**
* @notice Retrieve the current gas price minimum for a currency.
* When caled for 0x0 or Celo address, it returns gasPriceMinimum().
* For other addresses it returns gasPriceMinimum() mutiplied by
* the SortedOracles median of the token. It does not check tokenAddress is a valid fee currency.
* this function will never returns values less than ABSOLUTE_MINIMAL_GAS_PRICE.
* If Oracle rate doesn't exist, it returns ABSOLUTE_MINIMAL_GAS_PRICE.
* @dev This functions assumes one unit of token has 18 digits.
* @param tokenAddress The currency the gas price should be in (defaults to Celo).
* @return current gas price minimum in the requested currency
*/
function getGasPriceMinimum(address tokenAddress) external view returns (uint256) {
return Math.max(_getGasPriceMinimum(tokenAddress), ABSOLUTE_MINIMAL_GAS_PRICE);
}

/**
* @notice Adjust the gas price minimum based on governable parameters
* and block congestion.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.7 <0.8.20;

import "./FeeCurrencyAdapterOwnable.sol";

contract CeloFeeCurrencyAdapterOwnable is FeeCurrencyAdapterOwnable {
/**
* @notice Sets initialized == true on implementation contracts
* @param test Set to true to skip implementation initialization
*/
constructor(bool test) FeeCurrencyAdapterOwnable(test) {}

/**
* @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, 0, 0);
}
}
182 changes: 182 additions & 0 deletions packages/protocol/contracts-0.8/stability/FeeCurrencyAdapter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.7 <0.8.20;

import "@openzeppelin/contracts8/access/Ownable.sol";
import "@openzeppelin/contracts8/token/ERC20/IERC20.sol";

import "../../contracts/common/CalledByVm.sol";
import "../../contracts/common/Initializable.sol";
import "../../contracts/common/interfaces/ICeloVersionedContract.sol";
import "../../contracts/common/FixidityLib.sol";
import "../../contracts/stability/interfaces/ISortedOracles.sol";
import "./interfaces/IFeeCurrency.sol";
import "./interfaces/IDecimals.sol";
import "./interfaces/IFeeCurrencyAdapter.sol";

contract FeeCurrencyAdapter is Initializable, CalledByVm, IFeeCurrencyAdapter {
IFeeCurrency public adaptedToken;

uint96 public digitDifference;

uint256 public debited = 0;

string public name;
string public symbol;

uint8 public expectedDecimals;

uint256[44] __gap;

/**
* @notice Sets initialized == true on implementation contracts
* @param test Set to true to skip implementation initialization
*/
constructor(bool test) public Initializable(test) {}

/**
* @notice Used in place of the constructor to allow the contract to be upgradable via proxy.
* @param _adaptedToken The address of the adapted token.
* @param _name The name of the adapted token.
* @param _symbol The symbol of the adapted token.
* @param _expectedDecimals The expected number of decimals of the adapted token.
* @notice _expectedDecimals must be bigger than _adaptedToken.decimals().
*/
function initialize(
address _adaptedToken,
string memory _name,
string memory _symbol,
uint8 _expectedDecimals
) public virtual initializer {
_setAdaptedToken(_adaptedToken);
name = _name;
symbol = _symbol;
uint8 _decimals = IDecimals(_adaptedToken).decimals();
require(
_decimals < _expectedDecimals,
"Decimals of adapted token must be < expected decimals."
);
digitDifference = uint96(10**(_expectedDecimals - _decimals));
expectedDecimals = _expectedDecimals;
}

/**
* Downscales value to the adapted token's native digits and debits it.
* @param from from address
* @param value Debited value in the adapted digits.
*/
function debitGasFees(address from, uint256 value) external onlyVm {
uint256 valueScaled = downscale(value);
require(valueScaled > 0, "Scaled debit value must be > 0.");
debited = valueScaled;
adaptedToken.debitGasFees(from, valueScaled);
}

/**
* Downscales value to the adapted token's native digits and credits it.
* @param refundRecipient The recipient of the refund.
* @param tipRecipient The recipient of the tip.
* @param _gatewayFeeRecipient The recipient of the gateway fee. Unused.
* @param baseFeeRecipient The recipient of the base fee.
* @param refundAmount The amount to refund (in adapted token digits).
* @param tipAmount The amount to tip (in adapted token digits).
* @param _gatewayFeeAmount The amount of the gateway fee (in adapted token digits). Unused.
* @param baseFeeAmount The amount of the base fee (in adapted token digits).
*/
function creditGasFees(
address refundRecipient,
address tipRecipient,
address _gatewayFeeRecipient,
address baseFeeRecipient,
uint256 refundAmount,
uint256 tipAmount,
uint256 _gatewayFeeAmount,
uint256 baseFeeAmount
) external onlyVm {
if (debited == 0) {
// When eth.estimateGas is called, this function is called but we don't want to credit anything.
return;
}

uint256 refundScaled = downscale(refundAmount);
uint256 tipTxFeeScaled = downscale(tipAmount);
uint256 baseTxFeeScaled = downscale(baseFeeAmount);

require(
refundScaled + tipTxFeeScaled + baseTxFeeScaled <= debited,
"Cannot credit more than debited."
);

uint256 roundingError = debited - (refundScaled + tipTxFeeScaled + baseTxFeeScaled);

if (roundingError > 0) {
baseTxFeeScaled += roundingError;
}
adaptedToken.creditGasFees(
refundRecipient,
tipRecipient,
address(0),
baseFeeRecipient,
refundScaled,
tipTxFeeScaled,
0,
baseTxFeeScaled
);

debited = 0;
}

/**
* @notice Returns adapted token address.
* @return The adapted token address.
*/
function getAdaptedToken() external view returns (address) {
return address(adaptedToken);
}

/**
* @notice Gets the balance of the specified address with correct digits.
* @param account The address to query the balance of.
* @return The balance of the specified address.
*/
function balanceOf(address account) external view returns (uint256) {
return upscale(adaptedToken.balanceOf(account));
}

/**
* @notice Gets the total supply with correct digits.
* @return The total supply.
*/
function totalSupply() external view returns (uint256) {
return upscale(adaptedToken.totalSupply());
}

/**
* @notice Gets the total supply with correct digits.
* @return The total supply.
*/
function decimals() external view returns (uint8) {
return expectedDecimals;
}

function upscale(uint256 value) internal view returns (uint256) {
return value * digitDifference;
}

/**
* @notice Downscales value to the adapted token's native digits.
* @dev Downscale is rounding up in favour of protocol. User possibly can pay a bit more than expected (up to 1 unit of a token).
* Example:
* USDC has 6 decimals and in such case user can pay up to 0.000001 USDC more than expected.
* WBTC (currently not supported by Celo chain as fee currency) has 8 decimals and in such case user can pay up to 0.00000001 WBTC more than expected.
* Considering the current price of WBTC, it's less than 0.0005 USD. Even when WBTC price would be 1 mil USD, it's still would be only 0.01 USD.
* In general it is a very small amount and it is acceptable to round up in favor of the protocol.
* @param value The value to downscale.
*/
function downscale(uint256 value) internal view returns (uint256) {
return (value + digitDifference - 1) / digitDifference;
}

function _setAdaptedToken(address _adaptedToken) internal virtual {
adaptedToken = IFeeCurrency(_adaptedToken);
}
}
Loading

0 comments on commit fcf0387

Please sign in to comment.