Skip to content

Commit b2f909f

Browse files
Add script for pre-minting basenames (#83)
* Add script for pre-minting basenames * Add expected full premint list * Updated premint script and makefile * Lint * Add csv writing to premint logic * Ignore scratch * Fix typo * Run premint3 * Remove dup * Add not-found name * Run premint2 * premint verifications and attestations * Run premint4 * Add premint5, output csv * lint * update output * Add premint 6 * Add BNS parser * Run premint 7 * Update csv * Update csv * Run premint 8 for 1 year duration reservations * Run premint 9 * Add single run of premint for rodeo * Rerun BNS merkle gen * Run premint verification * Lint * cleanup for review
1 parent 14a6b17 commit b2f909f

File tree

16 files changed

+3775
-0
lines changed

16 files changed

+3775
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ docs/
1212

1313
# Dotenv file
1414
.env
15+
16+
# Local env
17+
script/Scratch*

Makefile

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
include .env
2+
3+
# premint1 file should be minted with a 100-year duration, these are coinbase-specific domains
4+
# 3153600000 = 100 (years) * 365 (days) * 24 (hours) * 3600 (seconds)
5+
.PHONY: execute-testnet-premint-1
6+
execute-testnet-premint-1:
7+
@for name in $$(cat script/premint/premint1); \
8+
do \
9+
echo "$$name"; \
10+
forge script script/premint/Premint.s.sol --sig "run(string,uint256)" "$$name" 3153600000 \
11+
--rpc-url $(BASE_SEPOLIA_RPC_URL) --fork-retries 5 --broadcast; \
12+
done
13+
14+
# premint1 file should be minted with a 100-year duration, these are coinbase-specific domains
15+
# 3153600000 = 100 (years) * 365 (days) * 24 (hours) * 3600 (seconds)
16+
.PHONY: execute-premint-1
17+
execute-premint-1:
18+
@for name in $$(cat script/premint/premint1); \
19+
do \
20+
echo "$$name"; \
21+
forge script script/premint/Premint.s.sol --sig "run(string,uint256)" "$$name" 3153600000 \
22+
--rpc-url $(BASE_RPC_URL) --fork-retries 5 --broadcast; \
23+
done
24+
25+
# premint2 file should be minted with a 10-year duration, these are cb exec domains
26+
# 315360000 = 10 (years) * 365 (days) * 24 (hours) * 3600 (seconds)
27+
.PHONY: execute-premint-2
28+
execute-premint-2:
29+
@for name in $$(cat script/premint/premint2); \
30+
do \
31+
echo "$$name"; \
32+
forge script script/premint/Premint.s.sol --ffi --sig "run(string,uint256)" "$$name" 315360000 \
33+
--rpc-url $(BASE_RPC_URL) --fork-retries 5 --broadcast; \
34+
done
35+
36+
# premint3 file should be minted with a 5-year duration, these are web2-specific domains
37+
# 157680000 = 5 (years) * 365 (days) * 24 (hours) * 3600 (seconds)
38+
.PHONY: execute-premint-3
39+
execute-premint-3:
40+
@for name in $$(cat script/premint/premint3); \
41+
do \
42+
echo "$$name"; \
43+
forge script script/premint/Premint.s.sol --ffi --sig "run(string,uint256)" "$$name" 157680000 \
44+
--rpc-url $(BASE_RPC_URL) --fork-retries 5 --broadcast; \
45+
done
46+
47+
# premint4 file should be minted with a 5-year duration, these are web3-specific domains/individuals
48+
# 157680000 = 5 (years) * 365 (days) * 24 (hours) * 3600 (seconds)
49+
.PHONY: execute-premint-4
50+
execute-premint-4:
51+
@for name in $$(cat script/premint/premint4); \
52+
do \
53+
echo "$$name"; \
54+
forge script script/premint/Premint.s.sol --ffi --sig "run(string,uint256)" "$$name" 157680000 \
55+
--rpc-url $(BASE_RPC_URL) --fork-retries 5 --broadcast; \
56+
done
57+
58+
# premint5 file should be minted with a 5-year duration, these are web3-specific domains/individuals
59+
# 157680000 = 5 (years) * 365 (days) * 24 (hours) * 3600 (seconds)
60+
.PHONY: execute-premint-5
61+
execute-premint-5:
62+
@for name in $$(cat script/premint/premint5); \
63+
do \
64+
echo "$$name"; \
65+
forge script script/premint/Premint.s.sol --ffi --sig "run(string,uint256)" "$$name" 157680000 \
66+
--rpc-url $(BASE_RPC_URL) --fork-retries 5 --broadcast; \
67+
done
68+
69+
# premint6 file should be minted with a 100-year duration, these are Coinbase/Base specific domains
70+
# 3153600000 = 100 (years) * 365 (days) * 24 (hours) * 3600 (seconds)
71+
.PHONY: execute-premint-6
72+
execute-premint-6:
73+
@for name in $$(cat script/premint/premint6); \
74+
do \
75+
echo "$$name"; \
76+
forge script script/premint/Premint.s.sol --ffi --sig "run(string,uint256)" "$$name" 3153600000 \
77+
--rpc-url $(BASE_RPC_URL) --fork-retries 5 --broadcast; \
78+
done
79+
80+
# premint7 file should be minted with a 1-year duration, these are the F500 names
81+
# 31536000 = 1 (years) * 365 (days) * 24 (hours) * 3600 (seconds)
82+
.PHONY: execute-premint-7
83+
execute-premint-7:
84+
@for name in $$(cat script/premint/premint7); \
85+
do \
86+
echo "$$name"; \
87+
forge script script/premint/Premint.s.sol --ffi --sig "run(string,uint256)" "$$name" 31536000 \
88+
--rpc-url $(BASE_RPC_URL) --fork-retries 5 --broadcast; \
89+
done
90+
91+
# premint8 file should be minted with a 1-year duration, these are the base BD names
92+
# 31536000 = 1 (years) * 365 (days) * 24 (hours) * 3600 (seconds)
93+
.PHONY: execute-premint-8
94+
execute-premint-8:
95+
@for name in $$(cat script/premint/premint8); \
96+
do \
97+
echo "$$name"; \
98+
forge script script/premint/Premint.s.sol --ffi --sig "run(string,uint256)" "$$name" 31536000 \
99+
--rpc-url $(BASE_RPC_URL) --fork-retries 5 --broadcast; \
100+
done
101+
102+
# premint9 file should be minted with a 100-year duration, these are the base project words
103+
# 3153600000 = 100 (years) * 365 (days) * 24 (hours) * 3600 (seconds)
104+
.PHONY: execute-premint-9
105+
execute-premint-9:
106+
@for name in $$(cat script/premint/premint9); \
107+
do \
108+
echo "$$name"; \
109+
forge script script/premint/Premint.s.sol --ffi --sig "run(string,uint256)" "$$name" 31536000 \
110+
--rpc-url $(BASE_RPC_URL) --fork-retries 5 --broadcast; \
111+
done

foundry.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ src = "src"
33
out = "out"
44
libs = ["lib"]
55
remappings = ["@ensdomains/buffer/=lib/buffer"]
6+
fs_permissions = [{access = "read", path = "./script/premint/"}]
67

78
[rpc_endpoints]
89
sepolia="${SEPOLIA_RPC_URL}"
@@ -11,3 +12,4 @@ base-sepolia="${BASE_SEPOLIA_RPC_URL}"
1112
[etherscan]
1213
sepolia={url = "https://api-sepolia.etherscan.io/api", key = "${ETHERSCAN_API_KEY}"}
1314
base-sepolia={url = "https://api-sepolia.basescan.org/api", key = "${BASE_ETHERSCAN_API_KEY}"}
15+

py/BNS.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import json
2+
3+
4+
def main():
5+
6+
owners = []
7+
with open("cache/Update-BNS-Users.json", "r") as f:
8+
data = json.load(f)
9+
for r in data:
10+
if(len(r["owners"]) > 1):
11+
print("multiple owners for %s" % r["name"])
12+
elif(len(r["owners"]) == 0):
13+
print("no owners for %s" % r["name"])
14+
else:
15+
owners.append(r["owners"][0]["owner_address"])
16+
17+
18+
seen = set()
19+
owner_count = dict()
20+
unique_owners = []
21+
for owner in owners:
22+
if owner not in seen:
23+
unique_owners.append(owner)
24+
seen.add(owner)
25+
owner_count[owner] = 1
26+
else:
27+
owner_count[owner] += 1
28+
29+
30+
with open("cache/bns.csv", "a") as f:
31+
for owner in unique_owners:
32+
f.write(owner + "\n")
33+
34+
35+
print("Total owned tokens: %s" % len(owners))
36+
print("Total unique owners: %s" % len(unique_owners))
37+
c = 0
38+
for w in sorted(owner_count, key=owner_count.get):
39+
if owner_count[w] > 9:
40+
c+=1
41+
print(w, owner_count[w])
42+
print("Multiple name holders: %s" % str(c))
43+
44+
if __name__ == "__main__":
45+
main()

py/writer.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/python3
2+
3+
import sys
4+
5+
print("In writer.py")
6+
with open("script/premint/output.csv", 'a') as f:
7+
f.write(sys.argv[1])

script/premint/Premint.s.sol

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.23;
3+
4+
import {BaseRegistrar} from "src/L2/BaseRegistrar.sol";
5+
import {RegistrarController} from "src/L2/RegistrarController.sol";
6+
import {LibString} from "solady/utils/LibString.sol";
7+
8+
import "forge-std/Script.sol";
9+
10+
/// @title Script for autonomously reserving names with a controller-permissioned pkey
11+
///
12+
/// @notice addr(PREMINT_PRIVATE_KEY) must be an approved `controller` on the BaseRegistrar
13+
contract Premint is Script {
14+
uint256 premintPrivateKey = vm.envUint("PREMINT_PRIVATE_KEY");
15+
address BASE_REGISTRAR = vm.envAddress("BASE_REGISTRAR_ADDR");
16+
address BASE_ECOSYSTEM_MULTISIG = vm.envAddress("BASE_ECOSYSTEM_MULTISIG");
17+
address REGISTRAR_CONTROLLER = vm.envAddress("REGISTRAR_CONTROLLER_ADDR");
18+
19+
function run(string memory name, uint256 duration) external {
20+
console.log("-------------------------------");
21+
console.log("Minting name:");
22+
console.log(name);
23+
console.log("-------------------------------");
24+
25+
vm.startBroadcast(premintPrivateKey);
26+
27+
bytes32 label = keccak256(bytes(name));
28+
uint256 id = uint256(label);
29+
30+
if (!BaseRegistrar(BASE_REGISTRAR).isAvailable(id)) {
31+
console.log("Name already registered");
32+
return;
33+
}
34+
35+
// Premint name
36+
BaseRegistrar(BASE_REGISTRAR).registerOnly(id, BASE_ECOSYSTEM_MULTISIG, duration);
37+
38+
// Record name and id in csv
39+
string memory idStr = vm.toString(id);
40+
string memory data = LibString.concat(name, ",");
41+
data = LibString.concat(data, idStr);
42+
data = LibString.concat(data, "\n");
43+
string[] memory input = new string[](3);
44+
input[0] = "python3";
45+
input[1] = "py/writer.py";
46+
input[2] = data;
47+
vm.ffi(input);
48+
}
49+
50+
function verify(uint256 lines, string calldata file) public view {
51+
for (uint256 i; i < lines; i++) {
52+
string memory name = vm.readLine(file);
53+
bytes32 label = keccak256(bytes(name));
54+
uint256 id = uint256(label);
55+
if (BaseRegistrar(BASE_REGISTRAR).nameExpires(id) == 0) {
56+
console.log("Not minted: ", name);
57+
} else if (BaseRegistrar(BASE_REGISTRAR).ownerOf(id) != BASE_ECOSYSTEM_MULTISIG) {
58+
console.log("Not owned by ecosystem multisig", name);
59+
}
60+
}
61+
}
62+
}

0 commit comments

Comments
 (0)