███████ ██████ ███████ ████████
██ ██ ██ ██ ██
███████ ██ ██ █████ ██
██ ██ ██ ██ ██
███████ ██████ ██ ██
Before you begin, you need to install the following tools and run the following commands:
Note: Feel free to skip this section if you don't plan on deploying, verifying or testing the contracts.
Note: XXXXXXXXXX
needs to be replaced with your API key.
- Node (v18) and yarn (v3)
- Git
- Foundry
- Go to
packages/hardhat
and run:- Run
npx hardhat vars set EVM_PRIVATE_KEY_1 XXXXXXXXXX
- Run
npx hardhat vars set EVM_PRIVATE_KEY_2 XXXXXXXXXX
- Run
npx hardhat vars set ALCHEMY_API_KEY XXXXXXXXXX
- Run
npx hardhat vars set ETHERSCAN_API_KEY XXXXXXXXXX
- Run
Note: Setting up multiple EVM_PRIVATE_KEY_
is optional, contracts and contract calls which require multiple addresses will require you to set up multiple like this.
Key smart contracts are found in the packages/hardhat/contracts
folder and cover several use cases:
claim
: contracts to distribute tokens with lockup conditions like vesting (continuous, tranche-based, or price-based) and voting powergovernance
: contracts to create a DAO, governor, and timelock. Allowing DAO members to vote with tokens held in a vesting contractsale
: contracts to sell tokens to users, can include access restrictions, fair random queues, and multiple payment methodsutilities
: contains other useful contracts (i.e. contract registry)
Related:
interfaces
: are helpful when building third-party contracts relying on Soft DAO primitivesmocks
: are stubbed out contracts for testing and development (not for use in production)token
: are commonly used token standards
These contracts are a WIP:
payment
: contracts to receive arbitrary payments from users and track how much they have sent
Setup your repository and contracts for the tests:
yarn
Run Hardhat tests:
Note: This command also includes a compile command and may take some time to complete.
yarn test
Run Foundry tests:
Note: This will do some setup the first time you run it and may take some time to complete.
yarn forge-test
Here is a real example where you can deploy an ERC20. Feel free to go to ignition/modules/Deploy_GenericERC20.ts
and modify it to meet your needs first.
npx hardhat ignition deploy ignition/modules/Deploy_GenericERC20.ts --network <your-network>
<your-network>
can be localhost
, sepolia
, etc. You can customize network configurations in hardhat.config.ts
.
For key storage we utilize the configuration variables (see Developer Setup for instructions). EVM_PRIVATE_KEY_1
will be the deployer of any contracts you end up deploying using the commands above. The deployer account will be used to execute any function calls that are part of your deployment script.
Simply add the --verify
flag to the end of the deploy
command.
npx hardhat ignition deploy ignition/modules/Deploy_GenericERC20.ts --network <your-network> --verify
npx hardhat ignition deploy ignition/modules/Deploy_FlatPriceSaleFactory.ts --network <your-network> --verify
This uses the FlatPriceSaleFactory contract to create a new sale with the configuration you desire.
npx hardhat ignition deploy ignition/modules/Execute_NewSale.ts --network <your-network>
Use the registry contracts below to find other official Soft DAO contracts. The registry is used to mark specific addresses as authentic contracts supporting specific interfaces following the ERC-165 standard, and the easiest way to decode the Registry contracts is via a subgraph watching the registry, such as those deployed by Tokensoft.
Note: Lowercase contract addresses are used as subgraph entity IDs.
URL: https://thegraph.com/hosted-service/subgraph/tokensoft/sales-mainnet Query:
{
registry(id: "0xc70573b924c92618e6143f6ac4c2b1ad7ba8785b") {
addresses {
id
interfaceIds
interfaceNames
}
}
}
Response:
{
"data": {
"registry": {
"addresses": [
{
"id": "0xf266195e1b30b8f536834303c555bd6aaf063f04",
"interfaceIds": [
"0xab85ea0e",
"0xfc57b782",
"0x09e04257",
"0x35ef410e"
],
"interfaceNames": [
"IDistributor",
"IAdvancedDistributor",
"IContinuousVesting",
"IMerkleSet"
]
}
]
}
}
}
This resonse means that the address 0xf266195e1b30b8f536834303c555bd6aaf063f04
is known to the Soft DAO as a Distributor and includes advanced features, a merkle root access list, and continuous vesting. See the two files below for more information on the interfaces.
This file includes the ERC-165 interface for each Solidity contract/interface as well as the source solidity file defining the interface.
Example results:
{
"Registry": {
"source": "contracts/utilities/Registry.sol",
"id": "0xe711948a"
},
"FlatPriceSaleFactory": {
"source": "contracts/sale/v2/FlatPriceSaleFactory.sol",
"id": "0xfcb73502"
},
"FlatPriceSale": {
"source": "contracts/sale/v2/FlatPriceSale.sol",
"id": "0x7a6d298d"
},
"IERC20": {
"source": "@openzeppelin/contracts/token/ERC20/IERC20.sol",
"id": "0x36372b07"
},
"IVotes": {
"source": "@openzeppelin/contracts/governance/utils/IVotes.sol",
"id": "0xe90fb3f6"
},
...
}
This file allows one to reference the interfaces when developing a subgraph.
import { TypedMap } from "@graphprotocol/graph-ts"
class knownInterfacesClass extends TypedMap<string, string>{
constructor(){
super()
// map interface names to ids AND ids to names
this.set("Sweepable", "0xac1d7eef")
this.set("0xac1d7eef", "Sweepable")
...
}
// convenience getters to emulate an object in AssemblyScript
get Sweepable(): string {
let value = this.get("Sweepable")
return value!.toString()
}
...
}
export const knownInterfaces = new knownInterfacesClass
Example AssemblyScript mapping file exampleMapping.ts
import { knownInterfaces } from "../../generated/interfaces";
// do something based on interface ID
if (registeredAddress.interfaceIds.includes(knownInterfaces.IDistributor)) {
log.info("Registered {} as a Distributor", [registeredAddress.id]);
saveDistributor(distributor.id, block);
}
- 0x4aD35755F3bC7d591CBa3D0D0Eb27C2497A73d30
- 0xC0A1CFc14996204C4bac28758b0A2C0d7b006fd9
- 0xab276a23b467CfDc86f59C1aF3103E526ebc38a2
- 0xA5D3d9Bf9940FeaCFcC2090D35e6c1AF4892DBE5
- 0x904C250B5B1b45274d2d7909b9394bEdA143DD5C
- 0x5103ED418004b03a796a41c97BdaaC8FfB5aa264
- 0x9Ef415dE715c0a55AA867bcDEa00eAf914aD6cb7
- 0x92DcF0aFD197E73345c893b856B93ee68CB61809
- 0x245A9bD01ccF512D1374BE4F7A8Eb06dA21E6333
- 0xfE245D36F8b4079C62B74eD4FfE7B055DB1B5A2D
- 0x55ee754b2cf0ccb70b808c47321ca1ad7ef0e118
- 0xB7488893AF633EFdAEB95F496B7D2FF2C50f1A9A
- 0x865D024BFd9e1C2Cd665fAc6666c5C3E4a375dd7
- 0x135D889aFF58584e12ab3bd4ce327a18aF3356Ef
- 0xc70573B924C92618E6143F6ac4C2B1aD7ba8785b
- 0x17c14f6087C62666D28361697f4a9B4D39DC3Bc5
- 0x07537efBa62504425f879E9D60A25aB09D139161
- 0xf9d55F554175B8a18cDB167063383f5462442EAD
- 0x89a415207b07a739b93d4fc70a2eab67c0effaa8
- 0xA5D3d9Bf9940FeaCFcC2090D35e6c1AF4892DBE5
- 0x4959353534a8ecf0b698a9d3115fbce393f3435c
- 0x904c250b5b1b45274d2d7909b9394beda143dd5c
- 0x5103ED418004b03a796a41c97BdaaC8FfB5aa264
- 0x638E9F037F8B45F9B1b20bEB890225e1e8d29B95
- 0x55ee754b2cf0ccb70b808c47321ca1ad7ef0e118
- 0xB7488893AF633EFdAEB95F496B7D2FF2C50f1A9A
- 0x3a03bF4106404B94d426bC31B831889f0d43960b
- 0x31b7625997603Ce07B349d6f0300B6CB5896959b
- 0x493E0a1f8304832658c461c2EaBfaeCeeE507097
- 0x7afd2700F8e915ed4D39897d0D284A54e6348Ad3
- 0x07537efBa62504425f879E9D60A25aB09D139161
- 0x17c14f6087C62666D28361697f4a9B4D39DC3Bc5
- 0x71bE8339023d779f2f85893761729Bb27b97891d
- 0x9c2D86d00aFDe6e616CADfBc0fe2D47C1d22b1c8
- 0xeEDB0e8e589F9ADf6768fc006BaA1C6462f5e563
- 0x000047203100A45635029eC21bbBec5EC53Cb6f6
- 0xb41169Cc124298Be20e2Ca956cC46E266ab5E203
- 0xC61da7Db4981c8839b51B32d4c83cCdf47ca0b20
- 0xA82d7ED01c31DD2A46681D18E3E213C9E9231605
- 0xb41169Cc124298Be20e2Ca956cC46E266ab5E203
- 0xC61da7Db4981c8839b51B32d4c83cCdf47ca0b20
- 0xA82d7ED01c31DD2A46681D18E3E213C9E9231605
- 0xb41169Cc124298Be20e2Ca956cC46E266ab5E203
- 0xC61da7Db4981c8839b51B32d4c83cCdf47ca0b20
- 0xa82d7ed01c31dd2a46681d18e3e213c9e9231605
- 0xb41169Cc124298Be20e2Ca956cC46E266ab5E203
- 0xC61da7Db4981c8839b51B32d4c83cCdf47ca0b20
- 0xA82d7ED01c31DD2A46681D18E3E213C9E9231605
Hint Typescript helps you catch errors at compile time, which can save time and improve code quality, but can be challenging for those who are new to the language or who are used to the more dynamic nature of JavaScript. Below are the steps to disable type & lint check at different levels
We run pre-commit
git hook which lints the staged files and don't let you commit if there is an linting error.
To disable this, go to .husky/pre-commit
file and comment out yarn lint-staged --verbose
- yarn lint-staged --verbose
+ # yarn lint-staged --verbose
By default, Vercel runs types and lint checks before building your app. The deployment will fail if there are any types or lint errors.
To ignore these checks while deploying from the CLI, use:
yarn vercel:yolo
If your repo is connected to Vercel, you can set NEXT_PUBLIC_IGNORE_BUILD_ERROR
to true
in a environment variable.
We have github workflow setup checkout .github/workflows/lint.yaml
which runs types and lint error checks every time code is pushed to main
branch or pull request is made to main
branch
To disable it, delete .github
directory
The contracts are licensed under the MIT license. Use them however you like — we'd appreciate a note that your core primitives are based on the Soft DAO!