Skip to content

Commit

Permalink
feat: Add VestingWallet (#402)
Browse files Browse the repository at this point in the history
<!--
Thank you for your interest in contributing to OpenZeppelin!

Consider opening an issue for discussion prior to submitting a PR. New
features will be merged faster if they were first discussed and designed
with the team.

Describe the changes introduced in this pull request. Include any
context necessary for understanding the PR's purpose.
-->

<!-- Fill in with issue number -->
Resolves #348 

#### PR Checklist

<!--
Before merging the pull request all of the following must be completed.
Feel free to submit a PR or Draft PR even if some items are pending.
Some of the items may not apply.
-->

- [x] Unit Tests
- [x] E2E Tests
- [x] Documentation

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Daniel Bigos <[email protected]>
Co-authored-by: Alisander Qoshqosh <[email protected]>
  • Loading branch information
4 people authored Nov 28, 2024
1 parent e43ab6b commit 1244d38
Show file tree
Hide file tree
Showing 21 changed files with 1,430 additions and 16 deletions.
14 changes: 4 additions & 10 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- `IErc1155Burnable` extension. #417
- `VestingWallet` contract. #402
- `Erc1155Burnable` extension. #417

### Changed

- Use `function_selector!` to calculate transfer type selector in `Erc1155`. #417
- Implement `MethodError` for `safe_erc20::Error`. #402
- Use `function_selector!` to calculate transfer type selector in `Erc1155`. #417

### Fixed

Expand All @@ -33,14 +35,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Removed `only_owner` from the public interface of `Ownable`. #352

### Changed

-

### Fixed

-

## [0.1.1] - 2024-10-28

### Changed
Expand Down
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ members = [
"examples/erc1155",
"examples/merkle-proofs",
"examples/ownable",
"examples/vesting-wallet",
"examples/access-control",
"examples/basic/token",
"examples/basic/script",
Expand All @@ -39,6 +40,7 @@ default-members = [
"examples/safe-erc20",
"examples/merkle-proofs",
"examples/ownable",
"examples/vesting-wallet",
"examples/ownable-two-step",
"examples/access-control",
"examples/basic/token",
Expand Down
2 changes: 1 addition & 1 deletion GUIDELINES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Setup

1. Install [Docker].
1. Install the [Solidity Compiler] version `0.8.24`
1. Install the [Solidity Compiler] version `0.8.24`.
(NOTE: it is important to use this exact version to avoid compatibility issues).
1. Install toolchain providing `cargo` using [rustup].
1. Install the cargo stylus tool with `cargo install --force cargo-stylus`.
Expand Down
2 changes: 2 additions & 0 deletions benches/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub mod erc721;
pub mod merkle_proofs;
pub mod ownable;
pub mod report;
pub mod vesting_wallet;

#[derive(Debug, Deserialize)]
struct ArbOtherFields {
Expand All @@ -32,6 +33,7 @@ struct ArbOtherFields {

/// Cache options for the contract.
/// `Bid(0)` will likely cache the contract on the nitro test node.
#[derive(Clone)]
pub enum CacheOpt {
None,
Bid(u32),
Expand Down
132 changes: 132 additions & 0 deletions benches/src/vesting_wallet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
use alloy::{
network::{AnyNetwork, EthereumWallet},
primitives::Address,
providers::ProviderBuilder,
sol,
sol_types::{SolCall, SolConstructor},
uint,
};
use alloy_primitives::U256;
use e2e::{receipt, Account};

use crate::{
report::{ContractReport, FunctionReport},
CacheOpt,
};

sol!(
#[sol(rpc)]
contract VestingWallet {
function owner() public view virtual returns (address owner);
function receiveEther() external payable virtual;
function start() external view returns (uint256 start);
function duration() external view returns (uint256 duration);
function end() external view returns (uint256 end);
function released() external view returns (uint256 released);
function released(address token) external view returns (uint256 released);
function releasable() external view returns (uint256 releasable);
function releasable(address token) external view returns (uint256 releasable);
function release() external;
function release(address token) external;
function vestedAmount(uint64 timestamp) external view returns (uint256 vestedAmount);
function vestedAmount(address token, uint64 timestamp) external view returns (uint256 vestedAmount);
}

#[sol(rpc)]
contract Erc20 {
function mint(address account, uint256 amount) external;
}
);

sol!("../examples/vesting-wallet/src/constructor.sol");
sol!("../examples/erc20/src/constructor.sol");

const START_TIMESTAMP: u64 = 1000;
const DURATION_SECONDS: u64 = 1000;

const TOKEN_NAME: &str = "Test Token";
const TOKEN_SYMBOL: &str = "TTK";
const CAP: U256 = uint!(1_000_000_U256);

pub async fn bench() -> eyre::Result<ContractReport> {
let reports = run_with(CacheOpt::None).await?;
let report = reports
.into_iter()
.try_fold(ContractReport::new("VestingWallet"), ContractReport::add)?;

let cached_reports = run_with(CacheOpt::Bid(0)).await?;
let report = cached_reports
.into_iter()
.try_fold(report, ContractReport::add_cached)?;

Ok(report)
}

pub async fn run_with(
cache_opt: CacheOpt,
) -> eyre::Result<Vec<FunctionReport>> {
let alice = Account::new().await?;
let alice_wallet = ProviderBuilder::new()
.network::<AnyNetwork>()
.with_recommended_fillers()
.wallet(EthereumWallet::from(alice.signer.clone()))
.on_http(alice.url().parse()?);

let contract_addr = deploy(&alice, cache_opt.clone()).await?;
let erc20_addr = deploy_token(&alice, cache_opt).await?;

let contract = VestingWallet::new(contract_addr, &alice_wallet);
let erc20 = Erc20::new(erc20_addr, &alice_wallet);

let _ = receipt!(contract.receiveEther().value(uint!(1000_U256)))?;
let _ = receipt!(erc20.mint(contract_addr, uint!(1000_U256)))?;

// IMPORTANT: Order matters!
use VestingWallet::*;
#[rustfmt::skip]
let receipts = vec![
(receiveEtherCall::SIGNATURE, receipt!(contract.receiveEther())?),
(startCall::SIGNATURE, receipt!(contract.start())?),
(durationCall::SIGNATURE, receipt!(contract.duration())?),
(endCall::SIGNATURE, receipt!(contract.end())?),
(released_0Call::SIGNATURE, receipt!(contract.released_0())?),
(released_1Call::SIGNATURE, receipt!(contract.released_1(erc20_addr))?),
(releasable_0Call::SIGNATURE, receipt!(contract.releasable_0())?),
(releasable_1Call::SIGNATURE, receipt!(contract.releasable_1(erc20_addr))?),
(release_0Call::SIGNATURE, receipt!(contract.release_0())?),
(release_1Call::SIGNATURE, receipt!(contract.release_1(erc20_addr))?),
(vestedAmount_0Call::SIGNATURE, receipt!(contract.vestedAmount_0(START_TIMESTAMP))?),
(vestedAmount_1Call::SIGNATURE, receipt!(contract.vestedAmount_1(erc20_addr, START_TIMESTAMP))?),
];

receipts
.into_iter()
.map(FunctionReport::new)
.collect::<eyre::Result<Vec<_>>>()
}

async fn deploy(
account: &Account,
cache_opt: CacheOpt,
) -> eyre::Result<Address> {
let args = VestingWalletExample::constructorCall {
beneficiary: account.address(),
startTimestamp: START_TIMESTAMP,
durationSeconds: DURATION_SECONDS,
};
let args = alloy::hex::encode(args.abi_encode());
crate::deploy(account, "vesting-wallet", Some(args), cache_opt).await
}

async fn deploy_token(
account: &Account,
cache_opt: CacheOpt,
) -> eyre::Result<Address> {
let args = Erc20Example::constructorCall {
name_: TOKEN_NAME.to_owned(),
symbol_: TOKEN_SYMBOL.to_owned(),
cap_: CAP,
};
let args = alloy::hex::encode(args.abi_encode());
crate::deploy(account, "erc20", Some(args), cache_opt).await
}
2 changes: 2 additions & 0 deletions contracts/src/finance/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
//! Primitives for financial systems.
pub mod vesting_wallet;
Loading

0 comments on commit 1244d38

Please sign in to comment.