Skip to content

Commit

Permalink
update distributor (#384)
Browse files Browse the repository at this point in the history
Co-authored-by: Arr00 <[email protected]>
  • Loading branch information
0xble and arr00 authored Mar 26, 2024
1 parent 136ed9b commit 1512942
Show file tree
Hide file tree
Showing 14 changed files with 31 additions and 140 deletions.
28 changes: 10 additions & 18 deletions contracts/distribution/TokenDistributor.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.20;

import "openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../globals/IGlobals.sol";
import "../globals/LibGlobals.sol";
import "../tokens/IERC20.sol";
Expand All @@ -12,7 +13,7 @@ import "../utils/LibSafeCast.sol";
import "./ITokenDistributor.sol";

/// @notice Creates token distributions for parties.
contract TokenDistributor is ITokenDistributor {
contract TokenDistributor is ITokenDistributor, ReentrancyGuard {
using LibAddress for address payable;
using LibERC20Compat for IERC20;
using LibRawResult for bytes;
Expand Down Expand Up @@ -105,7 +106,7 @@ contract TokenDistributor is ITokenDistributor {
Party party,
address payable feeRecipient,
uint16 feeBps
) external payable returns (DistributionInfo memory info) {
) external payable nonReentrant returns (DistributionInfo memory info) {
info = _createDistribution(
CreateDistributionArgs({
party: party,
Expand All @@ -124,7 +125,7 @@ contract TokenDistributor is ITokenDistributor {
Party party,
address payable feeRecipient,
uint16 feeBps
) external returns (DistributionInfo memory info) {
) external nonReentrant returns (DistributionInfo memory info) {
info = _createDistribution(
CreateDistributionArgs({
party: party,
Expand All @@ -141,7 +142,7 @@ contract TokenDistributor is ITokenDistributor {
function claim(
DistributionInfo calldata info,
uint256 partyTokenId
) public returns (uint128 amountClaimed) {
) public nonReentrant returns (uint128 amountClaimed) {
// Caller must own the party token.
{
address ownerOfPartyToken = info.party.ownerOf(partyTokenId);
Expand Down Expand Up @@ -185,7 +186,10 @@ contract TokenDistributor is ITokenDistributor {
}

/// @inheritdoc ITokenDistributor
function claimFee(DistributionInfo calldata info, address payable recipient) public {
function claimFee(
DistributionInfo calldata info,
address payable recipient
) public nonReentrant {
// DistributionInfo must be correct for this distribution ID.
DistributionState storage state = _distributionStates[info.party][info.distributionId];
if (state.distributionHash != _getDistributionHash(info)) {
Expand Down Expand Up @@ -364,25 +368,13 @@ contract TokenDistributor is ITokenDistributor {
uint256 amount
) private {
bytes32 balanceId = _getBalanceId(tokenType, token);
// Reduce stored token balance.
uint256 storedBalance = _storedBalances[balanceId] - amount;
// Temporarily set to max as a reentrancy guard. An interesing attack
// could occur if we didn't do this where an attacker could `claim()` and
// reenter upon transfer (e.g. in the `tokensToSend` hook of an ERC777) to
// `createERC20Distribution()`. Since the `balanceOf(address(this))`
// would not of been updated yet, the supply would be miscalculated and
// the attacker would create a distribution that essentially steals from
// the last distribution they were claiming from. Here, we prevent that
// by causing an arithmetic underflow with the supply calculation if
// this were to be attempted.
_storedBalances[balanceId] = type(uint256).max;
_storedBalances[balanceId] -= amount;
if (tokenType == TokenType.Native) {
recipient.transferEth(amount);
} else {
assert(tokenType == TokenType.Erc20);
IERC20(token).compatTransfer(recipient, amount);
}
_storedBalances[balanceId] = storedBalance;
}

function _getDistributionHash(
Expand Down
9 changes: 8 additions & 1 deletion contracts/renderers/PartyNFTRenderer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ contract PartyNFTRenderer is RendererBase {
IMetadataRegistry1_1 constant OLD_METADATA_REGISTRY =
IMetadataRegistry1_1(0x175487875F0318EdbAB54BBA442fF53b36e96015);
/// @notice The old token distributor contract address.
/// @dev Cannot store immutable arrays...
address immutable TOKEN_DISTRIBUTOR_V1;
address immutable TOKEN_DISTRIBUTOR_V2;
address immutable TOKEN_DISTRIBUTOR_V3;

/// @notice The base url for external URLs. External URL is BASE_EXTERNAL_URL + PARTY_ADDRESS
/// @dev First byte is the size of the data, the rest is the data (starting from MSB)
Expand All @@ -89,11 +91,13 @@ contract PartyNFTRenderer is RendererBase {
IFont font,
address tokenDistributionV1,
address tokenDistributionV2,
address tokenDistributionV3,
string memory baseExternalURL
) RendererBase(globals, rendererStorage, font) {
IMPL = address(this);
TOKEN_DISTRIBUTOR_V1 = tokenDistributionV1;
TOKEN_DISTRIBUTOR_V2 = tokenDistributionV2;
TOKEN_DISTRIBUTOR_V3 = tokenDistributionV3;

bytes memory baseExternalURLBytes = bytes(baseExternalURL);
if (baseExternalURLBytes.length > 31) {
Expand Down Expand Up @@ -662,11 +666,14 @@ contract PartyNFTRenderer is RendererBase {
if (address(this) == IMPL) return false;

// There will only be one distributor if old token distributor is not set
TokenDistributor[] memory distributors = new TokenDistributor[](3);
TokenDistributor[] memory distributors = new TokenDistributor[](4);
distributors[0] = TokenDistributor(
_GLOBALS.getAddress(LibGlobals.GLOBAL_TOKEN_DISTRIBUTOR)
);
uint256 l = 1;
if (TOKEN_DISTRIBUTOR_V3 != address(0)) {
distributors[l++] = TokenDistributor(TOKEN_DISTRIBUTOR_V3);
}
if (TOKEN_DISTRIBUTOR_V2 != address(0)) {
distributors[l++] = TokenDistributor(TOKEN_DISTRIBUTOR_V2);
}
Expand Down
15 changes: 0 additions & 15 deletions deploy/BaseGoerli.s.sol

This file was deleted.

1 change: 1 addition & 0 deletions deploy/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ abstract contract Deploy {
IFont(address(pixeldroidConsoleFont)),
deployConstants.tokenDistributorV1,
deployConstants.tokenDistributorV2,
deployConstants.tokenDistributorV3,
deployConstants.baseExternalURL
);
_trackDeployerGasAfter();
Expand Down
15 changes: 0 additions & 15 deletions deploy/Goerli.s.sol

This file was deleted.

76 changes: 6 additions & 70 deletions deploy/LibDeployConstants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ library LibDeployConstants {
uint96 contributionRouterInitialFee;
address tokenDistributorV1;
address tokenDistributorV2;
address tokenDistributorV3;
string baseExternalURL;
}

Expand Down Expand Up @@ -60,6 +61,7 @@ library LibDeployConstants {
contributionRouterInitialFee: 0.00055 ether,
tokenDistributorV1: 0x0000000000000000000000000000000000000000,
tokenDistributorV2: 0x0000000000000000000000000000000000000000,
tokenDistributorV3: 0xf0560F963538017CAA5081D96f839FE5D265acCB,
baseExternalURL: "https://party.app/party/"
});

Expand Down Expand Up @@ -94,82 +96,13 @@ library LibDeployConstants {
contributionRouterInitialFee: 0.00055 ether,
tokenDistributorV1: 0x0000000000000000000000000000000000000000,
tokenDistributorV2: 0x0000000000000000000000000000000000000000,
tokenDistributorV3: 0x2d451d8317feF4f3fB8798815520202195FE8C7C,
baseExternalURL: "https://party.app/party/"
});

return deployConstants;
}

function goerli(address multisig) internal pure returns (DeployConstants memory) {
address[] memory allowedERC20SwapOperatorTargets = new address[](1);
allowedERC20SwapOperatorTargets[0] = 0xF91bB752490473B8342a3E964E855b9f9a2A668e; // 0x Swap Aggregator

DeployConstants memory deployConstants = DeployConstants({
seaportExchangeAddress: 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC,
osZoraAuctionDuration: 2 minutes,
osZoraAuctionTimeout: 2 minutes,
osMinOrderDuration: 2 minutes,
osMaxOrderDuration: 14 days,
zoraMinAuctionDuration: 2 minutes,
zoraMaxAuctionDuration: 10 days,
zoraMaxAuctionTimeout: 7 days,
minCancelDelay: 5 minutes,
maxCancelDelay: 1 days,
distributorEmergencyActionAllowedDuration: 365 days,
partyDaoMultisig: multisig,
allowedERC20SwapOperatorTargets: allowedERC20SwapOperatorTargets,
osZone: 0x0000000000000000000000000000000000000000,
osConduitKey: 0xf984c55ca75735630c1c27d3d06969c1aa6af1df86d22ddc0e3a978ad6138e9f,
osConduitController: 0x00000000F9490004C11Cef243f5400493c00Ad63,
fractionalVaultFactory: 0x014850E83d9D0D1BB0c8624035F09626b967B81c,
nounsAuctionHouse: 0x7295e70f2B26986Ba108bD1Bf9E349a181F4a6Ea,
zoraReserveAuctionCoreEth: 0x2506D9F5A2b0E1A2619bCCe01CD3e7C289A13163,
networkName: "goerli",
deployedNounsMarketWrapper: 0x0000000000000000000000000000000000000000,
contributionRouterInitialFee: 0.00055 ether,
tokenDistributorV1: 0xE6F58B31344404E3479d81fB8f9dD592feB37965,
tokenDistributorV2: 0x8714EA9C2BC5a8f2d26D7c3F86558331c16145B5,
baseExternalURL: "https://party.app/party/"
});

return deployConstants;
}

function baseGoerli(address multisig) internal pure returns (DeployConstants memory) {
address[] memory allowedERC20SwapOperatorTargets = new address[](1);
allowedERC20SwapOperatorTargets[0] = 0xF91bB752490473B8342a3E964E855b9f9a2A668e; // 0x Swap Aggregator

DeployConstants memory deployConstants = DeployConstants({
seaportExchangeAddress: 0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC,
osZoraAuctionDuration: 2 minutes,
osZoraAuctionTimeout: 2 minutes,
osMinOrderDuration: 2 minutes,
osMaxOrderDuration: 14 days,
zoraMinAuctionDuration: 2 minutes,
zoraMaxAuctionDuration: 10 days,
zoraMaxAuctionTimeout: 7 days,
minCancelDelay: 5 minutes,
maxCancelDelay: 1 days,
distributorEmergencyActionAllowedDuration: 365 days,
partyDaoMultisig: multisig,
allowedERC20SwapOperatorTargets: allowedERC20SwapOperatorTargets,
osZone: 0x0000000000000000000000000000000000000000,
osConduitKey: 0xf984c55ca75735630c1c27d3d06969c1aa6af1df86d22ddc0e3a978ad6138e9f,
osConduitController: 0x00000000F9490004C11Cef243f5400493c00Ad63,
fractionalVaultFactory: 0x0000000000000000000000000000000000000000,
nounsAuctionHouse: 0x0000000000000000000000000000000000000000,
zoraReserveAuctionCoreEth: 0x0000000000000000000000000000000000000000,
networkName: "base-goerli",
deployedNounsMarketWrapper: 0x0000000000000000000000000000000000000000,
contributionRouterInitialFee: 0.00055 ether,
tokenDistributorV1: address(0),
tokenDistributorV2: 0x55D2463cf5b6743F279Fe9BcbF32415f575B953d,
baseExternalURL: "https://base.party.app/party/"
});

return deployConstants;
}

function mainnet() internal pure returns (DeployConstants memory) {
address[] memory allowedERC20SwapOperatorTargets = new address[](1);
allowedERC20SwapOperatorTargets[0] = 0xDef1C0ded9bec7F1a1670819833240f027b25EfF; // 0x Swap Aggregator
Expand Down Expand Up @@ -199,6 +132,7 @@ library LibDeployConstants {
contributionRouterInitialFee: 0.00055 ether,
tokenDistributorV1: 0x1CA2007a81F8A7491BB6E11D8e357FD810896454,
tokenDistributorV2: 0x49a3caab781f711aD74C9d2F34c3cbD835d6A608,
tokenDistributorV3: 0x0b7b86DCEAa8015CeD8F625d3b7A961b31fB05FE,
baseExternalURL: "https://party.app/party/"
});

Expand Down Expand Up @@ -234,6 +168,7 @@ library LibDeployConstants {
contributionRouterInitialFee: 0.00055 ether,
tokenDistributorV1: address(0),
tokenDistributorV2: 0xf0560F963538017CAA5081D96f839FE5D265acCB,
tokenDistributorV3: 0x65778953D291DD1e3a97c6b4d8BEea188B650077,
baseExternalURL: "https://base.party.app/party/"
});

Expand Down Expand Up @@ -268,6 +203,7 @@ library LibDeployConstants {
contributionRouterInitialFee: 0.00055 ether,
tokenDistributorV1: address(0),
tokenDistributorV2: address(0),
tokenDistributorV3: 0x5B19016a409a888326b05949391EB8797dD5F75B,
baseExternalURL: "https://zora.party.app/party/"
});

Expand Down
2 changes: 1 addition & 1 deletion lib/party-addresses
Submodule party-addresses updated 310 files
4 changes: 0 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
"test:fork": "yarn test --fork-url $ETH_RPC_URL",
"test:gas": "forge test --ffi --mc GasBenchmarks -vv",
"deploy": "node js/deploy.js",
"deploy:goerli": "DRY_RUN=0 forge script ./deploy/Goerli.s.sol -vvv --rpc-url $GOERLI_RPC_URL --broadcast --etherscan-api-key $ETHERSCAN_API_KEY --via-ir --skip test --optimize --optimizer-runs 50 --ffi --slow",
"deploy:goerli:dry": "DRY_RUN=1 forge script ./deploy/Goerli.s.sol -vvv --rpc-url $GOERLI_RPC_URL --via-ir --skip test --optimize --optimizer-runs 50 --ffi",
"deploy:sepolia": "DRY_RUN=0 forge script ./deploy/Sepolia.s.sol -vvv --rpc-url $SEPOLIA_RPC_URL --broadcast --etherscan-api-key $ETHERSCAN_API_KEY --via-ir --skip test --optimize --optimizer-runs 50 --ffi --slow",
"deploy:sepolia:dry": "DRY_RUN=1 forge script ./deploy/Sepolia.s.sol -vvv --rpc-url $SEPOLIA_RPC_URL --via-ir --skip test --optimize --optimizer-runs 50 --ffi",
"deploy:mainnet": "DRY_RUN=0 forge script ./deploy/Mainnet.s.sol -vvv --rpc-url $ETH_RPC_URL --broadcast --etherscan-api-key $ETHERSCAN_API_KEY --via-ir --skip test --optimize --optimizer-runs 50 --ffi --slow",
Expand All @@ -23,8 +21,6 @@
"deploy:base:dry": "DRY_RUN=1 forge script ./deploy/Base.s.sol -vvv --rpc-url $BASE_RPC_URL --via-ir --skip test --optimize --optimizer-runs 50 --ffi",
"deploy:base-sepolia": "DRY_RUN=0 forge script ./deploy/BaseSepolia.s.sol -vvv --rpc-url $BASE_SEPOLIA_RPC_URL --via-ir --broadcast --etherscan-api-key $BASESCAN_API_KEY --skip test --optimize --optimizer-runs 50 --ffi --slow",
"deploy:base-sepolia:dry": "DRY_RUN=1 forge script ./deploy/BaseSepolia.s.sol -vvv --rpc-url $BASE_SEPOLIA_RPC_URL --via-ir --skip test --optimize --optimizer-runs 50 --ffi",
"deploy:base-goerli": "DRY_RUN=0 forge script ./deploy/BaseGoerli.s.sol -vvv --rpc-url $BASE_GOERLI_RPC_URL --via-ir --broadcast --etherscan-api-key $BASESCAN_API_KEY --skip test --optimize --optimizer-runs 50 --ffi --slow",
"deploy:base-goerli:dry": "DRY_RUN=1 forge script ./deploy/BaseGoerli.s.sol -vvv --rpc-url $BASE_GOERLI_RPC_URL --via-ir --skip test --optimize --optimizer-runs 50 --ffi",
"deploy:zora:dry": "DRY_RUN=1 forge script ./deploy/Zora.s.sol -vvv --rpc-url $ZORA_RPC_URL --via-ir --skip test --optimize --optimizer-runs 50 --ffi --priority-gas-price 1",
"deploy:zora": "DRY_RUN=0 forge script ./deploy/Zora.s.sol -vvv --rpc-url $ZORA_RPC_URL --broadcast --via-ir --skip test --optimize --optimizer-runs 50 --ffi --slow --priority-gas-price 1",
"decode-revert": "node js/decode-revert.js",
Expand Down
1 change: 1 addition & 0 deletions test/crowdfund/InitialETHCrowdfund.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ contract InitialETHCrowdfundTestBase is LintJSON, TestUtils, ERC721Receiver {
font,
address(0),
address(0),
address(0),
"https://party.app/party/"
);
tokenDistributor = new TokenDistributor(globals, 0);
Expand Down
1 change: 1 addition & 0 deletions test/party/PartyGovernanceNFT.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ contract PartyGovernanceNFTTestBase is LintJSON, TestUtils {
font,
address(0),
address(0),
address(0),
"https://party.app/party/"
);
globalsAdmin.setGovernanceNftRendererAddress(address(nftRenderer));
Expand Down
1 change: 1 addition & 0 deletions test/utils/PartyGovernanceHelpers.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ contract PartyGovernanceHelpersTest is Test, TestUtils {
IFont(address(0)),
address(0),
address(0),
address(0),
"https://party.app/party/"
);
globalsAdmin.setGovernanceNftRendererAddress(address(nftRenderer));
Expand Down
10 changes: 1 addition & 9 deletions utils/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,15 +359,7 @@ async function updateHeadJson(chain: string, releaseName: string) {

async function main() {
const chain = process.argv[2];
const validChains = [
"mainnet",
"goerli",
"base",
"base-goerli",
"zora",
"sepolia",
"base-sepolia",
];
const validChains = ["mainnet", "base", "zora", "sepolia", "base-sepolia"];

if (!chain) {
console.error(`Missing chain argument. Valid chains are: ${validChains.join(", ")}`);
Expand Down
6 changes: 0 additions & 6 deletions utils/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ export const getBlockExplorerApiEndpoint = (chain: string) => {
return "https://api.etherscan.io/api";
} else if (chain === "base") {
return "https://api.basescan.org/api";
} else if (chain === "base-goerli") {
return "https://api-goerli.basescan.org/api";
} else if (chain === "zora") {
return "https://api.routescan.io/v2/network/mainnet/evm/7777777/etherscan/api";
} else if (chain === "base-sepolia") {
Expand Down Expand Up @@ -216,12 +214,8 @@ const getContractNames = (chain: string, libraries: string[]) => {
const getChainId = (chain: string) => {
if (chain === "mainnet") {
return 1;
} else if (chain === "goerli") {
return 5;
} else if (chain === "base") {
return 8453;
} else if (chain === "base-goerli") {
return 84531;
} else if (chain === "zora") {
return 7777777;
} else if (chain === "sepolia") {
Expand Down

0 comments on commit 1512942

Please sign in to comment.