@zoralabs/coins 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/.env.example +7 -0
  2. package/.turbo/turbo-build.log +49 -37
  3. package/CHANGELOG.md +6 -0
  4. package/README.md +29 -0
  5. package/abis/CoinTest.json +28 -0
  6. package/abis/Create2.json +28 -0
  7. package/abis/DeployScript.json +9 -0
  8. package/abis/DeterministicDeployerAndCaller.json +315 -0
  9. package/abis/DeterministicUUPSProxyDeployer.json +167 -0
  10. package/abis/FactoryTest.json +20 -0
  11. package/abis/GenerateDeterministicParams.json +9 -0
  12. package/abis/IERC165.json +1 -1
  13. package/abis/IERC20.json +42 -39
  14. package/abis/IImmutableCreate2Factory.json +93 -0
  15. package/abis/ISafe.json +15 -0
  16. package/abis/ISymbol.json +15 -0
  17. package/abis/ImmutableCreate2FactoryUtils.json +15 -0
  18. package/abis/LibString.json +7 -0
  19. package/abis/ProxyShim.json +112 -0
  20. package/abis/UUPSUpgradeable.json +15 -14
  21. package/abis/ZoraFactory.json +0 -5
  22. package/addresses/8453.json +5 -8
  23. package/addresses/84532.json +5 -8
  24. package/deterministicConfig/deployerAndCaller.json +5 -0
  25. package/deterministicConfig/zoraFactory.json +8 -0
  26. package/foundry.toml +14 -0
  27. package/package.json +3 -2
  28. package/remappings.txt +2 -1
  29. package/script/CoinsDeployerBase.sol +98 -0
  30. package/script/Deploy.s.sol +14 -5
  31. package/script/GenerateDeterministicParams.s.sol +43 -0
  32. package/src/Coin.sol +1 -1
  33. package/src/proxy/ZoraFactory.sol +7 -1
  34. package/src/utils/CoinConstants.sol +2 -2
  35. package/src/version/ContractVersionBase.sol +1 -1
  36. package/test/Coin.t.sol +119 -6
  37. package/test/Factory.t.sol +34 -11
  38. package/test/utils/BaseTest.sol +4 -4
  39. package/abis/Deploy.json +0 -29
  40. package/addresses/1.json +0 -4
@@ -0,0 +1,5 @@
1
+ {
2
+ "creationCode": "0x610180604052346101a1576040516100186040826101a5565b601e815260208101907f44657465726d696e69737469634465706c6f796572416e6443616c6c657200008252604051916100536040846101a5565b600183526020830191603160f81b835261006c816101c8565b610120526100798461035e565b61014052519020918260e05251902080610100524660a0526040519060208201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452604083015260608201524660808201523060a082015260a081526100e260c0826101a5565b5190206080523060c05260405161046b80820191906001600160401b0383118284101761018d575f928291610fbd8339039082f580156101825761016052604051610b269081610497823960805181610980015260a05181610a3d015260c0518161094a015260e051816109cf015261010051816109f50152610120518161025e0152610140518161028701526101605181818161035301526104bf0152f35b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b601f909101601f19168101906001600160401b0382119082101761018d57604052565b908151602081105f14610242575090601f8151116102025760208151910151602082106101f3571790565b5f198260200360031b1b161790565b604460209160405192839163305a27a960e01b83528160048401528051918291826024860152018484015e5f828201840152601f01601f19168101030190fd5b6001600160401b03811161018d575f54600181811c91168015610354575b602082101461034057601f811161030e575b50602092601f82116001146102af57928192935f926102a4575b50508160011b915f199060031b1c1916175f5560ff90565b015190505f8061028c565b601f198216935f8052805f20915f5b8681106102f657508360019596106102de575b505050811b015f5560ff90565b01515f1960f88460031b161c191690555f80806102d1565b919260206001819286850151815501940192016102be565b5f8052601f60205f20910160051c810190601f830160051c015b8181106103355750610272565b5f8155600101610328565b634e487b7160e01b5f52602260045260245ffd5b90607f1690610260565b908151602081105f14610389575090601f8151116102025760208151910151602082106101f3571790565b6001600160401b03811161018d57600154600181811c9116801561048c575b602082101461034057601f8111610459575b50602092601f82116001146103f857928192935f926103ed575b50508160011b915f199060031b1c19161760015560ff90565b015190505f806103d4565b601f1982169360015f52805f20915f5b8681106104415750836001959610610429575b505050811b0160015560ff90565b01515f1960f88460031b161c191690555f808061041b565b91926020600181928685015181550194019201610408565b60015f52601f60205f20910160051c810190601f830160051c015b81811061048157506103ba565b5f8155600101610474565b90607f16906103a856fe60806040526004361015610011575f80fd5b5f3560e01c806325746d39146103825780637db68ec41461033e57806384b0196e1461024657806386881034146101cf578063e3867c2914610105578063eae49c87146100d25763f9baed1814610066575f80fd5b346100ce5760603660031901126100ce5760243567ffffffffffffffff81116100ce57610097903690600401610449565b60443567ffffffffffffffff81116100ce576020916100bd6100c6923690600401610449565b906004356104f6565b604051908152f35b5f80fd5b346100ce575f3660031901126100ce576101016100ed6104b3565b60405191829160208352602083019061048f565b0390f35b60a03660031901126100ce5760043567ffffffffffffffff81116100ce57610131903690600401610449565b6024359060443567ffffffffffffffff81116100ce57610155903690600401610449565b60643567ffffffffffffffff81116100ce57610175903690600401610449565b608435916001600160a01b03831683036100ce57846101b8816101b36101aa6101bd986101a5888860209d6104f6565b610899565b909291926108d3565b61057a565b6105a8565b6040516001600160a01b039091168152f35b346100ce5760203660031901126100ce5760043567ffffffffffffffff81116100ce5760206100ed610208610101933690600401610449565b82806102126104b3565b6040519584879551918291018487015e8401908282015f8152815193849201905e01015f815203601f1981018352826103f7565b346100ce575f3660031901126100ce576102e26102827f00000000000000000000000000000000000000000000000000000000000000006106a6565b6102ab7f00000000000000000000000000000000000000000000000000000000000000006107c9565b60206102f0604051926102be83856103f7565b5f84525f368137604051958695600f60f81b875260e08588015260e087019061048f565b90858203604087015261048f565b4660608501523060808501525f60a085015283810360c08501528180845192838152019301915f5b82811061032757505050500390f35b835185528695509381019392810192600101610318565b346100ce575f3660031901126100ce576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b60803660031901126100ce5760043560243567ffffffffffffffff81116100ce576103b1903690600401610449565b9060443567ffffffffffffffff81116100ce576103d2903690600401610449565b606435906001600160a01b03821682036100ce57602093836101b86101bd953361057a565b90601f8019910116810190811067ffffffffffffffff82111761041957604052565b634e487b7160e01b5f52604160045260245ffd5b67ffffffffffffffff811161041957601f01601f191660200190565b81601f820112156100ce578035906104608261042d565b9261046e60405194856103f7565b828452602083830101116100ce57815f926020809301838601378301015290565b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b60405160018060a01b037f0000000000000000000000000000000000000000000000000000000000000000166020820152602081526104f36040826103f7565b90565b90916042926020815191012090602081519101206040519160208301937fdc039731015eea17e316614c8f3af7dca5fc4664683c8e8f2adc4e0ff71a7c9285526040840152606083015260808201526080815261055460a0826103f7565b51902061055f610947565b906040519161190160f01b8352600283015260228201522090565b6001600160a01b0316606082901c819003610593575050565b632696d3f160e11b5f5260045260245260445ffd5b919290805191600b602083019384206040519060408201528560208201523081520160ff8153605590206001600160a01b0390811691168181036106915750508051156106825751905ff5906001600160a01b03821615610673575f816020829351910182855af13d1561066b573d906106218261042d565b9161062f60405193846103f7565b82523d5f602084013e5b15610642575090565b60405163a5fa8d2b60e01b81526020600482015290819061066790602483019061048f565b0390fd5b606090610639565b633a0ba96160e11b5f5260045ffd5b631328927760e21b5f5260045ffd5b6312ae30e560e01b5f5260045260245260445ffd5b60ff81146106ec5760ff811690601f82116106dd57604051916106ca6040846103f7565b6020808452838101919036833783525290565b632cd44ac360e21b5f5260045ffd5b506040515f5f548060011c91600182169182156107bf575b6020841083146107ab57838552849290811561078c575060011461072f575b6104f3925003826103f7565b505f80805290917f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8183106107705750509060206104f392820101610723565b6020919350806001915483858801015201910190918392610758565b602092506104f394915060ff191682840152151560051b820101610723565b634e487b7160e01b5f52602260045260245ffd5b92607f1692610704565b60ff81146107ed5760ff811690601f82116106dd57604051916106ca6040846103f7565b506040515f6001548060011c916001821691821561088f575b6020841083146107ab57838552849290811561078c5750600114610830576104f3925003826103f7565b5060015f90815290917fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8183106108735750509060206104f392820101610723565b602091935080600191548385880101520191019091839261085b565b92607f1692610806565b81519190604183036108c9576108c29250602082015190606060408401519301515f1a90610a63565b9192909190565b50505f9160029190565b600481101561093357806108e5575050565b600181036108fc5763f645eedf60e01b5f5260045ffd5b60028103610917575063fce698f760e01b5f5260045260245ffd5b6003146109215750565b6335e2f38360e21b5f5260045260245ffd5b634e487b7160e01b5f52602160045260245ffd5b307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161480610a3a575b156109a2577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a08152610a3460c0826103f7565b51902090565b507f00000000000000000000000000000000000000000000000000000000000000004614610979565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411610ae5579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa15610ada575f516001600160a01b03811615610ad057905f905f90565b505f906001905f90565b6040513d5f823e3d90fd5b5050505f916003919056fea264697066735822122020d4cc29643fbc137d039c78a8d78f52fd9a09b7daa1a5943440ff9a3e8ea56f64736f6c634300081c003360c08060405234603257306080523360a0526104349081610037823960805181818160ae015261018b015260a051815050f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c80634f1ef2861461010257806352d1902d1461009c5763ad3cb1cc1461003a575f80fd5b34610098575f366003190112610098576040805190610059818361032e565b600582526020820191640352e302e360dc1b83528151928391602083525180918160208501528484015e5f828201840152601f01601f19168101030190f35b5f80fd5b34610098575f366003190112610098577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036100f35760206040515f5160206103df5f395f51905f528152f35b63703e46dd60e11b5f5260045ffd5b6040366003190112610098576004356001600160a01b03811690818103610098576024359067ffffffffffffffff821161009857366023830112156100985781600401359161015083610364565b9261015e604051948561032e565b8084526020840191366024838301011161009857815f926024602093018537850101526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630811490811561030c575b506100f3576040516352d1902d60e01b8152602081600481885afa5f91816102d8575b506101f15784634c9c8ce360e01b5f5260045260245ffd5b805f5160206103df5f395f51905f528692036102c65750823b156102b4575f5160206103df5f395f51905f5280546001600160a01b031916821790557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a282511561029b575f8091610291945190845af43d15610293573d9161027583610364565b92610283604051948561032e565b83523d5f602085013e610380565b005b606091610380565b505050346102a557005b63b398979f60e01b5f5260045ffd5b634c9c8ce360e01b5f5260045260245ffd5b632a87526960e21b5f5260045260245ffd5b9091506020813d602011610304575b816102f46020938361032e565b81010312610098575190866101d9565b3d91506102e7565b5f5160206103df5f395f51905f52546001600160a01b031614159050856101b6565b90601f8019910116810190811067ffffffffffffffff82111761035057604052565b634e487b7160e01b5f52604160045260245ffd5b67ffffffffffffffff811161035057601f01601f191660200190565b906103a4575080511561039557805190602001fd5b630a12f52160e11b5f5260045ffd5b815115806103d5575b6103b5575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156103ad56fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca264697066735822122005f8ca25544854f7fe07eac3cac751ac5b35b9a8529e80352f19449570409c3364736f6c634300081c0033",
3
+ "deployedAddress": "0xCB571Eaa13A8276B1Ed44348291dD80b5BC360dA",
4
+ "salt": "0x0000000000000000000000000000000000000000000000000000000000000000"
5
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "constructorArgs": "0x00000000000000000000000015b56e81f8a628aab8a5a8b9414f05cf5728d1ff",
3
+ "contractName": "Zora",
4
+ "creationCode": "0x60a06040523461016c575f61028a6020813803918261001d81610170565b93849283398101031261016c5751906001600160a01b03821680830361016c576100476020610170565b905f8252833b1561015a577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b031916821790557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a280511561015257818160208293519101855af43d15610145573d926001600160401b038411610131576100f7936100e7601f8201601f1916602001610170565b908152809360203d92013e6101a9565b505b7fffd9efbec42a225861234c46dd9ad199e6b6c0e9dc65ff463e6987cedc26d6a1608052604051608290816102088239608051815050f35b634e487b7160e01b83526041600452602483fd5b6100f792606092506101a9565b5050506100f9565b634c9c8ce360e01b5f5260045260245ffd5b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761019557604052565b634e487b7160e01b5f52604160045260245ffd5b906101cd57508051156101be57805190602001fd5b630a12f52160e11b5f5260045ffd5b815115806101fe575b6101de575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156101d656fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea2646970667358221220d17864a0488eaaba33173ba368bd2448917739c58ea27a5b985e8b13c01d346664736f6c634300081c003300000000000000000000000015b56e81f8a628aab8a5a8b9414f05cf5728d1ff",
5
+ "deployedAddress": "0x777777751622c0d3258f214F9DF38E35BF45baF3",
6
+ "deploymentCaller": "0x680E26B472d8cae8148ee21FCAd6A69D73766436",
7
+ "salt": "0x680e26b472d8cae8148ee21fcad6a69d73766436f27a901327372bd2be5d38f6"
8
+ }
package/foundry.toml CHANGED
@@ -4,6 +4,20 @@ test = "test"
4
4
  libs = ["node_modules"]
5
5
  via_ir = true
6
6
  optimizer = true
7
+ solc_version = '0.8.28'
8
+ optimizer_runs = 200
9
+ fs_permissions = [
10
+ { access = "readwrite", path = "./addresses" },
11
+ { access = "read", path = "./package.json" },
12
+ { access = "readwrite", path = "./deterministicConfig" },
13
+ { access = "read", path = "../shared-contracts/chainConfigs" },
14
+ { access = "read", path = "../shared-contracts/deterministicConfig" }
15
+ ]
7
16
 
8
17
  [profile.ci.fuzz]
9
18
  runs = 1000
19
+
20
+ [rpc_endpoints]
21
+ base = "https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
22
+ mainnet = "https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
23
+ zora = "https://rpc.zora.energy"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zoralabs/coins",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -25,12 +25,13 @@
25
25
  "forge-std": "https://github.com/foundry-rs/forge-std#v1.9.1",
26
26
  "prettier": "^3.0.3",
27
27
  "prettier-plugin-solidity": "^1.4.1",
28
+ "solady": "0.0.132",
28
29
  "tsup": "^7.2.0",
29
30
  "tsx": "^3.13.0",
30
31
  "typescript": "^5.2.2",
31
32
  "viem": "^2.21.18",
32
- "@zoralabs/shared-scripts": "^0.0.0",
33
33
  "@zoralabs/shared-contracts": "^0.0.1",
34
+ "@zoralabs/shared-scripts": "^0.0.0",
34
35
  "@zoralabs/tsconfig": "^0.0.1"
35
36
  },
36
37
  "scripts": {
package/remappings.txt CHANGED
@@ -1,4 +1,5 @@
1
1
  ds-test/=node_modules/ds-test/src/
2
2
  forge-std/=node_modules/forge-std/src/
3
3
  @openzeppelin/=node_modules/@openzeppelin/
4
- @zoralabs/shared-contracts/=node_modules/@zoralabs/shared-contracts/src/
4
+ @zoralabs/shared-contracts/=node_modules/@zoralabs/shared-contracts/src/
5
+ solady/=node_modules/solady/src/
@@ -0,0 +1,98 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.28;
3
+
4
+ import "forge-std/Script.sol";
5
+
6
+ import {ProxyDeployerScript, DeterministicContractConfig, DeterministicDeployerAndCaller} from "@zoralabs/shared-contracts/deployment/ProxyDeployerScript.sol";
7
+ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
8
+ import {ZoraFactoryImpl} from "../src/ZoraFactoryImpl.sol";
9
+ import {Coin} from "../src/Coin.sol";
10
+ import {IVersionedContract} from "@zoralabs/shared-contracts/interfaces/IVersionedContract.sol";
11
+
12
+ contract CoinsDeployerBase is ProxyDeployerScript {
13
+ address internal constant PROTOCOL_REWARDS = 0x7777777F279eba3d3Ad8F4E708545291A6fDBA8B;
14
+
15
+ using stdJson for string;
16
+
17
+ struct CoinsDeployment {
18
+ // Factory
19
+ address zoraFactory;
20
+ address zoraFactoryImpl;
21
+ // Implementation
22
+ address coinImpl;
23
+ string coinVersion;
24
+ }
25
+
26
+ function addressesFile() internal view returns (string memory) {
27
+ return string.concat("./addresses/", vm.toString(block.chainid), ".json");
28
+ }
29
+
30
+ function saveDeployment(CoinsDeployment memory deployment) internal {
31
+ string memory objectKey = "config";
32
+
33
+ vm.serializeAddress(objectKey, "ZORA_FACTORY", deployment.zoraFactory);
34
+ vm.serializeAddress(objectKey, "ZORA_FACTORY_IMPL", deployment.zoraFactoryImpl);
35
+ vm.serializeString(objectKey, "COIN_VERSION", deployment.coinVersion);
36
+ string memory result = vm.serializeAddress(objectKey, "COIN_IMPL", deployment.coinImpl);
37
+
38
+ vm.writeJson(result, addressesFile());
39
+ }
40
+
41
+ function readDeployment() internal returns (CoinsDeployment memory deployment) {
42
+ string memory file = addressesFile();
43
+ if (!vm.exists(file)) {
44
+ return deployment;
45
+ }
46
+ string memory json = vm.readFile(file);
47
+
48
+ deployment.zoraFactory = readAddressOrDefaultToZero(json, "ZORA_FACTORY");
49
+ deployment.zoraFactoryImpl = readAddressOrDefaultToZero(json, "ZORA_FACTORY_IMPL");
50
+ deployment.coinImpl = readAddressOrDefaultToZero(json, "COIN_IMPL");
51
+ deployment.coinVersion = readStringOrDefaultToEmpty(json, "COIN_VERSION");
52
+ }
53
+
54
+ function deployCoinImpl() internal returns (Coin) {
55
+ return new Coin(getZoraRecipient(), PROTOCOL_REWARDS, getWeth(), getNonFungiblePositionManager(), getUniswapSwapRouter());
56
+ }
57
+
58
+ function deployZoraFactoryImpl(address coinImpl) internal returns (ZoraFactoryImpl) {
59
+ return new ZoraFactoryImpl(coinImpl);
60
+ }
61
+
62
+ function deployZoraDeterministic(CoinsDeployment memory deployment, DeterministicDeployerAndCaller deployer) internal {
63
+ // read previously saved deterministic config
64
+ DeterministicContractConfig memory zoraConfig = readDeterministicContractConfig("zoraFactory");
65
+
66
+ // Deploy implementation contracts
67
+ deployment.coinImpl = address(deployCoinImpl());
68
+ deployment.zoraFactoryImpl = address(deployZoraFactoryImpl(deployment.coinImpl));
69
+ deployment.coinVersion = IVersionedContract(deployment.coinImpl).contractVersion();
70
+
71
+ if (deployment.zoraFactoryImpl.code.length == 0) {
72
+ revert("Factory Impl not yet deployed. Make sure to deploy it with DeployImpl.s.sol");
73
+ }
74
+
75
+ // build upgrade to and call for factory, with init call
76
+ bytes memory upgradeToAndCall = abi.encodeWithSelector(
77
+ UUPSUpgradeable.upgradeToAndCall.selector,
78
+ deployment.zoraFactoryImpl,
79
+ abi.encodeWithSelector(ZoraFactoryImpl.initialize.selector, getProxyAdmin())
80
+ );
81
+
82
+ // sign deployment with turnkey account
83
+ bytes memory signature = signDeploymentWithTurnkey(zoraConfig, upgradeToAndCall, deployer);
84
+
85
+ printVerificationCommand(zoraConfig);
86
+
87
+ deployment.zoraFactory = deployer.permitSafeCreate2AndCall(
88
+ signature,
89
+ zoraConfig.salt,
90
+ zoraConfig.creationCode,
91
+ upgradeToAndCall,
92
+ zoraConfig.deployedAddress
93
+ );
94
+
95
+ // validate that the zora factory owner is the proxy admin
96
+ require(ZoraFactoryImpl(deployment.zoraFactory).owner() == getProxyAdmin(), "Zora factory owner is not the proxy admin");
97
+ }
98
+ }
@@ -1,14 +1,23 @@
1
1
  // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.13;
2
+ pragma solidity ^0.8.28;
3
3
 
4
- import {Script, console} from "forge-std/Script.sol";
5
-
6
- contract Deploy is Script {
7
- function setUp() public {}
4
+ import {ProxyDeployerScript, DeterministicDeployerAndCaller} from "@zoralabs/shared-contracts/deployment/ProxyDeployerScript.sol";
5
+ import {CoinsDeployerBase} from "./CoinsDeployerBase.sol";
8
6
 
7
+ contract DeployScript is CoinsDeployerBase {
9
8
  function run() public {
9
+ CoinsDeployment memory deployment = readDeployment();
10
+
10
11
  vm.startBroadcast();
11
12
 
13
+ // get deployer contract
14
+ DeterministicDeployerAndCaller deployer = createOrGetDeployerAndCaller();
15
+
16
+ deployZoraDeterministic(deployment, deployer);
17
+
12
18
  vm.stopBroadcast();
19
+
20
+ // save the deployment json
21
+ saveDeployment(deployment);
13
22
  }
14
23
  }
@@ -0,0 +1,43 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.28;
3
+
4
+ import "forge-std/Script.sol";
5
+
6
+ import {ImmutableCreate2FactoryUtils} from "@zoralabs/shared-contracts/utils/ImmutableCreate2FactoryUtils.sol";
7
+ import {ProxyDeployerScript, DeterministicDeployerAndCaller, DeterministicContractConfig} from "@zoralabs/shared-contracts/deployment/ProxyDeployerScript.sol";
8
+ import {ZoraFactory} from "../src/proxy/ZoraFactory.sol";
9
+
10
+ contract GenerateDeterministicParams is ProxyDeployerScript {
11
+ function mineForZoraAddress(DeterministicDeployerAndCaller deployer, address caller) private returns (DeterministicContractConfig memory config) {
12
+ // get proxy creation code
13
+ bytes memory initCode = deployer.proxyCreationCode(type(ZoraFactory).creationCode);
14
+ bytes32 initCodeHash = keccak256(initCode);
15
+
16
+ // uupsProxyDeployer is deployer
17
+ (bytes32 salt, address expectedAddress) = mineSalt(address(deployer), initCodeHash, "7777777", caller);
18
+
19
+ console2.log("salt");
20
+ console2.log(vm.toString(salt));
21
+
22
+ config.salt = salt;
23
+ config.deployedAddress = expectedAddress;
24
+ config.creationCode = initCode;
25
+ config.constructorArgs = deployer.proxyConstructorArgs();
26
+ config.contractName = "Zora";
27
+ config.deploymentCaller = caller;
28
+ }
29
+
30
+ function run() public {
31
+ address caller = vm.envAddress("DEPLOYER");
32
+
33
+ vm.startBroadcast();
34
+
35
+ // create a proxy deployer, which we can use to generate deterministic addresses and corresponding params
36
+ DeterministicDeployerAndCaller deployer = createOrGetDeployerAndCaller();
37
+
38
+ vm.stopBroadcast();
39
+
40
+ DeterministicContractConfig memory zoraConfig = mineForZoraAddress(deployer, caller);
41
+ saveDeterministicContractConfig(zoraConfig, "zoraFactory");
42
+ }
43
+ }
package/src/Coin.sol CHANGED
@@ -350,7 +350,7 @@ contract Coin is ICoin, CoinConstants, ContractVersionBase, ERC20PermitUpgradeab
350
350
  /// @dev Deploy the pool
351
351
  function _deployPool(int24 tickLower_) internal {
352
352
  // If WETH is the pool's currency, validate the lower tick
353
- if (currency == WETH && tickLower_ != LP_TICK_LOWER_WETH) {
353
+ if (currency == WETH && tickLower_ < LP_TICK_LOWER_WETH) {
354
354
  revert InvalidWethLowerTick();
355
355
  }
356
356
 
@@ -22,5 +22,11 @@ import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.s
22
22
  OURS TRULY,
23
23
  */
24
24
  contract ZoraFactory is ERC1967Proxy {
25
- constructor(address _logic, bytes memory _data) ERC1967Proxy(_logic, _data) {}
25
+ bytes32 internal immutable name;
26
+
27
+ constructor(address _logic) ERC1967Proxy(_logic, "") {
28
+ // added to create unique bytecode for this contract
29
+ // so that it can be properly verified as its own contract.
30
+ name = keccak256("ZoraFactory");
31
+ }
26
32
  }
@@ -50,9 +50,9 @@ abstract contract CoinConstants {
50
50
  /// @dev 10000 basis points = 1%
51
51
  uint24 internal constant LP_FEE = 10000;
52
52
 
53
- /// @notice The LP's lower tick
53
+ /// @notice The LP's minimum lower tick
54
54
  /// @dev This is only used if the currency is WETH
55
- int24 internal constant LP_TICK_LOWER_WETH = -199200;
55
+ int24 internal constant LP_TICK_LOWER_WETH = -208200;
56
56
 
57
57
  /// @notice The LP's upper tick
58
58
  int24 internal constant LP_TICK_UPPER = 887200;
@@ -9,6 +9,6 @@ import {IVersionedContract} from "@zoralabs/shared-contracts/interfaces/IVersion
9
9
  contract ContractVersionBase is IVersionedContract {
10
10
  /// @notice The version of the contract
11
11
  function contractVersion() external pure override returns (string memory) {
12
- return "0.5.0";
12
+ return "0.6.0";
13
13
  }
14
14
  }
package/test/Coin.t.sol CHANGED
@@ -2,6 +2,7 @@
2
2
  pragma solidity ^0.8.13;
3
3
 
4
4
  import "./utils/BaseTest.sol";
5
+ import {ISwapRouter} from "../src/interfaces/ISwapRouter.sol";
5
6
 
6
7
  contract CoinTest is BaseTest {
7
8
  function setUp() public override {
@@ -11,7 +12,7 @@ contract CoinTest is BaseTest {
11
12
  }
12
13
 
13
14
  function test_contract_version() public view {
14
- assertEq(coin.contractVersion(), "0.5.0");
15
+ assertEq(coin.contractVersion(), "0.6.0");
15
16
  }
16
17
 
17
18
  function test_supply_constants() public view {
@@ -199,6 +200,82 @@ contract CoinTest is BaseTest {
199
200
  assertGe(coin.balanceOf(users.coinRecipient), amountOut, "coinRecipient coin balance");
200
201
  }
201
202
 
203
+ function test_sell_for_eth_direct_and_claim_secondary() public {
204
+ vm.deal(users.buyer, 1 ether);
205
+
206
+ vm.prank(users.buyer);
207
+ weth.deposit{value: 100_000}();
208
+
209
+ vm.prank(users.buyer);
210
+ weth.approve(address(swapRouter), 100_000);
211
+
212
+ // Set up the swap parameters
213
+ ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
214
+ tokenIn: WETH_ADDRESS,
215
+ tokenOut: address(coin),
216
+ fee: LP_FEE,
217
+ recipient: address(users.buyer),
218
+ amountIn: 100_000,
219
+ amountOutMinimum: 0,
220
+ sqrtPriceLimitX96: 0
221
+ });
222
+
223
+ // Execute the swap
224
+ vm.prank(users.buyer);
225
+ uint256 amountOut = ISwapRouter(swapRouter).exactInputSingle(params);
226
+
227
+ assertEq(coin.balanceOf(users.buyer), 108941722423358, "buyer coin balance");
228
+ assertEq(amountOut, 108941722423358);
229
+ assertGt(users.buyer.balance, 0, "seller eth balance");
230
+
231
+ // now we have unclaimed secondary rewards to claim
232
+ vm.prank(users.buyer);
233
+
234
+ // don't push ETH
235
+ coin.claimSecondaryRewards(false);
236
+ assertEq(protocolRewards.balanceOf(users.creator), 499);
237
+ assertEq(protocolRewards.balanceOf(users.platformReferrer), 249);
238
+ assertEq(protocolRewards.balanceOf(users.feeRecipient), 251);
239
+ }
240
+
241
+ function test_sell_for_eth_direct_and_claim_secondary_push_eth() public {
242
+ vm.deal(users.buyer, 1 ether);
243
+
244
+ vm.prank(users.buyer);
245
+ weth.deposit{value: 100_000}();
246
+
247
+ vm.prank(users.buyer);
248
+ weth.approve(address(swapRouter), 100_000);
249
+
250
+ // Set up the swap parameters
251
+ ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
252
+ tokenIn: WETH_ADDRESS,
253
+ tokenOut: address(coin),
254
+ fee: LP_FEE,
255
+ recipient: address(users.buyer),
256
+ amountIn: 100_000,
257
+ amountOutMinimum: 0,
258
+ sqrtPriceLimitX96: 0
259
+ });
260
+
261
+ // Execute the swap
262
+ vm.prank(users.buyer);
263
+ uint256 amountOut = ISwapRouter(swapRouter).exactInputSingle(params);
264
+
265
+ assertEq(coin.balanceOf(users.buyer), 108941722423358, "buyer coin balance");
266
+ assertEq(amountOut, 108941722423358);
267
+ assertGt(users.buyer.balance, 0, "seller eth balance");
268
+
269
+ // Now we have unclaimed secondary rewards to claim
270
+ vm.prank(users.buyer);
271
+
272
+ uint256 initialBalance = users.creator.balance;
273
+
274
+ // Push ETH
275
+ coin.claimSecondaryRewards(true);
276
+ assertEq(users.creator.balance - initialBalance, 499);
277
+ }
278
+
202
279
  function test_sell_for_eth() public {
203
280
  vm.deal(users.buyer, 1 ether);
204
281
  vm.prank(users.buyer);
@@ -284,18 +361,18 @@ contract CoinTest is BaseTest {
284
361
  coin.buy{value: 0.001 ether}(users.creator, 0.001 ether, 0, 0, users.tradeReferrer);
285
362
 
286
363
  uint256 beforeBalance = coin.balanceOf(users.creator);
287
- assertEq(beforeBalance, 10438320330337104517114132); // 10,438,320 coins
364
+ assertEq(beforeBalance, 11077349369032224007213331); // 11,077,349 coins
288
365
 
289
366
  vm.prank(users.creator);
290
367
  (uint256 amountSold, ) = coin.sell(users.creator, beforeBalance, 0, 0, users.tradeReferrer);
291
- assertEq(amountSold, 442747808421317694054680); // 442,747 coins (max that could be sold)
368
+ assertEq(amountSold, 1088231685891135360821548); // 1,088,232 coins (max that could be sold)
292
369
 
293
370
  uint256 afterBalance = coin.balanceOf(users.creator);
294
- assertEq(afterBalance, 9997786260957893411529725); // 9,997,786 coins
371
+ assertEq(afterBalance, 9994558841570544323195890); // 9,994,559 coins
295
372
 
296
- uint256 expectedMarketReward = 2213739042106588470273; // 2,213 coins
373
+ uint256 expectedMarketReward = 5441158429455676804107; // 5,441 coins
297
374
 
298
- // 9,997,786 = 10,438,320 order size - 442,747 true order size + 2,213 creator market reward
375
+ // 9,994,559 = 11,077,349 order size - 1,088,232 true order size + 5,441 creator market reward
299
376
  assertEq(afterBalance, ((beforeBalance - amountSold) + expectedMarketReward), "amountSold");
300
377
  }
301
378
 
@@ -361,6 +438,42 @@ contract CoinTest is BaseTest {
361
438
  assertGt(protocolRewards.balanceOf(users.feeRecipient), expectedFees.platformReferrer, "feeRecipient eth balance");
362
439
  }
363
440
 
441
+ function test_invalid_weth_tick() public {
442
+ address[] memory owners = new address[](1);
443
+ owners[0] = users.creator;
444
+
445
+ vm.expectRevert(ICoin.InvalidWethLowerTick.selector);
446
+ (address newCoinAddr, ) = factory.deploy(
447
+ users.creator,
448
+ owners,
449
+ "https://test.com",
450
+ "Test Token",
451
+ "TEST",
452
+ users.platformReferrer,
453
+ address(weth),
454
+ LP_TICK_LOWER_WETH - 1,
455
+ 0
456
+ );
457
+ }
458
+
459
+ function test_invalid_currency_tick() public {
460
+ address[] memory owners = new address[](1);
461
+ owners[0] = users.creator;
462
+
463
+ vm.expectRevert(ICoin.InvalidCurrencyLowerTick.selector);
464
+ (address newCoinAddr, ) = factory.deploy(
465
+ users.creator,
466
+ owners,
467
+ "https://test.com",
468
+ "Test Token",
469
+ "TEST",
470
+ users.platformReferrer,
471
+ address(0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913),
472
+ 20,
473
+ 0
474
+ );
475
+ }
476
+
364
477
  function test_default_order_referrer() public {
365
478
  vm.deal(users.buyer, 1 ether);
366
479
  vm.prank(users.buyer);
@@ -96,6 +96,35 @@ contract FactoryTest is BaseTest {
96
96
  console.log("BUYER_COIN_BALANCE ", coin.balanceOf(users.creator) - 10_000_000e18);
97
97
  }
98
98
 
99
+ function test_deploy_with_weth(uint256 initialOrderSize) public {
100
+ vm.assume(initialOrderSize > MIN_ORDER_SIZE);
101
+ vm.assume(initialOrderSize < 10 ether);
102
+
103
+ address[] memory owners = new address[](1);
104
+ owners[0] = users.creator;
105
+
106
+ vm.deal(users.creator, initialOrderSize);
107
+
108
+ vm.startPrank(users.creator);
109
+ weth.deposit{value: initialOrderSize}();
110
+
111
+ weth.approve(address(factory), type(uint256).max);
112
+
113
+ // Expect this to revert because WETH needs to be sent with msg.value.
114
+ vm.expectRevert();
115
+ factory.deploy(
116
+ users.creator,
117
+ owners,
118
+ "https://test2.com",
119
+ "Test2 Token",
120
+ "TEST2",
121
+ users.platformReferrer,
122
+ address(weth),
123
+ LP_TICK_LOWER_WETH,
124
+ initialOrderSize
125
+ );
126
+ }
127
+
99
128
  function test_deploy_with_one_eth() public {
100
129
  address[] memory owners = new address[](1);
101
130
  owners[0] = users.creator;
@@ -206,17 +235,7 @@ contract FactoryTest is BaseTest {
206
235
 
207
236
  vm.expectRevert(abi.encodeWithSelector(ICoin.InvalidWethLowerTick.selector));
208
237
 
209
- factory.deploy(
210
- users.creator,
211
- owners,
212
- "https://testcoinusdcpair.com",
213
- "Testcoinusdcpair",
214
- "TESTCOINUSDCPAIR",
215
- users.platformReferrer,
216
- address(0),
217
- USDC_TICK_LOWER,
218
- 0
219
- );
238
+ factory.deploy(users.creator, owners, "https://testcoin.com", "Testcoin", "TESTCOIN", users.platformReferrer, address(0), LP_TICK_LOWER_WETH - 1, 0);
220
239
  }
221
240
 
222
241
  function test_deploy_with_usdc_revert_invalid_eth_transfer() public {
@@ -272,6 +291,10 @@ contract FactoryTest is BaseTest {
272
291
  assertEq(factory.implementation(), address(newImpl), "implementation");
273
292
  }
274
293
 
294
+ function test_implementation_address() public view {
295
+ assertEq(factory.implementation(), address(factoryImpl));
296
+ }
297
+
275
298
  function test_revert_invalid_upgrade_impl() public {
276
299
  address newImpl = address(this);
277
300
 
@@ -59,7 +59,7 @@ contract BaseTest is Test, CoinConstants {
59
59
  IUniswapV3Pool internal pool;
60
60
 
61
61
  function setUp() public virtual {
62
- forkId = vm.createSelectFork("https://mainnet.base.org", 21179722);
62
+ forkId = vm.createSelectFork("base", 21179722);
63
63
 
64
64
  weth = IWETH(WETH_ADDRESS);
65
65
  usdc = IERC20Metadata(USDC_ADDRESS);
@@ -80,9 +80,9 @@ contract BaseTest is Test, CoinConstants {
80
80
 
81
81
  coinImpl = new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER);
82
82
  factoryImpl = new ZoraFactoryImpl(address(coinImpl));
83
- factory = ZoraFactoryImpl(
84
- address(new ZoraFactory(address(factoryImpl), abi.encodeWithSelector(ZoraFactoryImpl.initialize.selector, users.factoryOwner)))
85
- );
83
+ factory = ZoraFactoryImpl(address(new ZoraFactory(address(factoryImpl))));
84
+
85
+ ZoraFactoryImpl(factory).initialize(users.factoryOwner);
86
86
 
87
87
  vm.label(address(factory), "ZORA_FACTORY");
88
88
  vm.label(address(protocolRewards), "PROTOCOL_REWARDS");
package/abis/Deploy.json DELETED
@@ -1,29 +0,0 @@
1
- [
2
- {
3
- "type": "function",
4
- "name": "IS_SCRIPT",
5
- "inputs": [],
6
- "outputs": [
7
- {
8
- "name": "",
9
- "type": "bool",
10
- "internalType": "bool"
11
- }
12
- ],
13
- "stateMutability": "view"
14
- },
15
- {
16
- "type": "function",
17
- "name": "run",
18
- "inputs": [],
19
- "outputs": [],
20
- "stateMutability": "nonpayable"
21
- },
22
- {
23
- "type": "function",
24
- "name": "setUp",
25
- "inputs": [],
26
- "outputs": [],
27
- "stateMutability": "nonpayable"
28
- }
29
- ]
package/addresses/1.json DELETED
@@ -1,4 +0,0 @@
1
- {
2
- "WETH": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
3
- "UniswapQuoter": "0x61fFE014bA17989E743c5F6cB21bF9697530B21e"
4
- }