Skip to content

Commit

Permalink
Merge pull request #322 from corpus-io/feature/releaseV5.0.1
Browse files Browse the repository at this point in the history
Feature/release v5.0.1
  • Loading branch information
malteish authored Jan 5, 2024
2 parents c5ae9eb + aba4aab commit 242729b
Show file tree
Hide file tree
Showing 12 changed files with 597 additions and 79 deletions.
2 changes: 1 addition & 1 deletion contracts/factories/Factory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pragma solidity 0.8.23;

abstract contract Factory {
/// The address of the implementation contract
address immutable implementation;
address public immutable implementation;

constructor(address _implementation) {
require(_implementation != address(0), "Factory: implementation can not be zero");
Expand Down
62 changes: 20 additions & 42 deletions contracts/factories/PrivateOfferFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,45 +53,26 @@ contract PrivateOfferFactory {
address _vestingContractOwner,
address trustedForwarder
) external returns (address) {
bytes32 salt = _getSalt(
_rawSalt,
_arguments,
_vestingStart,
_vestingCliff,
_vestingDuration,
_vestingContractOwner
);

// deploy the vesting contract
Vesting vesting = Vesting(
vestingCloneFactory.createVestingClone(salt, trustedForwarder, address(this), address(_arguments.token))
vestingCloneFactory.createVestingCloneWithLockupPlan(
_rawSalt,
trustedForwarder,
_vestingContractOwner,
address(_arguments.token),
_arguments.tokenAmount,
_arguments.tokenReceiver,
_vestingStart,
_vestingCliff,
_vestingDuration
)
);

// create the vesting plan
vesting.createVesting(
_arguments.tokenAmount,
_arguments.tokenReceiver,
_vestingStart,
_vestingCliff,
_vestingDuration,
false
); // this plan is not mintable

vesting.removeManager(address(this));

// transfer ownership of the vesting contract
if (_vestingContractOwner == address(0)) {
// if the owner is 0, the vesting contract will not have an owner. So no one can interfere with the vesting.
vesting.renounceOwnership();
} else {
vesting.transferOwnership(_vestingContractOwner);
}

// deploy the private offer
// update currency receiver to be the vesting contract
PrivateOfferArguments memory calldataArguments = _arguments;
calldataArguments.tokenReceiver = address(vesting);
// update currency receiver to be the vesting contract

// deploy the private offer
address privateOffer = _deployPrivateOffer(_rawSalt, calldataArguments);

require(_arguments.token.balanceOf(address(vesting)) == _arguments.tokenAmount, "Execution failed");
Expand Down Expand Up @@ -120,19 +101,16 @@ contract PrivateOfferFactory {
address _vestingContractOwner,
address trustedForwarder
) public view returns (address, address) {
bytes32 salt = _getSalt(
address vestingAddress = vestingCloneFactory.predictCloneAddressWithLockupPlan(
_rawSalt,
_arguments,
trustedForwarder,
_vestingContractOwner,
address(_arguments.token),
_arguments.tokenAmount,
_arguments.tokenReceiver,
_vestingStart,
_vestingCliff,
_vestingDuration,
_vestingContractOwner
);
address vestingAddress = vestingCloneFactory.predictCloneAddress(
salt,
trustedForwarder,
address(this),
address(_arguments.token)
_vestingDuration
);

// since the vesting contracts address will be used as the token receiver, we need to use it for the prediction
Expand Down
105 changes: 104 additions & 1 deletion contracts/factories/VestingCloneFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ contract VestingCloneFactory is CloneFactory {
address _trustedForwarder,
address _owner,
address _token
) external returns (address) {
) public returns (address) {
bytes32 salt = keccak256(abi.encode(_rawSalt, _trustedForwarder, _owner, _token));
address clone = Clones.cloneDeterministic(implementation, salt);
Vesting vesting = Vesting(clone);
Expand All @@ -36,6 +36,65 @@ contract VestingCloneFactory is CloneFactory {
return clone;
}

/**
* Create a new vesting clone with a lockup plan. The contract ownership can be renounced in the same transaction,
* leaving the contract without an owner and thus without any way to change the vesting plan or add other plans.
* @dev This function creates a transferrable vesting plan.
* @param _rawSalt value that influences the address of the clone, but not the initialization
* @param _trustedForwarder the trusted forwarder (ERC2771) can not be changed, but is checked for security
* @param _owner future owner of the vesting contract. If 0, the contract will not have an owner.
* @param _token token to vest
* @param _allocation amount of tokens to vest
* @param _beneficiary address receiving the tokens
* @param _start start date of the vesting
* @param _cliff cliff duration
* @param _duration total duration
*/
function createVestingCloneWithLockupPlan(
bytes32 _rawSalt,
address _trustedForwarder,
address _owner,
address _token,
uint256 _allocation,
address _beneficiary,
uint64 _start,
uint64 _cliff,
uint64 _duration
) external returns (address) {
// generate salt from all parameters
bytes32 salt = keccak256(
abi.encode(
_rawSalt,
_trustedForwarder,
_owner,
_token,
_allocation,
_beneficiary,
_start,
_cliff,
_duration
)
);
// deploy the vesting contract
Vesting vesting = Vesting(createVestingClone(salt, _trustedForwarder, address(this), _token));

// create the vesting plan
vesting.createVesting(_allocation, _beneficiary, _start, _cliff, _duration, false); // this plan is not mintable

// remove the manager role from the vesting contract
vesting.removeManager(address(this));

// transfer ownership of the vesting contract
if (_owner == address(0)) {
// if the owner is 0, the vesting contract will not have an owner. So no one can interfere with the vesting.
vesting.renounceOwnership();
} else {
vesting.transferOwnership(_owner);
}

return address(vesting);
}

/**
* Calculate the address a clone will have using the given parameters
* @param _rawSalt value that influences the address of the clone, but not the initialization
Expand All @@ -56,4 +115,48 @@ contract VestingCloneFactory is CloneFactory {
bytes32 salt = keccak256(abi.encode(_rawSalt, _trustedForwarder, _owner, _token));
return Clones.predictDeterministicAddress(implementation, salt);
}

/**
* Calculate the address a clone will have using the given parameters of the contract and the lockup plan
* @param _rawSalt value that influences the address of the clone, but not the initialization
* @param _trustedForwarder the trusted forwarder (ERC2771) can not be changed, but is checked for security
* @param _owner future owner of the vesting contract. If 0, the contract will not have an owner.
* @param _token token to vest
* @param _allocation amount of tokens to vest
* @param _beneficiary address receiving the tokens
* @param _start start date of the vesting
* @param _cliff cliff duration
* @param _duration total duration
*/
function predictCloneAddressWithLockupPlan(
bytes32 _rawSalt,
address _trustedForwarder,
address _owner,
address _token,
uint256 _allocation,
address _beneficiary,
uint64 _start,
uint64 _cliff,
uint64 _duration
) external view returns (address) {
require(
Vesting(implementation).isTrustedForwarder(_trustedForwarder),
"VestingCloneFactory: Unexpected trustedForwarder"
);
bytes32 salt = keccak256(
abi.encode(
_rawSalt,
_trustedForwarder,
_owner,
_token,
_allocation,
_beneficiary,
_start,
_cliff,
_duration
)
);
salt = keccak256(abi.encode(salt, _trustedForwarder, address(this), _token));
return Clones.predictDeterministicAddress(implementation, salt);
}
}
6 changes: 6 additions & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ optimizer: {
},
```

#### Verify ERC1967Proxy

```
npx hardhat verify --network goerli 0x676Fae4c5b791D6Cb2732C27ec794c6378ABbC04 --constructor-args script/verificationArguments/hardhat/ERC1967Proxy.js
```

### foundry

Example for token verification:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tokenize.it/contracts",
"version": "5.0.0",
"version": "5.0.1",
"description": "Tokenize.it smart contracts for company tokenization, crowdinvesting, private offers and employee participation",
"keywords": [
"evm",
Expand Down
Loading

0 comments on commit 242729b

Please sign in to comment.