Skip to main content

Smart Contracts

How to build smart contracts with the Hyperverse Builderkit.


Getting Started

After setting up your local environment, you're ready to build your smart contract. EVM Smart Modules are written in Solidity and use Hardhat to compile and deploy smart contracts in the contracts directory.

1

Additional resources

Haven't set up your environment? See Environment Setup before moving forward. Check out Ethereum, Solidity, Hardhat for additional resources to help you get started.

Contracts Folder

The contracts folder contains the following files.

  • Module.sol - Contains the core functionality of your smart module.
  • ModuleFactory.sol - Contains the clone factory implementation of the smart module.
  • CloneFactory.sol - Enables the ModuleFactory to deploy clones for your smart module.
  • IHyperverseModule.sol - Contains the Hyperverse EVM Smart Module standard.
Example

The Builderkit contains examples of completed ERC721 EVM Module contracts here.

Update Module.sol

The Module.sol file contains the core functionality of your smart module. To update this contract, import interfaces and utilities, update the contract name & metadata, and add all smart contract functionality.

// Update file name to match smart module (ex. ERC721.sol)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
// Import interfaces and utilities
import './hyperverse/IHyperverseModule.sol';
// Update contract name and include inherited contracts
contract Module is IHyperverseModule {
address public immutable contractOwner;
address private tenantOwner;

constructor(address _owner) {
// Update metadata
metadata = ModuleMetadata(
'Module',
Author(_owner, 'https://externallink.net'),
'1.0.0',
3479831479814,
'https://externallink.net'
);
contractOwner = _owner;
}
function init(address _tenant) external {
tenantOwner = _tenant;
}
// Add smart contract functionality
}
Example

View an example of a completed Module.sol contract at ERC721.sol

Update ModuleFactory.sol

The ModuleFactory.sol file contains the clone factory implementation of the smart module. To update this contract, update the contract name to reflect changes in your Module.sol contract.

// Update file name to match smart module (ex. ERC721Factory.sol)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;

import './hyperverse/CloneFactory.sol';
import './hyperverse/IHyperverseModule.sol';
// Import smart contract
import './Module.sol';

/**
* @dev Clone Factory Implementation
*/

// Update occurrences of module name
contract ModuleFactory is CloneFactory {
struct Tenant {
Module module;
address owner;
}

mapping(address => Tenant) public tenants;

address public immutable owner;
address public immutable masterContract;
// Update admin ethereum address
address private hyperverseAdmin = 0xD847C7408c48b6b6720CCa75eB30a93acbF5163D;

modifier isOwner(address _tenant) {
require(
tenants[_tenant].owner == msg.sender,
'The calling address is not an owner of a tenant'
);
_;
}
modifier isAllowedToCreateInstance(address _tenant) {
require(
msg.sender == _tenant || msg.sender == hyperverseAdmin,
'Please use a valid address to create an instance'
);
_;
}

constructor(address _masterContract, address _owner) {
masterContract = _masterContract;
owner = _owner;
}

/******************* TENANT FUNCTIONALITIES *******************/

function createInstance(address _tenant) external isAllowedToCreateInstance(_tenant) {
// Update module name
Module m = Module(createClone(masterContract));

//initializing tenant state of clone
m.init(msg.sender);

//set Tenant data
Tenant storage newTenant = tenants[_tenant];
// Update occurrences of module name
newTenant.module = m;
newTenant.owner = _tenant;
}

function getProxy(address _tenant) public view returns (Module) {
return tenants[_tenant].module;
}
}
info

View an example of a completed ModuleFactory.sol contract at ERC721Factory.sol

You may extend the functionality of your smart module by developing additional interfaces, utilities, and smart contracts. Read the Solidity docs for more information.

Update Deploy Script

When your smart contract is complete, navigate to the /scripts/deploy.js file to update your deploy scripts. This will allow you to deploy your smart modules to the Ethereum network.

const hre = require("hardhat");
const fs = require("fs-extra");
const { constants } = require("ethers");
const main = async () => {
const [deployer] = await ethers.getSigners();
console.log("Deployer Address: ", deployer.address);
const hyperverseAdmin = deployer.address;
// Update module name
const BaseModule = await hre.ethers.getContractFactory("Module");
const baseContract = await BaseModule.deploy(hyperverseAdmin);
await baseContract.deployed();
console.log("Module Contract deployed to: ", baseContract.address);
// Update module factory name
const ModuleFactory = await hre.ethers.getContractFactory("ModuleFactory");
const moduleFactory = await ModuleFactory.deploy(
baseContract.address,
hyperverseAdmin
);
await moduleFactory.deployed();

const env = JSON.parse(fs.readFileSync("contracts.json").toString());
env[hre.network.name] = env[hre.network.name] || {};
env[hre.network.name].testnet = env[hre.network.name].testnet || {};

env[hre.network.name].testnet.contractAddress = baseContract.address;
// Update occurrences of module factory
env[hre.network.name].testnet.factoryAddress = moduleFactory.address;

// Save contract addresses back to file
fs.writeJsonSync("contracts.json", env, { spaces: 2 });

// Deploy default tenant
let proxyAddress = constants.AddressZero;
// Update occurrences of module factory
await moduleFactory.createInstance(deployer.address);
while (proxyAddress === constants.AddressZero) {
proxyAddress = await moduleFactory.getProxy(deployer.address);
}
};

const runMain = async () => {
try {
await main();
process.exit(0);
} catch (error) {
console.error(error);
process.exit(1);
}
};

runMain();
Example

View an example of a completed deploy.js here

Build Unit Tests

You're now ready to start building your unit tests!

โ†’
Step 3: Unit Tests
unit-tests