Skip to content

Commit 5879539

Browse files
2 parents 5bafda1 + 87af96c commit 5879539

File tree

8 files changed

+396
-50
lines changed

8 files changed

+396
-50
lines changed

contracts/passport/SmartBuilderScore.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
66
import "./PassportBuilderScore.sol";
77
import "@openzeppelin/contracts/access/Ownable.sol";
88

9+
// Deprecated in favor of TalentBuilderScorer
910
contract SmartBuilderScore is Ownable {
1011
using ECDSA for bytes32;
1112

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.24;
3+
4+
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
5+
import "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
6+
import "./PassportBuilderScore.sol";
7+
import "@openzeppelin/contracts/access/Ownable.sol";
8+
9+
contract TalentBuilderScore is Ownable {
10+
using ECDSA for bytes32;
11+
12+
address public trustedSigner;
13+
address public feeReceiver;
14+
PassportBuilderScore public passportBuilderScore;
15+
PassportRegistry public passportRegistry;
16+
uint256 public cost = 0.0001 ether;
17+
18+
event BuilderScoreSet(address indexed user, uint256 score, uint256 talentId);
19+
20+
bool public enabled;
21+
22+
constructor(
23+
address _trustedSigner,
24+
address _passportBuilderScoreAddress,
25+
address _passportRegistryAddress,
26+
address _feeReceiver
27+
) Ownable(_trustedSigner) {
28+
trustedSigner = _trustedSigner;
29+
passportBuilderScore = PassportBuilderScore(_passportBuilderScoreAddress);
30+
passportRegistry = PassportRegistry(_passportRegistryAddress);
31+
feeReceiver = _feeReceiver;
32+
enabled = true;
33+
}
34+
35+
/**
36+
* @notice Changes the owner of passport registry.
37+
* @param _newOwner The new owner of passport registry.
38+
* @dev Can only be called by the owner.
39+
*/
40+
function setPassportRegistryOwner(address _newOwner) public onlyOwner {
41+
passportRegistry.transferOwnership(_newOwner);
42+
}
43+
44+
/**
45+
* @notice Enables or disables the SmartBuilderScore contract.
46+
* @param _enabled Whether the SmartBuilderScore contract should be enabled.
47+
* @dev Can only be called by the owner.
48+
*/
49+
function setEnabled(bool _enabled) public onlyOwner {
50+
enabled = _enabled;
51+
}
52+
53+
/**
54+
* @notice Disables the SmartBuilderScore contract.
55+
* @dev Can only be called by the owner.
56+
*/
57+
function setDisabled() public onlyOwner {
58+
enabled = false;
59+
}
60+
61+
/**
62+
* @notice Sets the cost of adding a score.
63+
* @param _cost The cost of adding a score.
64+
* @dev Can only be called by the owner.
65+
*/
66+
function setCost(uint256 _cost) public onlyOwner {
67+
cost = _cost;
68+
}
69+
70+
/**
71+
* @notice Updates the fee receiver address.
72+
* @param _feeReceiver The new fee receiver address.
73+
* @dev Can only be called by the owner.
74+
*/
75+
function updateReceiver(address _feeReceiver) public onlyOwner {
76+
feeReceiver = _feeReceiver;
77+
}
78+
79+
/**
80+
* @notice Creates an attestation if the provided number is signed by the trusted signer.
81+
* @param score The number to be attested.
82+
* @param talentId The number of the talent profile to receive the attestation.
83+
* @param wallet The wallet to receive the attestation.
84+
* @param signature The signature of the trusted signer.
85+
*/
86+
function addScore(uint256 score, uint256 talentId, address wallet, bytes memory signature) public payable {
87+
require(enabled, "Setting the Builder Score is disabled for this contract");
88+
// Ensure the caller has paid the required fee
89+
require(msg.value >= cost, "Insufficient payment");
90+
// Hash the number
91+
bytes32 numberHash = keccak256(abi.encodePacked(score, talentId, wallet));
92+
93+
// Recover the address that signed the hash
94+
address signer = MessageHashUtils.toEthSignedMessageHash(numberHash).recover(signature);
95+
96+
// Ensure the signer is the trusted signer
97+
require(signer == trustedSigner, "Invalid signature");
98+
99+
// Transfer fee to fee receiver
100+
payable(feeReceiver).transfer(msg.value);
101+
102+
// Create passport if it does not exist
103+
if(passportRegistry.idPassport(talentId) == address(0)) {
104+
passportRegistry.adminCreate("talent_builder_score", wallet, talentId);
105+
}
106+
107+
// Emit event
108+
require(passportBuilderScore.setScore(talentId, score), "Failed to set score");
109+
emit BuilderScoreSet(wallet, score, talentId);
110+
}
111+
}

scripts/passport/deployScorer.ts

Lines changed: 0 additions & 42 deletions
This file was deleted.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { ethers, network } from "hardhat";
2+
3+
import { deployTalentBuilderScore } from "../shared";
4+
import { PassportBuilderScore, PassportRegistry } from "../../test/shared/artifacts";
5+
6+
const PASSPORT_REGISTRY_ADDRESS_MAINNET = "0xb477A9BD2547ad61f4Ac22113172Dd909E5B2331";
7+
const PASSPORT_REGISTRY_ADDRESS_TESTNET = "0xa600b3356c1440B6D6e57b0B7862dC3dFB66bc43";
8+
9+
const PASSPORT_BUILDER_SCORE_MAINNET = "0xBBFeDA7c4d8d9Df752542b03CdD715F790B32D0B"
10+
const PASSPORT_BUILDER_SCORE_TESTNET = "0x5f3aA689C4DCBAe505E6F6c8548DbD9b908bA71d"
11+
12+
const FEE_RECEIVER_MAINNET = "0xC925bD0E839E8e22A7DDEbe7f4C21b187deeC358";
13+
const FEE_RECEIVER_TESTNET = "0x08BC8a92e5C99755C675A21BC4FcfFb59E0A9508";
14+
15+
async function main() {
16+
console.log(`Deploying passport registry at ${network.name}`);
17+
18+
const [admin] = await ethers.getSigners();
19+
20+
console.log(`Admin will be ${admin.address}`);
21+
22+
const smartBuilderScore = await deployTalentBuilderScore(
23+
admin.address,
24+
PASSPORT_BUILDER_SCORE_TESTNET,
25+
PASSPORT_REGISTRY_ADDRESS_TESTNET,
26+
FEE_RECEIVER_TESTNET
27+
);
28+
29+
console.log(`Smart Builder Score Address: ${smartBuilderScore.address}`);
30+
31+
console.log("Adding trusted signer");
32+
33+
const passportBuilderScore = new ethers.Contract(
34+
PASSPORT_BUILDER_SCORE_TESTNET,
35+
PassportBuilderScore.abi,
36+
admin
37+
);
38+
await passportBuilderScore.addTrustedSigner(smartBuilderScore.address);
39+
40+
const passportRegistry = new ethers.Contract(
41+
PASSPORT_REGISTRY_ADDRESS_TESTNET,
42+
PassportRegistry.abi,
43+
admin
44+
);
45+
46+
console.log("Transfering ownership");
47+
48+
// Set smart builder score as the owner of passportRegistry so it's the only contract that can create new passports onchain
49+
await passportRegistry.transferOwnership(smartBuilderScore.address);
50+
51+
const newOwner = await passportRegistry.owner();
52+
53+
console.log(`New owner: ${newOwner}`);
54+
55+
console.log("Done");
56+
}
57+
58+
main()
59+
.then(() => process.exit(0))
60+
.catch((error) => {
61+
console.error(error);
62+
process.exit(1);
63+
});
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import hre from "hardhat";
2+
3+
import { getContract } from "viem";
4+
import { baseSepolia, base } from "viem/chains";
5+
import { privateKeyToSimpleSmartAccount } from "permissionless/accounts";
6+
7+
import dotenv from "dotenv";
8+
9+
dotenv.config();
10+
11+
import * as PassportBuilderScore from "../../artifacts/contracts/passport/PassportBuilderScore.sol/PassportBuilderScore.json";
12+
13+
const ENTRYPOINT = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789";
14+
const PASSPORT_BUILDER_SCORE_ADDRESS = "0xBBFeDA7c4d8d9Df752542b03CdD715F790B32D0B"
15+
16+
// Script to transfer ownership of passport buider score to a smart wallet
17+
async function main() {
18+
const [admin] = await hre.viem.getWalletClients();
19+
const publicClient = await hre.viem.getPublicClient();
20+
21+
if(!process.env.PRIVATE_KEY){
22+
console.error("Missing PK");
23+
return
24+
}
25+
const privateKey = `0x${process.env.PRIVATE_KEY}`;
26+
27+
console.log("privateKey", privateKey);
28+
const smartAccount = await privateKeyToSimpleSmartAccount(publicClient, {
29+
privateKey,
30+
entryPoint: ENTRYPOINT, // global entrypoint
31+
factoryAddress: "0x9406Cc6185a346906296840746125a0E44976454",
32+
});
33+
34+
console.log(`Owner SCA ${smartAccount.address}`);
35+
36+
const passportBuilderScore = getContract({
37+
address: PASSPORT_BUILDER_SCORE_ADDRESS,
38+
abi: PassportBuilderScore.abi,
39+
client: {
40+
public: publicClient,
41+
wallet: admin,
42+
},
43+
});
44+
45+
const tx = await passportBuilderScore.write.transferOwnership([smartAccount.address]);
46+
47+
await publicClient.waitForTransactionReceipt({ hash: tx });
48+
49+
const owner = await passportBuilderScore.read.owner();
50+
51+
console.log(`New owner: ${owner}`);
52+
}
53+
54+
main()
55+
.then(() => process.exit(0))
56+
.catch((error) => {
57+
console.error(error);
58+
process.exit(1);
59+
});

scripts/shared/index.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type {
66
PassportBuilderScore,
77
TalentCommunitySale,
88
TalentTGEUnlock,
9-
SmartBuilderScore,
9+
TalentBuilderScore,
1010
PassportWalletRegistry,
1111
TalentTGEUnlockTimestamp,
1212
TalentVault,
@@ -74,23 +74,23 @@ export async function deployPassportBuilderScore(registry: string, owner: string
7474
return deployedPassportBuilderScore as PassportBuilderScore;
7575
}
7676

77-
export async function deploySmartBuilderScore(
77+
export async function deployTalentBuilderScore(
7878
owner: string,
79+
passportBuilderScore: string,
7980
passportRegistry: string,
8081
feeReceiver: string,
81-
passportBuilderScore: string
82-
): Promise<SmartBuilderScore> {
83-
const smartBuilderScoreContract = await ethers.getContractFactory("SmartBuilderScore");
82+
): Promise<TalentBuilderScore> {
83+
const talentBuilderScoreContract = await ethers.getContractFactory("TalentBuilderScore");
8484

85-
const deployedSmartBuilderScore = await smartBuilderScoreContract.deploy(
85+
const deployedTalentBuilderScore = await talentBuilderScoreContract.deploy(
8686
owner,
8787
passportBuilderScore,
8888
passportRegistry,
8989
feeReceiver
9090
);
91-
await deployedSmartBuilderScore.deployed();
91+
await deployedTalentBuilderScore.deployed();
9292

93-
return deployedSmartBuilderScore as SmartBuilderScore;
93+
return deployedTalentBuilderScore as TalentBuilderScore;
9494
}
9595

9696
export async function deployTalentCommunitySale(

0 commit comments

Comments
 (0)