Smart Deployer
Smart Deployer is a universal architecture for organizing and managing paid smart contract deployments.
This solution allows developers to:
- Create their own Smart Deployer (DeployManager.sol)
- Create & connect utility contracts using template
- Monetize the deployment of utility contracts
The repository is currently under development. We are building it as part of the Solidity University Bootcamp program.
👉 More details: bootcamp.solidity.university
Contents
DeployManager
Inherits: IDeployManager, Ownable, ERC165
Author: Solidity University
Allows users to deploy utility contracts by cloning registered templates.
Uses OpenZeppelin's Clones and Ownable; assumes templates implement IUtilityContract.
State Variables
deployedContracts
mapping(address => address[]) public deployedContracts;
contractsData
mapping(address => ContractInfo) public contractsData;
Functions
constructor
constructor() payable Ownable(msg.sender);
deploy
Deploys a new utility contract
Emits NewDeployment event
function deploy(address _utilityContract, bytes calldata _initData) external payable override returns (address);
Parameters
Name | Type | Description |
---|---|---|
_utilityContract | address | The address of the utility contract template |
_initData | bytes | The initialization data for the utility contract |
Returns
Name | Type | Description |
---|---|---|
<none> | address | The address of the deployed utility contract |
addNewContract
function addNewContract(address _contractAddress, uint256 _fee, bool _isActive) external override onlyOwner;
updateFee
function updateFee(address _contractAddress, uint256 _newFee) external override onlyOwner;
deactivateContract
function deactivateContract(address _address) external override onlyOwner;
activateContract
function activateContract(address _address) external override onlyOwner;
supportsInterface
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool);
Structs
ContractInfo
struct ContractInfo {
uint256 fee;
bool isActive;
uint256 registredAt;
}
IDeployManager
Inherits: IERC165
Author: Solidity Univesity
This interface defines the functions, errors and events for the DeployManager contract.
Functions
deploy
Deploys a new utility contract
Emits NewDeployment event
function deploy(address _utilityContract, bytes calldata _initData) external payable returns (address);
Parameters
Name | Type | Description |
---|---|---|
_utilityContract | address | The address of the utility contract template |
_initData | bytes | The initialization data for the utility contract |
Returns
Name | Type | Description |
---|---|---|
<none> | address | The address of the deployed utility contract |
addNewContract
function addNewContract(address _contractAddress, uint256 _fee, bool _isActive) external;
updateFee
function updateFee(address _contractAddress, uint256 _newFee) external;
deactivateContract
function deactivateContract(address _contractAddress) external;
activateContract
function activateContract(address _contractAddress) external;
Events
NewContractAdded
Emitted when a new utility contract template is registered.
event NewContractAdded(address indexed _contractAddress, uint256 _fee, bool _isActive, uint256 _timestamp);
Parameters
Name | Type | Description |
---|---|---|
_contractAddress | address | Address of the registered utility contract template. |
_fee | uint256 | Fee (in wei) required to deploy a clone of this contract. |
_isActive | bool | Whether the contract is active and deployable. |
_timestamp | uint256 | Timestamp when the contract was added. |
ContractFeeUpdated
event ContractFeeUpdated(address indexed _contractAddress, uint256 _oldFee, uint256 _newFee, uint256 _timestamp);
ContractStatusUpdated
event ContractStatusUpdated(address indexed _contractAddress, bool _isActive, uint256 _timestamp);
NewDeployment
event NewDeployment(address indexed _deployer, address indexed _contractAddress, uint256 _fee, uint256 _timestamp);
Errors
ContractNotActive
Reverts if the contract is not active
error ContractNotActive();
NotEnoughtFunds
Not enough funds to deploy the contract
error NotEnoughtFunds();
ContractDoesNotRegistered
Reverts if the contract is not registered
error ContractDoesNotRegistered();
InitializationFailed
Reverts if the .initialize() function fails
error InitializationFailed();
ContractIsNotUtilityContract
Reverts if the contract is not a utility contract
error ContractIsNotUtilityContract();
Contents
ERC1155Airdroper
Inherits: AbstractUtilityContract, Ownable
State Variables
MAX_AIRDROP_BATCH_SIZE
uint256 public constant MAX_AIRDROP_BATCH_SIZE = 10;
token
IERC1155 public token;
treasury
address public treasury;
Functions
constructor
constructor() payable Ownable(msg.sender);
airdrop
function airdrop(address[] calldata receivers, uint256[] calldata amounts, uint256[] calldata tokenIds)
external
onlyOwner;
initialize
function initialize(bytes memory _initData) external override notInitialized returns (bool);
getInitData
function getInitData(address _deployManager, address _token, address _treasury, address _owner)
external
pure
returns (bytes memory);
Errors
ReceiversLengthMismatch
error ReceiversLengthMismatch();
AmountsLengthMismatch
error AmountsLengthMismatch();
BatchSizeExceeded
error BatchSizeExceeded();
NeedToApproveTokens
error NeedToApproveTokens();
Contents
ERC20Airdroper
Inherits: AbstractUtilityContract, Ownable
Author: Solidity University
This contract allows the owner to airdrop ERC20 tokens to multiple addresses.
Inherits from AbstractUtilityContract and Ownable
State Variables
MAX_AIRDROP_BATCH_SIZE
uint256 public constant MAX_AIRDROP_BATCH_SIZE = 300;
token
IERC20 public token;
amount
uint256 public amount;
treasury
address public treasury;
Functions
constructor
constructor() payable Ownable(msg.sender);
airdrop
function airdrop(address[] calldata receivers, uint256[] calldata amounts) external onlyOwner;
initialize
function initialize(bytes memory _initData) external override notInitialized returns (bool);
getInitData
function getInitData(address _deployManager, address _token, uint256 _amount, address _treasury, address _owner)
external
pure
returns (bytes memory);
Errors
ArraysLengthMismatch
error ArraysLengthMismatch();
NotEnoughApprovedTokens
error NotEnoughApprovedTokens();
TransferFailed
error TransferFailed();
BatchSizeExceeded
error BatchSizeExceeded();
Contents
ERC721Airdroper
Inherits: AbstractUtilityContract, Ownable
State Variables
MAX_AIRDROP_BATCH_SIZE
uint256 public constant MAX_AIRDROP_BATCH_SIZE = 300;
token
IERC721 public token;
treasury
address public treasury;
Functions
constructor
constructor() payable Ownable(msg.sender);
airdrop
function airdrop(address[] calldata receivers, uint256[] calldata tokenIds) external onlyOwner;
initialize
function initialize(bytes memory _initData) external override notInitialized returns (bool);
getInitData
function getInitData(address _deployManager, address _token, address _treasury, address _owner)
external
pure
returns (bytes memory);
Errors
ArraysLengthMismatch
error ArraysLengthMismatch();
NeedToApproveTokens
error NeedToApproveTokens();
BatchSizeExceeded
error BatchSizeExceeded();
Contents
AbstractUtilityContract
Inherits: IUtilityContract, ERC165
Author: Solidity University
This abstract contract provides a base implementation for utility contracts.
Utility contracts should inherit from this contract and implement the initialize function.
State Variables
initialized
bool public initialized;
deployManager
address public deployManager;
Functions
notInitialized
modifier notInitialized();
initialize
function initialize(bytes memory _initData) external virtual override returns (bool);
setDeployManager
function setDeployManager(address _deployManager) internal virtual;
validateDeployManager
function validateDeployManager(address _deployManager) internal view returns (bool);
getDeployManager
function getDeployManager() external view virtual override returns (address);
supportsInterface
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool);
IUtilityContract
Inherits: IERC165
Author: Solidity University
This interface defines the functions and events for utility contracts.
Utility contracts should implement this interface to be compatible with the DeployManager.
Functions
initialize
Initializes the utility contract with the provided data
This function should be called by the DeployManager after deploying the contract
function initialize(bytes memory _initData) external returns (bool);
Parameters
Name | Type | Description |
---|---|---|
_initData | bytes | The initialization data for the utility contract |
Returns
Name | Type | Description |
---|---|---|
<none> | bool | True if the initialization was successful |
getDeployManager
function getDeployManager() external view returns (address);
Errors
DeployManagerCannotBeZero
Reverts if the deploy manager is not set or is invalid
error DeployManagerCannotBeZero();
NotDeployManager
error NotDeployManager();
FailedToDeployManager
error FailedToDeployManager();
AlreadyInitialized
error AlreadyInitialized();
Contents
IVesting
Provides a standard interface for token vesting contracts
Functions
claim
Claims all tokens currently available for the caller according to their vesting schedule
function claim() external;
startVesting
Creates a new vesting schedule for a beneficiary
function startVesting(VestingParams calldata params) external;
Parameters
Name | Type | Description |
---|---|---|
params | VestingParams | Struct containing the parameters for the new vesting schedule |
vestedAmount
Returns the total amount of tokens vested for a beneficiary at the current time
function vestedAmount(address _claimer) external view returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
_claimer | address | Address of the beneficiary |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | Amount of tokens vested |
claimableAmount
Returns the amount of tokens that can currently be claimed by a beneficiary
function claimableAmount(address _claimer) external view returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
_claimer | address | Address of the beneficiary |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | Amount of tokens claimable |
withdrawUnallocated
Withdraws all unallocated tokens from the contract to the specified address
function withdrawUnallocated(address _to) external;
Parameters
Name | Type | Description |
---|---|---|
_to | address | Address to receive the withdrawn tokens |
getVestingInfo
Returns the information about a vesting schedule for a beneficiary
function getVestingInfo(address _claimer) external view returns (VestingInfo memory);
Parameters
Name | Type | Description |
---|---|---|
_claimer | address | Address of the beneficiary |
Returns
Name | Type | Description |
---|---|---|
<none> | VestingInfo | VestingInfo struct containing the vesting information |
getInitData
Returns the ABI-encoded initialization data for the contract
function getInitData(address _deployManager, address _token, address _owner) external view returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
_deployManager | address | Address of the deploy manager |
_token | address | Address of the ERC20 token |
_owner | address | Address of the contract owner |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | ABI-encoded initialization data |
Events
VestingCreated
Emitted when a new vesting schedule is created
event VestingCreated(address indexed beneficiary, uint256 amount, uint256 creationTime);
Parameters
Name | Type | Description |
---|---|---|
beneficiary | address | Address of the beneficiary |
amount | uint256 | Total number of tokens to be vested |
creationTime | uint256 | Timestamp when the vesting schedule was created |
TokensWithdrawn
Emitted when tokens are withdrawn from the contract
event TokensWithdrawn(address indexed to, uint256 amount);
Parameters
Name | Type | Description |
---|---|---|
to | address | Address receiving the withdrawn tokens |
amount | uint256 | Number of tokens withdrawn |
Claim
Emitted when a beneficiary claims vested tokens
event Claim(address indexed beneficiary, uint256 amount, uint256 timestamp);
Parameters
Name | Type | Description |
---|---|---|
beneficiary | address | Address of the beneficiary |
amount | uint256 | Number of tokens claimed |
timestamp | uint256 | Timestamp when the claim was made |
Errors
VestingNotFound
Reverts if the vesting schedule does not exist for the beneficiary
error VestingNotFound();
ClaimNotAvailable
Reverts if the claim is not yet available
error ClaimNotAvailable(uint256 blockTimestamp, uint256 availableFrom);
Parameters
Name | Type | Description |
---|---|---|
blockTimestamp | uint256 | Current block timestamp |
availableFrom | uint256 | Timestamp when the claim becomes available |
NothingToClaim
Reverts if there are no tokens available to claim
error NothingToClaim();
InfsufficientBalance
Reverts if the contract does not have enough tokens to allocate
error InfsufficientBalance(uint256 availableBalance, uint256 totalAmount);
Parameters
Name | Type | Description |
---|---|---|
availableBalance | uint256 | Number of tokens currently available in the contract |
totalAmount | uint256 | Number of tokens required for vesting |
VestingAlreadyExist
Reverts if a vesting schedule already exists for the beneficiary
error VestingAlreadyExist();
AmountCantBeZero
Reverts if the specified amount is zero
error AmountCantBeZero();
StartTimeShouldBeFuture
Reverts if the vesting start time is not in the future
error StartTimeShouldBeFuture(uint256 startTime, uint256 blockTimestamp);
Parameters
Name | Type | Description |
---|---|---|
startTime | uint256 | The specified start time |
blockTimestamp | uint256 | The current block timestamp |
DurationCantBeZero
Reverts if the vesting duration is zero
error DurationCantBeZero();
CooldownCantBeLongerThanDuration
Reverts if the claim cooldown period is longer than the vesting duration
error CooldownCantBeLongerThanDuration();
InvalidBeneficiary
Reverts if the beneficiary address is invalid
error InvalidBeneficiary();
BelowMinimalClaimAmount
Reverts if the claimable amount is less than the minimum claim amount
error BelowMinimalClaimAmount(uint256 minClaimAmount, uint256 claimable);
Parameters
Name | Type | Description |
---|---|---|
minClaimAmount | uint256 | The minimum claimable amount |
claimable | uint256 | The actual claimable amount |
CooldownNotPassed
Reverts if the required cooldown period between claims has not passed
error CooldownNotPassed(uint256 blockTimestamp, uint256 lastClaimTime);
Parameters
Name | Type | Description |
---|---|---|
blockTimestamp | uint256 | The current block timestamp |
lastClaimTime | uint256 | The timestamp of the last claim |
NothingToWithdraw
Reverts if there are no tokens available to withdraw
error NothingToWithdraw();
Structs
VestingInfo
Information about a beneficiary's vesting schedule
struct VestingInfo {
uint256 totalAmount;
uint256 startTime;
uint256 cliff;
uint256 duration;
uint256 claimed;
uint256 lastClaimTime;
uint256 claimCooldown;
uint256 minClaimAmount;
bool created;
}
Properties
Name | Type | Description |
---|---|---|
totalAmount | uint256 | Total number of tokens to be vested |
startTime | uint256 | Timestamp when vesting begins |
cliff | uint256 | Duration of the cliff period in seconds |
duration | uint256 | Total duration of the vesting period in seconds |
claimed | uint256 | Amount of tokens already claimed |
lastClaimTime | uint256 | Timestamp of the last claim |
claimCooldown | uint256 | Minimum time interval between claims in seconds |
minClaimAmount | uint256 | Minimum amount that can be claimed in a single transaction |
created | bool | Indicates whether the vesting schedule has been created |
VestingParams
Parameters for creating a new vesting schedule in startVesting function
struct VestingParams {
address beneficiary;
uint256 totalAmount;
uint256 startTime;
uint256 cliff;
uint256 duration;
uint256 claimCooldown;
uint256 minClaimAmount;
}
Properties
Name | Type | Description |
---|---|---|
beneficiary | address | Address that will receive vested tokens |
totalAmount | uint256 | Total number of tokens to be vested |
startTime | uint256 | Timestamp when vesting begins |
cliff | uint256 | Duration of the cliff period in seconds |
duration | uint256 | Total duration of the vesting period in seconds |
claimCooldown | uint256 | Minimum time interval between claims in seconds |
minClaimAmount | uint256 | Minimum amount that can be claimed in a single transaction |
Vesting
Inherits: IVesting, AbstractUtilityContract, Ownable
Manages token vesting schedules for beneficiaries
Inherits IVesting, AbstractUtilityContract, Ownable
State Variables
token
The ERC20 token that is being vested
IERC20 public token;
allocatedTokens
The total amount of tokens that have been allocated for vesting
uint256 public allocatedTokens;
vestings
A mapping of beneficiary addresses to their vesting information
mapping(address => IVesting.VestingInfo) public vestings;
Functions
constructor
Initializes the contract with deploy manager, token, and owner
constructor() payable Ownable(msg.sender);
claim
Claims all tokens currently available for the caller according to their vesting schedule
function claim() public;
startVesting
Creates a new vesting schedule for a beneficiary
function startVesting(IVesting.VestingParams calldata params) external onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
params | IVesting.VestingParams | Struct containing the parameters for the new vesting schedule |
withdrawUnallocated
Withdraws all unallocated tokens from the contract to the specified address
function withdrawUnallocated(address _to) external onlyOwner;
Parameters
Name | Type | Description |
---|---|---|
_to | address | Address to receive the withdrawn tokens |
initialize
function initialize(bytes memory _initData) external override notInitialized returns (bool);
vestedAmount
Returns the total amount of tokens vested for a beneficiary at the current time
function vestedAmount(address _claimer) public view returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
_claimer | address | Address of the beneficiary |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | Amount of tokens vested |
claimableAmount
Returns the amount of tokens that can currently be claimed by a beneficiary
function claimableAmount(address _claimer) public view returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
_claimer | address | Address of the beneficiary |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | Amount of tokens claimable |
getVestingInfo
Returns the information about a vesting schedule for a beneficiary
function getVestingInfo(address _claimer) public view returns (IVesting.VestingInfo memory);
Parameters
Name | Type | Description |
---|---|---|
_claimer | address | Address of the beneficiary |
Returns
Name | Type | Description |
---|---|---|
<none> | IVesting.VestingInfo | VestingInfo struct containing the vesting information |
getInitData
Returns the ABI-encoded initialization data for the contract
function getInitData(address _deployManager, address _token, address _owner) external pure returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
_deployManager | address | Address of the deploy manager |
_token | address | Address of the ERC20 token |
_owner | address | Address of the contract owner |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | ABI-encoded initialization data |
VestingLib
Provides utility functions for calculating vested and claimable token amounts
Functions
vestedAmount
Calculates the total amount of tokens vested for a given vesting schedule at the current time
function vestedAmount(IVesting.VestingInfo storage v) internal view returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
v | IVesting.VestingInfo | The vesting information struct |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The total amount of tokens vested |
claimableAmount
Calculates the amount of tokens currently claimable by the beneficiary
function claimableAmount(IVesting.VestingInfo storage v) internal view returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
v | IVesting.VestingInfo | The vesting information struct |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | The amount of tokens that can be claimed |
ERC20Mock
Inherits: ERC20
Functions
constructor
constructor(address recipient) payable ERC20("MyToken", "MTK");