Skip to content

Commit

Permalink
Merge pull request #153 from SmartInvoiceXYZ/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
moconnell committed Dec 5, 2023
2 parents 614b81d + 3f09616 commit f54faac
Show file tree
Hide file tree
Showing 165 changed files with 11,496 additions and 22,188 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
// Auto-sort imports
"sort-imports": "off",
"import/order": "off",
"simple-import-sort/imports": "error",
"simple-import-sort/imports": "off",
"simple-import-sort/exports": "error",

// Allow props spreading
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ jobs:
- name: Build Dapp
run: yarn dapp:build
env:
REACT_APP_INFURA_ID: ${{ secrets.INFURA_ID }}
REACT_APP_GA4_ID: ${{ secrets.GA4_ID }}
REACT_APP_DEBUG_LOGS: 'true'
NEXT_PUBLIC_INFURA_ID: ${{ secrets.INFURA_ID }}
NEXT_PUBLIC_GA4_ID: ${{ secrets.GA4_ID }}
NEXT_PUBLIC_DEBUG_LOGS: 'true'
- name: Deploy Docs
uses: w9jds/firebase-action@master
with:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,6 @@ packages/subgraph/src/types

# firebase tmp
.firebase/

/packages/contracts/flat/
/packages/dapp/.next/
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint-staged
# yarn lint-staged
4 changes: 4 additions & 0 deletions .sample-env
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
INFURA_PROJECT_ID=
PRIVATE_KEY=
ETHERSCAN_API_KEY=
COINMARKETCAP_API_KEY=
CURRENCY=
POLYGONSCAN_API_KEY=
23 changes: 11 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"subgraph:build": "yarn workspace @smart-invoice/subgraph build",
"subgraph:deploy-kovan": "yarn workspace @smart-invoice/subgraph deploy-kovan",
"subgraph:deploy-rinkeby": "yarn workspace @smart-invoice/subgraph deploy-rinkeby",
"dapp:dev": "yarn workspace @smart-invoice/dapp dev",
"dapp:start": "yarn workspace @smart-invoice/dapp start",
"dapp:build": "yarn workspace @smart-invoice/dapp build",
"docs:start": "yarn workspace @smart-invoice/docs start",
Expand All @@ -25,8 +26,7 @@
"contracts:deploy-factory": "yarn workspace @smart-invoice/contracts deploy-factory",
"lint": "eslint --ignore-path .gitignore \"./packages/**/*.{ts,tsx,js,jsx}\"",
"format": "prettier --ignore-path .gitignore --write \"{*,**/*}.{ts,tsx,js,jsx,json,md,sol}\"",
"prepare": "husky install",
"postinstall": "patch-package"
"prepare": "husky install"
},
"workspaces": {
"nohoist": [
Expand All @@ -44,22 +44,26 @@
},
"license": "MIT",
"devDependencies": {
"@babel/eslint-parser": "^7.23.3",
"@typescript-eslint/parser": "^6.7.0",
"async-prompt": "^1.0.1",
"babel-eslint": "^10.1.0",
"dotenv": "^8.2.0",
"eslint": "^7.32.0",
"eslint": "^8.51.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-mocha": "^10.1.0",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-mocha": "^10.2.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-simple-import-sort": "^10.0.0",
"ethers": "^5.1.0",
"husky": "^6.0.0",
"it-all": "^1.0.2",
"lint-staged": "^14.0.1",
"prettier": "^3.0.3",
"prettier-plugin-solidity": "^1.1.3"
"prettier-plugin-solidity": "^1.1.3",
"typescript": "^4.9.5"
},
"lint-staged": {
"*.{ts,tsx,js,jsx}": [
Expand All @@ -69,10 +73,5 @@
"*.{json,md,sol}": [
"prettier --write"
]
},
"dependencies": {
"@typescript-eslint/parser": "^6.7.0",
"patch-package": "^8.0.0",
"typescript": "^4.9.5"
}
}
10 changes: 10 additions & 0 deletions packages/contracts/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
INFURA_PROJECT_ID='<rpc key>'
PRIVATE_KEY='<wallet private key>'

# verification
ETHERSCAN_API_KEY='<etherscan api key>'
POLYGONSCAN_API_KEY='<polygonscan api key>'
GNOSISSCAN_API_KEY='<gnosisscan api key>'

# fork goerli for (zap) tests
FORK=true
226 changes: 226 additions & 0 deletions packages/contracts/contracts/SafeSplitsDaoEscrowZap.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

import "hardhat/console.sol";
import "@openzeppelin/contracts/proxy/Clones.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";

import "./SafeSplitsEscrowZap.sol";
import "./interfaces/ISpoilsManager.sol";

contract SafeSplitsDaoEscrowZap is SafeSplitsEscrowZap {
/// @notice The DAO controller address
address dao;

error DaoSplitCreationFailed();

/// @notice The DAO's SpoilsManager address
ISpoilsManager spoilsManager;

event SafeSplitsDaoEscrowCreated(
address safe,
address projectTeamSplit,
address daoSplit,
address escrow
);

struct DaoZapData {
ZapData zapData;
address daoSplit;
}

/**
* @dev Deploys a new Split with the provided owners and percent allocations, optionally creates a DAO split for spoils
* @param _owners The address list of owners for the raid party split
* @param _percentAllocations The percent allocations for the raid party split
* @param _splitsData Bundled data for splits
* @param _daoZapData Resulting data struct
*/
function _createSplit(
address[] memory _owners,
uint32[] memory _percentAllocations,
bytes calldata _splitsData,
DaoZapData memory _daoZapData
) internal returns (DaoZapData memory) {
_daoZapData.zapData.projectTeamSplit = splitMain.createSplit(
_owners,
_percentAllocations,
distributorFee,
_daoZapData.zapData.safe
);
if (_daoZapData.zapData.projectTeamSplit == address(0)) {
revert ProjectTeamSplitNotCreated();
}

bool _isDaoSplit = abi.decode(_splitsData, (bool));

if (_isDaoSplit) {
// prepare arrays
address[] memory daoSplitRecipients = new address[](2);
uint32[] memory daoSplitPercentAllocations = new uint32[](2);

// dao split recipients
address daoReceiver = spoilsManager.receiver();

// dao split amounts
uint32 daoSplitAmount = spoilsManager.getSpoils();
uint32 projectSplitAmount = (100 *
spoilsManager.SPLIT_PERCENTAGE_SCALE()) - (daoSplitAmount);

// sort the addresses into the correct order
if (
uint160(daoReceiver) <
uint160(_daoZapData.zapData.projectTeamSplit)
) {
daoSplitRecipients[0] = daoReceiver;
daoSplitRecipients[1] = _daoZapData.zapData.projectTeamSplit;
daoSplitPercentAllocations[0] = daoSplitAmount;
daoSplitPercentAllocations[1] = projectSplitAmount;
} else {
daoSplitRecipients[0] = _daoZapData.zapData.projectTeamSplit;
daoSplitRecipients[1] = daoReceiver;
daoSplitPercentAllocations[0] = projectSplitAmount;
daoSplitPercentAllocations[1] = daoSplitAmount;
}

// (recipients array, percent allocations array, no distributor fee, safe address)
_daoZapData.daoSplit = splitMain.createSplit(
daoSplitRecipients,
daoSplitPercentAllocations,
distributorFee,
dao
);
if (_daoZapData.daoSplit == address(0)) {
revert DaoSplitCreationFailed();
}
}

return _daoZapData;
}

function _handleEscrowParams(
DaoZapData memory _daoZapData
) internal view returns (address[] memory) {
address[] memory escrowParams = new address[](2);
escrowParams[0] = _daoZapData.zapData.safe;
escrowParams[1] = _daoZapData.zapData.projectTeamSplit;

if (_daoZapData.daoSplit != address(0)) {
escrowParams[0] = dao;
escrowParams[1] = _daoZapData.daoSplit;
}

return escrowParams;
}

function _createSafeSplitEscrow(
address[] memory _owners,
uint32[] memory _percentAllocations,
uint256[] memory _milestoneAmounts,
bytes calldata _safeData,
bytes calldata _splitsData,
bytes calldata _escrowData
) internal {
DaoZapData memory daoZapData = DaoZapData({
zapData: ZapData({
safe: address(0),
projectTeamSplit: address(0),
escrow: address(0)
}),
daoSplit: address(0)
});

daoZapData.zapData = _deploySafe(
_owners,
_safeData,
daoZapData.zapData
);

daoZapData = _createSplit(
_owners,
_percentAllocations,
_splitsData,
daoZapData
);

address[] memory escrowParams = _handleEscrowParams(daoZapData);

daoZapData.zapData = _deployEscrow(
_milestoneAmounts,
_escrowData,
escrowParams,
daoZapData.zapData
);

emit SafeSplitsDaoEscrowCreated(
daoZapData.zapData.safe,
daoZapData.zapData.projectTeamSplit,
daoZapData.daoSplit,
daoZapData.zapData.escrow
);
}

/**
* @dev Deploys a new Safe, Raid Party Split and Escrow with the provided details
* @param _owners The safe owners and raid party split participants
* @param _percentAllocations The percent allocations for the raid party split
* @param _milestoneAmounts The initial milestone amounts for the escrow
* @param _safeData The number of required confirmations for a Safe transaction
* @param _escrowData The nonce for the salt used in the escrow deployment (recycled from safe deployment)
*/
function createSafeSplitEscrow(
address[] memory _owners,
uint32[] memory _percentAllocations,
uint256[] memory _milestoneAmounts,
bytes calldata _safeData,
bytes calldata _splitsData,
bytes calldata _escrowData
) public {
if (_percentAllocations.length != _owners.length) {
revert InvalidAllocationsOwnersData();
}
_createSafeSplitEscrow(
_owners,
_percentAllocations,
_milestoneAmounts,
_safeData,
_splitsData,
_escrowData
);
}

function _handleData(bytes calldata _data) internal override {
(
address _safeSingleton,
address _fallbackHandler,
address _safeFactory,
address _splitMain,
address _spoilsManager,
address _escrowFactory,
address _wrappedNativeToken,
address _dao
) = abi.decode(
_data,
(
address,
address,
address,
address,
address,
address,
address,
address
)
);

safeSingleton = _safeSingleton;
fallbackHandler = _fallbackHandler;
safeFactory = ISafeProxyFactory(_safeFactory);
splitMain = ISplitMain(_splitMain);
spoilsManager = ISpoilsManager(_spoilsManager);
escrowFactory = ISmartInvoiceFactory(_escrowFactory);
wrappedNativeToken = IWRAPPED(_wrappedNativeToken);
dao = _dao;
}
}
Loading

1 comment on commit f54faac

@vercel
Copy link

@vercel vercel bot commented on f54faac Dec 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.