Skip to content

Commit

Permalink
Implement testing using Foundry
Browse files Browse the repository at this point in the history
  • Loading branch information
alhonaut committed Sep 12, 2024
0 parents commit f62766d
Show file tree
Hide file tree
Showing 10 changed files with 605 additions and 0 deletions.
45 changes: 45 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: CI

on:
push:
pull_request:
workflow_dispatch:

env:
FOUNDRY_PROFILE: ci

jobs:
check:
strategy:
fail-fast: true

name: Foundry project
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive

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

- name: Show Forge version
run: |
forge --version
- name: Run Forge fmt
run: |
forge fmt --check
id: fmt

- name: Run Forge build
run: |
forge build --sizes
id: build

- name: Run Forge tests
run: |
forge test -vvv
id: test
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Compiler files
cache/
out/

# Ignores development broadcast logs
!/broadcast
/broadcast/*/31337/
/broadcast/**/dry-run/

# Docs
docs/

# Dotenv file
.env
66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
## Foundry

**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.**

Foundry consists of:

- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.

## Documentation

https://book.getfoundry.sh/

## Usage

### Build

```shell
$ forge build
```

### Test

```shell
$ forge test
```

### Format

```shell
$ forge fmt
```

### Gas Snapshots

```shell
$ forge snapshot
```

### Anvil

```shell
$ anvil
```

### Deploy

```shell
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
```

### Cast

```shell
$ cast <subcommand>
```

### Help

```shell
$ forge --help
$ anvil --help
$ cast --help
```
6 changes: 6 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[profile.default]
src = "src"
out = "out"
libs = ["lib"]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
1 change: 1 addition & 0 deletions lib/forge-std
Submodule forge-std added at 1714be
4 changes: 4 additions & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
forge-std/=lib/forge-std/src/
@chainlink/=/node_modules/@chainlink
@openzeppelin/=/node_modules/@openzeppelin
@aave/=/node_modules/@aave
83 changes: 83 additions & 0 deletions src/PaymentV1.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {IERC20} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol";
import {IPool} from "@aave/core-v3/contracts/interfaces/IPool.sol";

contract USDCPayment {
using SafeERC20 for IERC20;

mapping(bytes32 => uint256) public s_transactions; // list of amounts per ID

IPool public immutable i_pool;
IERC20 public immutable i_usdc;

error AmountIsZero();
error TransferFailed();
error IncorrectTokenAmount();
error IncorrectAmountId();
error NotOwner();
error InvalidUsdcToken();

event ProposalOpened(bytes32 id, uint256 amount, address initiator);
event ProposalClosed(bytes32 id, address freelancer);

constructor(address _addressPool, address _usdcAddress) {
if (_usdcAddress == address(0)) revert InvalidUsdcToken();
i_pool = IPool(_addressPool);
i_usdc = IERC20(_usdcAddress);
i_usdc.safeApprove(_addressPool, type(uint256).max);
}

function openProposal(uint256 _amount) external {
if (_amount == 0) revert AmountIsZero();

if (!i_usdc.transferFrom(msg.sender, address(this), _amount)) {
revert TransferFailed();
}
bytes32 uniqueId = generateID(msg.sender, _amount);

s_transactions[uniqueId] = _amount;
i_pool.supply(address(i_usdc), _amount, address(this), 0);

emit ProposalOpened(uniqueId, _amount, msg.sender);
}

/// @param id Generated ID to ensure is caller is valid owner.
/// @param freelancer address of beneficiary for succesfull job or empty address in case of calling by client
function closeProposal(bytes32 id, address freelancer) external {
uint256 proposalAmount = s_transactions[id];
if (proposalAmount == 0) {
revert IncorrectAmountId();
}
delete s_transactions[id];

address receiver;
if (freelancer == address(0)) {
receiver = msg.sender;
} else {
receiver = freelancer;
}

emit ProposalClosed(id, freelancer);

i_pool.withdraw(address(i_usdc), proposalAmount, receiver);
}

function getBalance(address _tokenAddress) external view returns (uint256) {
return IERC20(_tokenAddress).balanceOf(address(this));
}

// generate unique Indetifier for cross-chain transaction
/// @param _beneficiary The address of the client.
function generateID(
address _beneficiary,
uint256 _amount
) public view returns (bytes32) {
return
keccak256(abi.encodePacked(_beneficiary, _amount, block.timestamp));
}

receive() external payable {}
}
147 changes: 147 additions & 0 deletions src/interfaces/IComet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/**
* @title Compound's Comet Main Interface (without Ext)
* @notice An efficient monolithic money market protocol
* @author Compound
*/
abstract contract IComet {
error Absurd();
error AlreadyInitialized();
error BadAsset();
error BadDecimals();
error BadDiscount();
error BadMinimum();
error BadPrice();
error BorrowTooSmall();
error BorrowCFTooLarge();
error InsufficientReserves();
error LiquidateCFTooLarge();
error NoSelfTransfer();
error NotCollateralized();
error NotForSale();
error NotLiquidatable();
error Paused();
error SupplyCapExceeded();
error TimestampTooLarge();
error TooManyAssets();
error TooMuchSlippage();
error TransferInFailed();
error TransferOutFailed();
error Unauthorized();

event Supply(address indexed from, address indexed dst, uint amount);
event Transfer(address indexed from, address indexed to, uint amount);
event Withdraw(address indexed src, address indexed to, uint amount);

event SupplyCollateral(address indexed from, address indexed dst, address indexed asset, uint amount);
event TransferCollateral(address indexed from, address indexed to, address indexed asset, uint amount);
event WithdrawCollateral(address indexed src, address indexed to, address indexed asset, uint amount);

/// @notice Event emitted when a borrow position is absorbed by the protocol
event AbsorbDebt(address indexed absorber, address indexed borrower, uint basePaidOut, uint usdValue);

/// @notice Event emitted when a user's collateral is absorbed by the protocol
event AbsorbCollateral(address indexed absorber, address indexed borrower, address indexed asset, uint collateralAbsorbed, uint usdValue);

/// @notice Event emitted when a collateral asset is purchased from the protocol
event BuyCollateral(address indexed buyer, address indexed asset, uint baseAmount, uint collateralAmount);

/// @notice Event emitted when an action is paused/unpaused
event PauseAction(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused);

/// @notice Event emitted when reserves are withdrawn by the governor
event WithdrawReserves(address indexed to, uint amount);

function supply(address asset, uint amount) virtual external;
function supplyTo(address dst, address asset, uint amount) virtual external;
function supplyFrom(address from, address dst, address asset, uint amount) virtual external;

function transfer(address dst, uint amount) virtual external returns (bool);
function transferFrom(address src, address dst, uint amount) virtual external returns (bool);

function transferAsset(address dst, address asset, uint amount) virtual external;
function transferAssetFrom(address src, address dst, address asset, uint amount) virtual external;

function withdraw(address asset, uint amount) virtual external;
function withdrawTo(address to, address asset, uint amount) virtual external;
function withdrawFrom(address src, address to, address asset, uint amount) virtual external;

function approveThis(address manager, address asset, uint amount) virtual external;
function withdrawReserves(address to, uint amount) virtual external;

function absorb(address absorber, address[] calldata accounts) virtual external;
function buyCollateral(address asset, uint minAmount, uint baseAmount, address recipient) virtual external;
function quoteCollateral(address asset, uint baseAmount) virtual public view returns (uint);

function getCollateralReserves(address asset) virtual public view returns (uint);
function getReserves() virtual public view returns (int);
function getPrice(address priceFeed) virtual public view returns (uint);

function isBorrowCollateralized(address account) virtual public view returns (bool);
function isLiquidatable(address account) virtual public view returns (bool);

function totalSupply() virtual external view returns (uint256);
function totalBorrow() virtual external view returns (uint256);
function balanceOf(address owner) virtual public view returns (uint256);
function borrowBalanceOf(address account) virtual public view returns (uint256);

function pause(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused) virtual external;
function isSupplyPaused() virtual public view returns (bool);
function isTransferPaused() virtual public view returns (bool);
function isWithdrawPaused() virtual public view returns (bool);
function isAbsorbPaused() virtual public view returns (bool);
function isBuyPaused() virtual public view returns (bool);

function accrueAccount(address account) virtual external;
function getSupplyRate(uint utilization) virtual public view returns (uint64);
function getBorrowRate(uint utilization) virtual public view returns (uint64);
function getUtilization() virtual public view returns (uint);

function governor() virtual external view returns (address);
function pauseGuardian() virtual external view returns (address);
function baseToken() virtual external view returns (address);
function baseTokenPriceFeed() virtual external view returns (address);
function extensionDelegate() virtual external view returns (address);

/// @dev uint64
function supplyKink() virtual external view returns (uint);
/// @dev uint64
function supplyPerSecondInterestRateSlopeLow() virtual external view returns (uint);
/// @dev uint64
function supplyPerSecondInterestRateSlopeHigh() virtual external view returns (uint);
/// @dev uint64
function supplyPerSecondInterestRateBase() virtual external view returns (uint);
/// @dev uint64
function borrowKink() virtual external view returns (uint);
/// @dev uint64
function borrowPerSecondInterestRateSlopeLow() virtual external view returns (uint);
/// @dev uint64
function borrowPerSecondInterestRateSlopeHigh() virtual external view returns (uint);
/// @dev uint64
function borrowPerSecondInterestRateBase() virtual external view returns (uint);
/// @dev uint64
function storeFrontPriceFactor() virtual external view returns (uint);

/// @dev uint64
function baseScale() virtual external view returns (uint);
/// @dev uint64
function trackingIndexScale() virtual external view returns (uint);

/// @dev uint64
function baseTrackingSupplySpeed() virtual external view returns (uint);
/// @dev uint64
function baseTrackingBorrowSpeed() virtual external view returns (uint);
/// @dev uint104
function baseMinForRewards() virtual external view returns (uint);
/// @dev uint104
function baseBorrowMin() virtual external view returns (uint);
/// @dev uint104
function targetReserves() virtual external view returns (uint);

function numAssets() virtual external view returns (uint8);
function decimals() virtual external view returns (uint8);

function initializeStorage() virtual external;
}
12 changes: 12 additions & 0 deletions src/interfaces/IUSDC.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

interface IUSDC {
function balanceOf(address account) external view returns (uint256);
function mint(address to, uint256 amount) external;
function configureMinter(
address minter,
uint256 minterAllowedAmount
) external;
function masterMinter() external view returns (address);
}
Loading

0 comments on commit f62766d

Please sign in to comment.