Skip to content

feat: Release v2.0.0 #1

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

Merged
merged 4 commits into from
Dec 11, 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
28 changes: 25 additions & 3 deletions .github/workflows/forge-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ name: Forge Tests (PR)
on: [pull_request]

jobs:
run-ci:
test:
name: Test with "deep" profile
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand All @@ -18,8 +19,8 @@ jobs:
git config --global url."https://github.com/".insteadOf "[email protected]:"
git submodule update --init --recursive

- name: Run forge tests
run: forge test
- name: Run Forge tests
run: ./scripts/test.sh -p deep

coverage_report:
name: Generate coverage report
Expand All @@ -39,6 +40,8 @@ jobs:
- name: Generate coverage report
run: |
forge coverage --report lcov
sudo apt-get install lcov
lcov --remove lcov.info -o lcov.info 'tests/*'
- name: Report code coverage
uses: zgosalvez/github-actions-report-lcov@v1
with:
Expand All @@ -47,3 +50,22 @@ jobs:
artifact-name: code-coverage-report
github-token: ${{ secrets.GITHUB_TOKEN }}
working-directory: ./

size_check:
name: Check contracts sizes
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

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

- name: Install submodules
run: |
git config --global url."https://github.com/".insteadOf "[email protected]:"
git submodule update --init --recursive

- name: Check contract sizes
run: ./scripts/check-sizes.sh
31 changes: 26 additions & 5 deletions .github/workflows/forge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ name: Forge Tests

on:
push:
branches:
- main
branches: [main]

jobs:
run-ci:
test:
name: Test with "deep" profile
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand All @@ -21,8 +21,8 @@ jobs:
git config --global url."https://github.com/".insteadOf "[email protected]:"
git submodule update --init --recursive

- name: Run forge tests
run: forge test
- name: Run Forge tests
run: ./scripts/test.sh -p super_deep

coverage_report:
name: Generate coverage report
Expand All @@ -42,6 +42,8 @@ jobs:
- name: Generate coverage report
run: |
forge coverage --report lcov
sudo apt-get install lcov
lcov --remove lcov.info -o lcov.info 'tests/*'
- name: Report code coverage
uses: zgosalvez/github-actions-report-lcov@v1
with:
Expand All @@ -50,3 +52,22 @@ jobs:
artifact-name: code-coverage-report
github-token: ${{ secrets.GITHUB_TOKEN }}
working-directory: ./

size_check:
name: Check contracts sizes
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

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

- name: Install submodules
run: |
git config --global url."https://github.com/".insteadOf "[email protected]:"
git submodule update --init --recursive

- name: Check contract sizes
run: ./scripts/check-sizes.sh
20 changes: 5 additions & 15 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
install:
@git submodule update --init --recursive

update:
@forge update

# Build and test

profile ?=default

build:
@FOUNDRY_PROFILE=production forge build
@scripts/build.sh -p production

release:
@scripts/release.sh

test:
forge test
size:
@scripts/check-sizes.sh

clean:
@forge clean
test:
@scripts/test.sh -p default
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ forge install
| Spearbit Auditors via Cantina | [`2023-06-05 - Cantina Report`](https://docs.google.com/viewer?url=https://github.com/maple-labs/maple-v2-audits/files/11667848/cantina-maple.pdf) |
| Three Sigma | [`2023-04-10 - Three Sigma Report`](https://docs.google.com/viewer?url=https://github.com/maple-labs/maple-v2-audits/files/11663546/maple-v2-audit_three-sigma_2023.pdf) |

### August 2024 Release
| Auditor | Report Link |
|---|---|
| 0xMacro | [`2024-08-14 - 0xMacro Report`](https://github.com/maple-labs/syrup-utils/blob/main/audits/0xMacro-Maple-Finance-Aug-2024.pdf) |
| Three Sigma | [`2024-08-23 - Three Sigma Report`](https://github.com/maple-labs/syrup-utils/blob/main/audits/ThreeSigma-Maple-Finance-Aug-2024.pdf) |

## Bug Bounty

Expand Down
2 changes: 0 additions & 2 deletions configs/package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ packages:
contractName: MapleLoanFactory
- path: contracts/MapleLoanInitializer.sol
contractName: MapleLoanInitializer
- path: contracts/MapleLoanStorage.sol
contractName: MapleLoanStorage
- path: contracts/MapleRefinancer.sol
contractName: MapleRefinancer
customDescription: Maple Open Term Loan Artifacts and ABIs
14 changes: 12 additions & 2 deletions contracts/MapleLoan.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { MapleLoanStorage } from "./MapleLoanStorage.sol";
██║ ╚═╝ ██║██║ ██║██║ ███████╗███████╗
╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚══════╝╚══════╝


██████╗ ██████╗ ███████╗███╗ ██╗ ████████╗███████╗██████╗ ███╗ ███╗ ██╗ ██████╗ █████╗ ███╗ ██╗ ██╗ ██╗ ██╗
██╔═══██╗██╔══██╗██╔════╝████╗ ██║ ╚══██╔══╝██╔════╝██╔══██╗████╗ ████║ ██║ ██╔═══██╗██╔══██╗████╗ ██║ ██║ ██║███║
██║ ██║██████╔╝█████╗ ██╔██╗ ██║ ██║ █████╗ ██████╔╝██╔████╔██║ ██║ ██║ ██║███████║██╔██╗ ██║ ██║ ██║╚██║
Expand Down Expand Up @@ -84,6 +85,14 @@ contract MapleLoan is IMapleLoan, MapleProxiedInternals, MapleLoanStorage {
emit BorrowerAccepted(borrower = msg.sender);
}

function acceptLoanTerms() external override whenNotPaused onlyBorrower {
require(!loanTermsAccepted, "ML:ALT:ALREADY_ACCEPTED");

loanTermsAccepted = true;

emit LoanTermsAccepted();
}

function acceptNewTerms(address refinancer_, uint256 deadline_, bytes[] calldata calls_)
external override whenNotPaused onlyBorrower returns (bytes32 refinanceCommitment_)
{
Expand Down Expand Up @@ -266,8 +275,9 @@ contract MapleLoan is IMapleLoan, MapleProxiedInternals, MapleLoanStorage {
}

function fund() external override whenNotPaused onlyLender returns (uint256 fundsLent_, uint40 paymentDueDate_, uint40 defaultDate_) {
require(dateFunded == 0, "ML:F:LOAN_ACTIVE");
require(principal != 0, "ML:F:LOAN_CLOSED");
require(loanTermsAccepted, "ML:F:TERMS_NOT_ACCEPTED");
require(dateFunded == 0, "ML:F:LOAN_ACTIVE");
require(principal != 0, "ML:F:LOAN_CLOSED");

dateFunded = _uint40(block.timestamp);

Expand Down
2 changes: 2 additions & 0 deletions contracts/MapleLoanStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ abstract contract MapleLoanStorage is IMapleLoanStorage {
uint64 public override lateInterestPremiumRate; // The amount to increase the interest rate by for late payments.
uint64 public override platformServiceFeeRate; // The annualized platform service fee rate.

bool public override loanTermsAccepted; // The state of the borrower's acceptance of the loan terms.

}
2 changes: 1 addition & 1 deletion contracts/MapleRefinancer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { MapleLoanStorage } from "./MapleLoanStorage.sol";

*/

/// @title Refinancer uses storage from a MapleLoan defined by MapleLoanStorage.
/// @title MapleRefinancer uses storage from a MapleLoan defined by MapleLoanStorage.
contract MapleRefinancer is IMapleRefinancer, MapleLoanStorage {

function decreasePrincipal(uint256 amount_) external override {
Expand Down
5 changes: 5 additions & 0 deletions contracts/interfaces/IMapleLoan.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ interface IMapleLoan is IMapleProxied, IMapleLoanEvents, IMapleLoanStorage {
*/
function acceptLender() external;

/**
* @dev Accept the loan terms, must be called by the borrower.
*/
function acceptLoanTerms() external;

/**
* @dev Accept the proposed terms and trigger refinance execution.
* @param refinancer_ The address of the refinancer contract.
Expand Down
5 changes: 5 additions & 0 deletions contracts/interfaces/IMapleLoanEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ interface IMapleLoanEvents {
*/
event LenderAccepted(address indexed lender_);

/**
* @dev The loan terms were accepted by the borrower.
*/
event LoanTermsAccepted();

/**
* @dev The terms of the refinance proposal were accepted.
* @param refinanceCommitment_ The hash of the refinancer, deadline, and calls proposed.
Expand Down
5 changes: 5 additions & 0 deletions contracts/interfaces/IMapleLoanStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ interface IMapleLoanStorage {
*/
function lender() external view returns (address lender_);

/**
* @dev Whether the loan terms have been accepted by the borrower.
*/
function loanTermsAccepted() external view returns (bool loanTermsAccepted_);

/**
* @dev The amount of time the borrower has, after the loan is called, to make a payment, paying back the called principal.
*/
Expand Down
10 changes: 5 additions & 5 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ contracts = 'contracts' # The contract directory
test = 'tests' # The test directory
libs = ['modules'] # A list of library directories
solc_version = '0.8.7' # Override for the solc version (setting this ignores `auto_detect_solc`)
optimizer = true # Enable or disable the solc optimizer
optimizer_runs = 200 # The number of optimizer runs
optimizer = false # Enable or disable the solc optimizer
verbosity = 3 # The verbosity of tests
block_timestamp = 1_622_400_000 # Timestamp for tests (non-zero)
fuzz_runs = 100 # Number of fuzz runs

[profile.deep]
fuzz_runs = 1000

[profile.super_deep]
fuzz_runs = 50000

[profile.release]
optimizer = true # Enable or disable the solc optimizer
optimizer_runs = 200 # The number of optimizer runs
[profile.production]
optimizer = true # Enable or disable the solc optimizer
optimizer_runs = 200 # The number of optimizer runs
6 changes: 2 additions & 4 deletions package.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: open-term-loan
version: 0.0.1
version: 1.0.1
source: contracts
packages:
- path: contracts/MapleLoan.sol
Expand All @@ -8,8 +8,6 @@ packages:
contractName: MapleLoanFactory
- path: contracts/MapleLoanInitializer.sol
contractName: MapleLoanInitializer
- path: contracts/MapleLoanStorage.sol
contractName: MapleLoanStorage
- path: contracts/MapleRefinancer.sol
contractName: MapleRefinancer
customDescription: Maple Loan Artifacts and ABIs
customDescription: Maple Open Term Loan Artifacts and ABIs
33 changes: 33 additions & 0 deletions scripts/check-sizes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash

while getopts p: flag
do
case "${flag}" in
p) profile=${OPTARG};;
esac
done

export FOUNDRY_PROFILE=production

sizes=$(forge build --sizes)

names=($(cat ./configs/package.yaml | grep " contractName:" | sed -r 's/.{18}//'))

fail=false

for i in "${!names[@]}"; do
line=$(echo "$sizes" | grep -w "${names[i]}")

if [[ $line == *"-"* ]]; then
echo "${names[i]} is too large"
fail=true
fi
done

if $fail
then
echo "Contract size check failed"
exit 1
else
echo "Contract size check passed"
fi
2 changes: 1 addition & 1 deletion scripts/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ version=$(cat ./configs/package.yaml | grep "version: " | sed -r 's/.{9}//')
name=$(cat ./configs/package.yaml | grep "name: " | sed -r 's/.{6}//')
customDescription=$(cat ./configs/package.yaml | grep "customDescription: " | sed -r 's/.{19}//')

./scripts/build.sh -p release
./scripts/build.sh -p production

rm -rf ./package
mkdir -p package
Expand Down
58 changes: 58 additions & 0 deletions tests/AcceptLoanTerms.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.7;

import { Test } from "../modules/forge-std/src/Test.sol";

import { MapleLoanHarness } from "./utils/Harnesses.sol";
import { MockFactory, MockGlobals } from "./utils/Mocks.sol";

contract AcceptLoanTermsTests is Test {

event LoanTermsAccepted();

address account = makeAddr("account");

MapleLoanHarness loan = new MapleLoanHarness();
MockFactory factory = new MockFactory();
MockGlobals globals = new MockGlobals();

function setUp() external {
factory.__setGlobals(address(globals));

loan.__setFactory(address(factory));
loan.__setBorrower(account);
}

function test_acceptLoanTerms_paused() external {
globals.__setFunctionPaused(true);

vm.expectRevert("ML:PAUSED");
loan.acceptLoanTerms();
}

function test_acceptLoanTerms_notBorrower() external {
vm.expectRevert("ML:NOT_BORROWER");
loan.acceptLoanTerms();
}

function test_acceptLoanTerms_alreadyAccepted() external {
loan.__setLoanTermsAccepted(true);

vm.prank(account);
vm.expectRevert("ML:ALT:ALREADY_ACCEPTED");
loan.acceptLoanTerms();
}

function test_acceptLoanTerms_success() external {
assertTrue(!loan.loanTermsAccepted());

vm.expectEmit();
emit LoanTermsAccepted();

vm.prank(account);
loan.acceptLoanTerms();

assertTrue(loan.loanTermsAccepted());
}

}
Loading
Loading