@zoralabs/coins 0.4.0 → 0.5.1-sdkalpha.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.
- package/.env.example +7 -0
- package/.turbo/turbo-build.log +93 -74
- package/CHANGELOG.md +12 -0
- package/README.md +29 -0
- package/abis/Coin.json +10 -0
- package/abis/CoinTest.json +55 -0
- package/abis/Create2.json +28 -0
- package/abis/DeployScript.json +9 -0
- package/abis/DeterministicDeployerAndCaller.json +315 -0
- package/abis/DeterministicUUPSProxyDeployer.json +167 -0
- package/abis/FactoryTest.json +20 -0
- package/abis/GenerateDeterministicParams.json +9 -0
- package/abis/ICoin.json +10 -0
- package/abis/IImmutableCreate2Factory.json +93 -0
- package/abis/ISafe.json +15 -0
- package/abis/ISymbol.json +15 -0
- package/abis/ImmutableCreate2FactoryUtils.json +15 -0
- package/abis/LibString.json +7 -0
- package/abis/ProxyShim.json +112 -0
- package/abis/ZoraFactory.json +0 -5
- package/addresses/8453.json +5 -8
- package/addresses/84532.json +5 -8
- package/deterministicConfig/deployerAndCaller.json +5 -0
- package/deterministicConfig/zoraFactory.json +8 -0
- package/dist/index.cjs +100 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +96 -3
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +475 -0
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/foundry.toml +14 -0
- package/integration/.env +2 -0
- package/lcov.info +634 -0
- package/package/wagmiGenerated.ts +111 -2
- package/package.json +4 -3
- package/remappings.txt +2 -1
- package/script/CoinsDeployerBase.sol +98 -0
- package/script/Deploy.s.sol +14 -5
- package/script/GenerateDeterministicParams.s.sol +43 -0
- package/src/Coin.sol +25 -7
- package/src/ZoraFactoryImpl.sol +2 -2
- package/src/interfaces/ICoin.sol +8 -2
- package/src/proxy/ZoraFactory.sol +7 -1
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/Coin.t.sol +152 -4
- package/test/Factory.t.sol +33 -0
- package/test/utils/BaseTest.sol +4 -4
- package/wagmi.config.ts +7 -1
- package/abis/Deploy.json +0 -29
- package/addresses/1.json +0 -4
|
@@ -146,7 +146,10 @@ export const coinABI = [
|
|
|
146
146
|
{ name: 'tradeReferrer', internalType: 'address', type: 'address' },
|
|
147
147
|
],
|
|
148
148
|
name: 'buy',
|
|
149
|
-
outputs: [
|
|
149
|
+
outputs: [
|
|
150
|
+
{ name: '', internalType: 'uint256', type: 'uint256' },
|
|
151
|
+
{ name: '', internalType: 'uint256', type: 'uint256' },
|
|
152
|
+
],
|
|
150
153
|
stateMutability: 'payable',
|
|
151
154
|
},
|
|
152
155
|
{
|
|
@@ -352,7 +355,10 @@ export const coinABI = [
|
|
|
352
355
|
{ name: 'tradeReferrer', internalType: 'address', type: 'address' },
|
|
353
356
|
],
|
|
354
357
|
name: 'sell',
|
|
355
|
-
outputs: [
|
|
358
|
+
outputs: [
|
|
359
|
+
{ name: '', internalType: 'uint256', type: 'uint256' },
|
|
360
|
+
{ name: '', internalType: 'uint256', type: 'uint256' },
|
|
361
|
+
],
|
|
356
362
|
stateMutability: 'nonpayable',
|
|
357
363
|
},
|
|
358
364
|
{
|
|
@@ -948,10 +954,95 @@ export const coinABI = [
|
|
|
948
954
|
{ type: 'error', inputs: [], name: 'UseRevokeOwnershipToRemoveSelf' },
|
|
949
955
|
] as const
|
|
950
956
|
|
|
957
|
+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
958
|
+
// IUniswapV3Pool
|
|
959
|
+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
960
|
+
|
|
961
|
+
export const iUniswapV3PoolABI = [
|
|
962
|
+
{
|
|
963
|
+
type: 'function',
|
|
964
|
+
inputs: [],
|
|
965
|
+
name: 'feeGrowthGlobal0X128',
|
|
966
|
+
outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }],
|
|
967
|
+
stateMutability: 'view',
|
|
968
|
+
},
|
|
969
|
+
{
|
|
970
|
+
type: 'function',
|
|
971
|
+
inputs: [],
|
|
972
|
+
name: 'feeGrowthGlobal1X128',
|
|
973
|
+
outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }],
|
|
974
|
+
stateMutability: 'view',
|
|
975
|
+
},
|
|
976
|
+
{
|
|
977
|
+
type: 'function',
|
|
978
|
+
inputs: [],
|
|
979
|
+
name: 'slot0',
|
|
980
|
+
outputs: [
|
|
981
|
+
{
|
|
982
|
+
name: 'slot0',
|
|
983
|
+
internalType: 'struct IUniswapV3Pool.Slot0',
|
|
984
|
+
type: 'tuple',
|
|
985
|
+
components: [
|
|
986
|
+
{ name: 'sqrtPriceX96', internalType: 'uint160', type: 'uint160' },
|
|
987
|
+
{ name: 'tick', internalType: 'int24', type: 'int24' },
|
|
988
|
+
{ name: 'observationIndex', internalType: 'uint16', type: 'uint16' },
|
|
989
|
+
{
|
|
990
|
+
name: 'observationCardinality',
|
|
991
|
+
internalType: 'uint16',
|
|
992
|
+
type: 'uint16',
|
|
993
|
+
},
|
|
994
|
+
{
|
|
995
|
+
name: 'observationCardinalityNext',
|
|
996
|
+
internalType: 'uint16',
|
|
997
|
+
type: 'uint16',
|
|
998
|
+
},
|
|
999
|
+
{ name: 'feeProtocol', internalType: 'uint8', type: 'uint8' },
|
|
1000
|
+
{ name: 'unlocked', internalType: 'bool', type: 'bool' },
|
|
1001
|
+
],
|
|
1002
|
+
},
|
|
1003
|
+
],
|
|
1004
|
+
stateMutability: 'view',
|
|
1005
|
+
},
|
|
1006
|
+
{
|
|
1007
|
+
type: 'function',
|
|
1008
|
+
inputs: [
|
|
1009
|
+
{ name: 'recipient', internalType: 'address', type: 'address' },
|
|
1010
|
+
{ name: 'zeroForOne', internalType: 'bool', type: 'bool' },
|
|
1011
|
+
{ name: 'amountSpecified', internalType: 'int256', type: 'int256' },
|
|
1012
|
+
{ name: 'sqrtPriceLimitX96', internalType: 'uint160', type: 'uint160' },
|
|
1013
|
+
{ name: 'data', internalType: 'bytes', type: 'bytes' },
|
|
1014
|
+
],
|
|
1015
|
+
name: 'swap',
|
|
1016
|
+
outputs: [
|
|
1017
|
+
{ name: 'amount0', internalType: 'int256', type: 'int256' },
|
|
1018
|
+
{ name: 'amount1', internalType: 'int256', type: 'int256' },
|
|
1019
|
+
],
|
|
1020
|
+
stateMutability: 'nonpayable',
|
|
1021
|
+
},
|
|
1022
|
+
{
|
|
1023
|
+
type: 'function',
|
|
1024
|
+
inputs: [],
|
|
1025
|
+
name: 'token0',
|
|
1026
|
+
outputs: [{ name: '', internalType: 'address', type: 'address' }],
|
|
1027
|
+
stateMutability: 'nonpayable',
|
|
1028
|
+
},
|
|
1029
|
+
{
|
|
1030
|
+
type: 'function',
|
|
1031
|
+
inputs: [],
|
|
1032
|
+
name: 'token1',
|
|
1033
|
+
outputs: [{ name: '', internalType: 'address', type: 'address' }],
|
|
1034
|
+
stateMutability: 'nonpayable',
|
|
1035
|
+
},
|
|
1036
|
+
] as const
|
|
1037
|
+
|
|
951
1038
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
952
1039
|
// ZoraFactoryImpl
|
|
953
1040
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
954
1041
|
|
|
1042
|
+
/**
|
|
1043
|
+
* - [__View Contract on Base Basescan__](https://basescan.org/address/0x777777751622c0d3258f214F9DF38E35BF45baF3)
|
|
1044
|
+
* - [__View Contract on Base Sepolia Basescan__](https://sepolia.basescan.org/address/0x777777751622c0d3258f214F9DF38E35BF45baF3)
|
|
1045
|
+
*/
|
|
955
1046
|
export const zoraFactoryImplABI = [
|
|
956
1047
|
{
|
|
957
1048
|
type: 'constructor',
|
|
@@ -1195,3 +1286,21 @@ export const zoraFactoryImplABI = [
|
|
|
1195
1286
|
name: 'UUPSUnsupportedProxiableUUID',
|
|
1196
1287
|
},
|
|
1197
1288
|
] as const
|
|
1289
|
+
|
|
1290
|
+
/**
|
|
1291
|
+
* - [__View Contract on Base Basescan__](https://basescan.org/address/0x777777751622c0d3258f214F9DF38E35BF45baF3)
|
|
1292
|
+
* - [__View Contract on Base Sepolia Basescan__](https://sepolia.basescan.org/address/0x777777751622c0d3258f214F9DF38E35BF45baF3)
|
|
1293
|
+
*/
|
|
1294
|
+
export const zoraFactoryImplAddress = {
|
|
1295
|
+
8453: '0x777777751622c0d3258f214F9DF38E35BF45baF3',
|
|
1296
|
+
84532: '0x777777751622c0d3258f214F9DF38E35BF45baF3',
|
|
1297
|
+
} as const
|
|
1298
|
+
|
|
1299
|
+
/**
|
|
1300
|
+
* - [__View Contract on Base Basescan__](https://basescan.org/address/0x777777751622c0d3258f214F9DF38E35BF45baF3)
|
|
1301
|
+
* - [__View Contract on Base Sepolia Basescan__](https://sepolia.basescan.org/address/0x777777751622c0d3258f214F9DF38E35BF45baF3)
|
|
1302
|
+
*/
|
|
1303
|
+
export const zoraFactoryImplConfig = {
|
|
1304
|
+
address: zoraFactoryImplAddress,
|
|
1305
|
+
abi: zoraFactoryImplABI,
|
|
1306
|
+
} as const
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zoralabs/coins",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1-sdkalpha.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -25,13 +25,14 @@
|
|
|
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/
|
|
33
|
+
"@zoralabs/tsconfig": "^0.0.1",
|
|
33
34
|
"@zoralabs/shared-scripts": "^0.0.0",
|
|
34
|
-
"@zoralabs/
|
|
35
|
+
"@zoralabs/shared-contracts": "^0.0.1"
|
|
35
36
|
},
|
|
36
37
|
"scripts": {
|
|
37
38
|
"build": "pnpm run wagmi:generate && pnpm run copy-abis && pnpm run prettier:write && tsup",
|
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
|
+
}
|
package/script/Deploy.s.sol
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
pragma solidity ^0.8.
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
3
|
|
|
4
|
-
import {
|
|
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
|
@@ -138,7 +138,7 @@ contract Coin is ICoin, CoinConstants, ContractVersionBase, ERC20PermitUpgradeab
|
|
|
138
138
|
uint256 minAmountOut,
|
|
139
139
|
uint160 sqrtPriceLimitX96,
|
|
140
140
|
address tradeReferrer
|
|
141
|
-
) public payable nonReentrant returns (uint256) {
|
|
141
|
+
) public payable nonReentrant returns (uint256, uint256) {
|
|
142
142
|
// Ensure the recipient is not the zero address
|
|
143
143
|
if (recipient == address(0)) {
|
|
144
144
|
revert AddressZero();
|
|
@@ -173,7 +173,7 @@ contract Coin is ICoin, CoinConstants, ContractVersionBase, ERC20PermitUpgradeab
|
|
|
173
173
|
|
|
174
174
|
emit CoinBuy(msg.sender, recipient, tradeReferrer, amountOut, currency, tradeReward, trueOrderSize);
|
|
175
175
|
|
|
176
|
-
return amountOut;
|
|
176
|
+
return (orderSize, amountOut);
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
/// @notice Executes a sell order
|
|
@@ -188,12 +188,15 @@ contract Coin is ICoin, CoinConstants, ContractVersionBase, ERC20PermitUpgradeab
|
|
|
188
188
|
uint256 minAmountOut,
|
|
189
189
|
uint160 sqrtPriceLimitX96,
|
|
190
190
|
address tradeReferrer
|
|
191
|
-
) public nonReentrant returns (uint256) {
|
|
191
|
+
) public nonReentrant returns (uint256, uint256) {
|
|
192
192
|
// Ensure the recipient is not the zero address
|
|
193
193
|
if (recipient == address(0)) {
|
|
194
194
|
revert AddressZero();
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
// Record the coin balance of this contract before the swap
|
|
198
|
+
uint256 beforeCoinBalance = balanceOf(address(this));
|
|
199
|
+
|
|
197
200
|
// Transfer the coins from the seller to this contract
|
|
198
201
|
transfer(address(this), orderSize);
|
|
199
202
|
|
|
@@ -214,6 +217,21 @@ contract Coin is ICoin, CoinConstants, ContractVersionBase, ERC20PermitUpgradeab
|
|
|
214
217
|
// Execute the swap
|
|
215
218
|
uint256 amountOut = ISwapRouter(swapRouter).exactInputSingle(params);
|
|
216
219
|
|
|
220
|
+
// Record the coin balance of this contract after the swap
|
|
221
|
+
uint256 afterCoinBalance = balanceOf(address(this));
|
|
222
|
+
|
|
223
|
+
// If the swap was partially executed:
|
|
224
|
+
if (afterCoinBalance > beforeCoinBalance) {
|
|
225
|
+
// Calculate the refund
|
|
226
|
+
uint256 coinRefund = afterCoinBalance - beforeCoinBalance;
|
|
227
|
+
|
|
228
|
+
// Update the order size
|
|
229
|
+
orderSize -= coinRefund;
|
|
230
|
+
|
|
231
|
+
// Transfer the refund back to the seller
|
|
232
|
+
_transfer(address(this), recipient, coinRefund);
|
|
233
|
+
}
|
|
234
|
+
|
|
217
235
|
// If currency is WETH, convert to ETH
|
|
218
236
|
if (currency == WETH) {
|
|
219
237
|
IWETH(WETH).withdraw(amountOut);
|
|
@@ -225,7 +243,7 @@ contract Coin is ICoin, CoinConstants, ContractVersionBase, ERC20PermitUpgradeab
|
|
|
225
243
|
// Calculate the payout after the fee
|
|
226
244
|
uint256 payoutSize = amountOut - tradeReward;
|
|
227
245
|
|
|
228
|
-
|
|
246
|
+
_handlePayout(payoutSize, recipient);
|
|
229
247
|
|
|
230
248
|
_handleTradeRewards(tradeReward, tradeReferrer);
|
|
231
249
|
|
|
@@ -233,7 +251,7 @@ contract Coin is ICoin, CoinConstants, ContractVersionBase, ERC20PermitUpgradeab
|
|
|
233
251
|
|
|
234
252
|
emit CoinSell(msg.sender, recipient, tradeReferrer, orderSize, currency, tradeReward, payoutSize);
|
|
235
253
|
|
|
236
|
-
return
|
|
254
|
+
return (orderSize, payoutSize);
|
|
237
255
|
}
|
|
238
256
|
|
|
239
257
|
/// @notice Enables a user to burn their tokens
|
|
@@ -415,10 +433,10 @@ contract Coin is ICoin, CoinConstants, ContractVersionBase, ERC20PermitUpgradeab
|
|
|
415
433
|
}
|
|
416
434
|
}
|
|
417
435
|
|
|
418
|
-
/// @dev Handles sending ETH and ERC20 payouts
|
|
436
|
+
/// @dev Handles sending ETH and ERC20 payouts and refunds to recipients
|
|
419
437
|
/// @param orderPayout The amount of currency to pay out
|
|
420
438
|
/// @param recipient The address to receive the payout
|
|
421
|
-
function
|
|
439
|
+
function _handlePayout(uint256 orderPayout, address recipient) internal {
|
|
422
440
|
if (currency == WETH) {
|
|
423
441
|
Address.sendValue(payable(recipient), orderPayout);
|
|
424
442
|
} else {
|
package/src/ZoraFactoryImpl.sol
CHANGED
|
@@ -102,9 +102,9 @@ contract ZoraFactoryImpl is IZoraFactory, UUPSUpgradeable, ReentrancyGuardUpgrad
|
|
|
102
102
|
|
|
103
103
|
IERC20(currency).approve(address(coin), orderSize);
|
|
104
104
|
|
|
105
|
-
coinsPurchased = coin.buy(payoutRecipient, orderSize, 0, 0, address(0));
|
|
105
|
+
(, coinsPurchased) = coin.buy(payoutRecipient, orderSize, 0, 0, address(0));
|
|
106
106
|
} else {
|
|
107
|
-
coinsPurchased = coin.buy{value: msg.value}(payoutRecipient, orderSize, 0, 0, address(0));
|
|
107
|
+
(, coinsPurchased) = coin.buy{value: msg.value}(payoutRecipient, orderSize, 0, 0, address(0));
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
}
|
package/src/interfaces/ICoin.sol
CHANGED
|
@@ -172,7 +172,7 @@ interface ICoin is IERC165, IERC721Receiver, IERC7572 {
|
|
|
172
172
|
uint256 minAmountOut,
|
|
173
173
|
uint160 sqrtPriceLimitX96,
|
|
174
174
|
address tradeReferrer
|
|
175
|
-
) external payable returns (uint256);
|
|
175
|
+
) external payable returns (uint256, uint256);
|
|
176
176
|
|
|
177
177
|
/// @notice Executes a sell order
|
|
178
178
|
/// @param recipient The recipient of the currency
|
|
@@ -180,7 +180,13 @@ interface ICoin is IERC165, IERC721Receiver, IERC7572 {
|
|
|
180
180
|
/// @param minAmountOut The minimum amount of currency to receive
|
|
181
181
|
/// @param sqrtPriceLimitX96 The price limit for the swap
|
|
182
182
|
/// @param tradeReferrer The address of the trade referrer
|
|
183
|
-
function sell(
|
|
183
|
+
function sell(
|
|
184
|
+
address recipient,
|
|
185
|
+
uint256 orderSize,
|
|
186
|
+
uint256 minAmountOut,
|
|
187
|
+
uint160 sqrtPriceLimitX96,
|
|
188
|
+
address tradeReferrer
|
|
189
|
+
) external returns (uint256, uint256);
|
|
184
190
|
|
|
185
191
|
/// @notice Enables a user to burn their tokens
|
|
186
192
|
/// @param amount The amount of tokens to burn
|
|
@@ -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
|
-
|
|
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
|
}
|
|
@@ -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.
|
|
12
|
+
return "0.5.0";
|
|
13
13
|
}
|
|
14
14
|
}
|