Skip to content

Commit

Permalink
Merge pull request #540 from clrfund/brightid-v6
Browse files Browse the repository at this point in the history
Upgrade to brightId v6 api
  • Loading branch information
yuetloo authored Aug 29, 2022
2 parents b23f323 + 9eab8a1 commit c3d540d
Show file tree
Hide file tree
Showing 43 changed files with 2,045 additions and 2,498 deletions.
6 changes: 6 additions & 0 deletions contracts/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ BRIGHTID_CONTEXT=clr.fund
# BrightId node addr that signs verifications. Node One uses this one
BRIGHTID_VERIFIER_ADDR=0xb1d71F62bEe34E9Fc349234C201090c33BCdF6DB

# used in the BrightId sponsor deployment script
BRIGHTID_USER_REGISTRY=

# used in the BrightId user registry deployment script
FUNDING_ROUND_FACTORY_ADDRESS

# JSON-RPC endpoint to the selected network
JSONRPC_HTTP_URL=https://eth-goerli.alchemyapi.io/v2/ADD_API_KEY

Expand Down
15 changes: 15 additions & 0 deletions contracts/contracts/userRegistry/BrightIdSponsor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.6.12;

contract BrightIdSponsor {
event Sponsor(address indexed addr);

/**
* @dev sponsor a BrightId user by emitting an event
* that a BrightId node is listening for
*/
function sponsor(address addr) public {
emit Sponsor(addr);
}
}
86 changes: 69 additions & 17 deletions contracts/contracts/userRegistry/BrightIdUserRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,59 @@
pragma solidity ^0.6.12;

import './IUserRegistry.sol';
import './BrightIdSponsor.sol';
import '@openzeppelin/contracts/access/Ownable.sol';

contract BrightIdUserRegistry is Ownable, IUserRegistry {
string private constant ERROR_NEWER_VERIFICATION = 'NEWER VERIFICATION REGISTERED BEFORE';
string private constant ERROR_NOT_AUTHORIZED = 'NOT AUTHORIZED';
string private constant ERROR_INVALID_VERIFIER = 'INVALID VERIFIER';
string private constant ERROR_INVALID_CONTEXT = 'INVALID CONTEXT';
string private constant ERROR_INVALID_SPONSOR = 'INVALID SPONSOR';
string private constant ERROR_INVALID_REGISTRATION_PERIOD = 'INVALID REGISTRATION PERIOD';
string private constant ERROR_EXPIRED_VERIFICATION = 'EXPIRED VERIFICATION';
string private constant ERROR_REGISTRATION_CLOSED = 'REGISTRATION CLOSED';

bytes32 public context;
address public verifier;
BrightIdSponsor public brightIdSponsor;

// Only register a verified user during this period
uint256 public registrationStartTime;
uint256 public registrationDeadline;

struct Verification {
uint256 time;
bool isVerified;
}
mapping(address => Verification) public verifications;

event SetBrightIdSettings(bytes32 context, address verifier);
event Sponsor(address indexed addr);

event Registered(address indexed addr, uint256 timestamp);
event RegistrationPeriodChanged(uint256 startTime, uint256 deadline);
event SponsorChanged(address sponsor);

/**
* @param _context BrightID context used for verifying users
* @param _verifier BrightID verifier address that signs BrightID verifications
* @param _sponsor Contract address that emits BrightID sponsor event
*/
constructor(bytes32 _context, address _verifier) public {
constructor(bytes32 _context, address _verifier, address _sponsor) public {
// ecrecover returns zero on error
require(_verifier != address(0), ERROR_INVALID_VERIFIER);
require(_sponsor != address(0), ERROR_INVALID_SPONSOR);

context = _context;
verifier = _verifier;
brightIdSponsor = BrightIdSponsor(_sponsor);
}

/**
* @notice Sponsor a BrightID user by context id
* @param addr BrightID context id
*/
function sponsor(address addr) public {
emit Sponsor(addr);
brightIdSponsor.sponsor(addr);
}

/**
Expand All @@ -57,6 +72,30 @@ contract BrightIdUserRegistry is Ownable, IUserRegistry {
emit SetBrightIdSettings(_context, _verifier);
}

/**
* @notice Set BrightID sponsor
* @param _sponsor Contract address that emits BrightID sponsor event
*/
function setSponsor(address _sponsor) external onlyOwner {
require(_sponsor != address(0), ERROR_INVALID_SPONSOR);

brightIdSponsor = BrightIdSponsor(_sponsor);
emit SponsorChanged(_sponsor);
}

/**
* @notice Set the registration period for verified users
* @param _startTime Registration start time
* @param _deadline Registration deadline
*/
function setRegistrationPeriod(uint256 _startTime, uint256 _deadline) external onlyOwner {
require(_startTime <= _deadline, ERROR_INVALID_REGISTRATION_PERIOD);

registrationStartTime = _startTime;
registrationDeadline = _deadline;
emit RegistrationPeriodChanged(_startTime, _deadline);
}

/**
* @notice Check a user is verified or not
* @param _user BrightID context id used for verifying users
Expand All @@ -67,41 +106,54 @@ contract BrightIdUserRegistry is Ownable, IUserRegistry {
view
returns (bool)
{
return verifications[_user].isVerified;
Verification memory verification = verifications[_user];
return canRegister(verification.time);
}

/**
* @notice check if the registry is open for registration
* @param _timestamp timestamp
*/
function canRegister(uint256 _timestamp)
public
view
returns (bool)
{
return _timestamp > 0
&& _timestamp >= registrationStartTime
&& _timestamp < registrationDeadline;
}

/**
* @notice Register a user by BrightID verification
* @param _context The context used in the users verification
* @param _addrs The history of addresses used by this user in this context
* @param _addr The address used by this user in this context
* @param _verificationHash sha256 of the verification expression
* @param _timestamp The BrightID node's verification timestamp
* @param _v Component of signature
* @param _r Component of signature
* @param _s Component of signature
*/
function register(
bytes32 _context,
address[] calldata _addrs,
address _addr,
bytes32 _verificationHash,
uint _timestamp,
uint8 _v,
bytes32 _r,
bytes32 _s
) external {
require(context == _context, ERROR_INVALID_CONTEXT);
require(verifications[_addrs[0]].time < _timestamp, ERROR_NEWER_VERIFICATION);
require(verifications[_addr].time < _timestamp, ERROR_NEWER_VERIFICATION);
require(canRegister(block.timestamp), ERROR_REGISTRATION_CLOSED);
require(canRegister(_timestamp), ERROR_EXPIRED_VERIFICATION);

bytes32 message = keccak256(abi.encodePacked(_context, _addrs, _timestamp));
bytes32 message = keccak256(abi.encodePacked(_context, _addr, _verificationHash, _timestamp));
address signer = ecrecover(message, _v, _r, _s);
require(verifier == signer, ERROR_NOT_AUTHORIZED);

verifications[_addrs[0]].time = _timestamp;
verifications[_addrs[0]].isVerified = true;
for(uint i = 1; i < _addrs.length; i++) {
// update time of all previous context ids to be sure no one can use old verifications again
verifications[_addrs[i]].time = _timestamp;
// set old verifications unverified
verifications[_addrs[i]].isVerified = false;
}
verifications[_addr].time = _timestamp;

emit Registered(_addr, _timestamp);
}
}
3 changes: 2 additions & 1 deletion contracts/scripts/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ async function main() {

userRegistry = await BrightIdUserRegistry.deploy(
utils.formatBytes32String(process.env.BRIGHTID_CONTEXT || 'clr.fund'),
process.env.BRIGHTID_VERIFIER_ADDR
process.env.BRIGHTID_VERIFIER_ADDR,
process.env.BRIGHTID_SPONSOR
)
} else {
throw new Error('unsupported user registry type')
Expand Down
60 changes: 60 additions & 0 deletions contracts/scripts/deployBrightIdSponsor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { ethers } from 'hardhat'
import { Contract, utils } from 'ethers'

async function main() {
console.log('*******************')
console.log('Deploying a user registry!')
console.log('*******************')

if (!process.env.BRIGHTID_USER_REGISTRY) {
console.error('Missing BRIGHTID_USER_REGISTRY environment variable')
return
}
if (!process.env.BRIGHTID_CONTEXT) {
console.error('Missing BRIGHTID_CONTEXT environment variable')
return
}
if (!process.env.BRIGHTID_VERIFIER_ADDR) {
console.error('Missing BRIGHTID_VERIFIER_ADDR environment variable')
return
}

const [deployer] = await ethers.getSigners()
console.log('deployer.address: ', deployer.address)

console.log('deploying brightid sponsor contract')
const BrightIdSponsor = await ethers.getContractFactory(
'BrightIdSponsor',
deployer
)
const sponsor = await BrightIdSponsor.deploy()
const receipt = await sponsor.deployTransaction.wait()
console.log(`Deployed BrightId Sponsor Contract at ${sponsor.address}`)
console.log('transaction hash', receipt.transactionHash)

const userRegistry = await ethers.getContractAt(
'BrightIdUserRegistry',
process.env.BRIGHTID_USER_REGISTRY
)
const tx = await userRegistry.setSettings(
utils.formatBytes32String(process.env.BRIGHTID_CONTEXT),
process.env.BRIGHTID_VERIFIER_ADDR,
sponsor.address
)
const settingReceipt = await tx.wait()
console.log(
'Set user registry settings at hash',
settingReceipt.transactionHash
)

console.log('*******************')
console.log('Deploy complete!')
console.log('*******************')
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
16 changes: 15 additions & 1 deletion contracts/scripts/deployRound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ async function main() {
)
userRegistry = await BrightIdUserRegistry.deploy(
utils.formatBytes32String(process.env.BRIGHTID_CONTEXT || 'clr.fund'),
process.env.BRIGHTID_VERIFIER_ADDR
process.env.BRIGHTID_VERIFIER_ADDR,
process.env.BRIGHTID_SPONSOR
)
} else {
throw new Error('unsupported user registry type')
Expand Down Expand Up @@ -166,6 +167,7 @@ async function main() {
deployer.address
)
await addFundingSourceTx.wait()
console.log('Added funding source', addFundingSourceTx.hash)

const deployNewRoundTx = await fundingRoundFactory.deployNewRound()
await deployNewRoundTx.wait()
Expand Down Expand Up @@ -227,6 +229,18 @@ async function main() {
const maciAddress = await fundingRound.maci()
console.log('maci.address: ', maciAddress)

if (userRegistryType === 'brightid') {
const maci = await ethers.getContractAt('MACI', maciAddress)
const startTime = await maci.signUpTimestamp()
const endTime = await maci.calcSignUpDeadline()
const periodTx = await userRegistry.setRegistrationPeriod(
startTime,
endTime
)
console.log('Set user registration period', periodTx.hash)
await periodTx.wait()
}

console.log('*******************')
console.log('Deploy complete!')
console.log('*******************')
Expand Down
17 changes: 17 additions & 0 deletions contracts/scripts/deployTestRound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,23 @@ async function main() {
const maciAddress = await fundingRound.maci()
console.log(`MACI address: ${maciAddress}`)

if (userRegistryType === 'brightid') {
const userRegistryAddress = await fundingRound.userRegistry()
const userRegistry = await ethers.getContractAt(
'BrightIdUserRegistry',
userRegistryAddress
)
const maci = await ethers.getContractAt('MACI', maciAddress)
const startTime = await maci.signUpTimestamp()
const endTime = await maci.calcSignUpDeadline()
const periodTx = await userRegistry.setRegistrationPeriod(
startTime,
endTime
)
console.log('Set user registration period', periodTx.hash)
await periodTx.wait()
}

const recipientRegistryType = process.env.RECIPIENT_REGISTRY_TYPE || 'simple'
const recipientRegistryAddress = await factory.recipientRegistry()
if (recipientRegistryType === 'simple') {
Expand Down
72 changes: 72 additions & 0 deletions contracts/scripts/deployUserRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { ethers } from 'hardhat'
import { Contract, utils } from 'ethers'

async function main() {
console.log('*******************')
console.log('Deploying a user registry!')
console.log('*******************')
const [deployer] = await ethers.getSigners()
console.log('deployer.address: ', deployer.address)

const fundingRoundFactoryAddress = process.env.FUNDING_ROUND_FACTORY_ADDRESS

if (!fundingRoundFactoryAddress) {
throw new Error(
'Environment variable FUNDING_ROUND_FACTORY_ADDRESS is not setup'
)
}
const fundingRoundFactory = await ethers.getContractAt(
'FundingRoundFactory',
fundingRoundFactoryAddress
)
console.log('funding round factory address ', fundingRoundFactory.address)

const userRegistryType = process.env.USER_REGISTRY_TYPE || 'simple'
let userRegistry: Contract
if (userRegistryType === 'simple') {
const SimpleUserRegistry = await ethers.getContractFactory(
'SimpleUserRegistry',
deployer
)
userRegistry = await SimpleUserRegistry.deploy()
} else if (userRegistryType === 'brightid') {
console.log('deploying brightid user registry')
const BrightIdUserRegistry = await ethers.getContractFactory(
'BrightIdUserRegistry',
deployer
)

userRegistry = await BrightIdUserRegistry.deploy(
utils.formatBytes32String(process.env.BRIGHTID_CONTEXT || 'clr.fund'),
process.env.BRIGHTID_VERIFIER_ADDR,
process.env.BRIGHTID_SPONSOR
)
console.log('transaction hash', userRegistry.deployTransaction.hash)
} else {
throw new Error('unsupported user registry type')
}
await userRegistry.deployTransaction.wait()
console.log(
`Deployed ${userRegistryType} user registry at ${userRegistry.address}`
)

const setUserRegistryTx = await fundingRoundFactory.setUserRegistry(
userRegistry.address
)
await setUserRegistryTx.wait()
console.log(
'set user registry in funding round factory',
setUserRegistryTx.hash
)

console.log('*******************')
console.log('Deploy complete!')
console.log('*******************')
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
Loading

0 comments on commit c3d540d

Please sign in to comment.