Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
0318206
Emit Register event (#23)
robdoesstuff Oct 2, 2023
edc3827
whitlisting enabled by default (#22)
robdoesstuff Oct 2, 2023
5820e9a
Add schema update event (#24)
robdoesstuff Oct 2, 2023
3c49f18
Added getters for registered fragment data (#27)
robdoesstuff Oct 3, 2023
6873a36
Fixed literef collisions in scope (#25)
robdoesstuff Oct 8, 2023
7b61b08
Two step transfer (#26)
robdoesstuff Oct 8, 2023
c1da475
Patch an address (#28)
robdoesstuff Oct 8, 2023
809a2a1
Refactor - Split all interfaces and base implementations (#30)
robdoesstuff Oct 8, 2023
9238118
Refactor - split tests (#31)
robdoesstuff Oct 9, 2023
b518a9c
Unindexed scope name (#34)
robdoesstuff Oct 26, 2023
0272bbb
Relation types (#32)
robdoesstuff Nov 1, 2023
06c3890
Made scope change events use plain string instead of index (#33) (#35)
robdoesstuff Nov 1, 2023
2ced614
Allow patches to be fragments (#36)
robdoesstuff Nov 3, 2023
e25f830
Made scope change events use plain string instead of index (#33) (#38)
robdoesstuff Nov 3, 2023
d798b3d
Merge branch 'main' into v1.1
robdoesstuff Nov 3, 2023
9f2ee67
Moved test NFTs and fixed linter with proto test (#39)
robdoesstuff Nov 3, 2023
4121af9
Explicit patch ownership (#37)
robdoesstuff Nov 6, 2023
e89c047
1155 Patch (#40)
robdoesstuff Nov 8, 2023
ae611b2
Dynamic arrays (#41)
robdoesstuff Nov 13, 2023
f91df4f
Multi ref pools (#42)
robdoesstuff Nov 14, 2023
842f944
hotfix v1.1
robdoesstuff Nov 15, 2023
a254a07
Reverse lookups (#43)
robdoesstuff Nov 20, 2023
65e43e7
Renamed incorrectly named liteRefs (#44)
robdoesstuff Nov 20, 2023
3b86830
Payable mint support (#45)
robdoesstuff Nov 29, 2023
99ddda4
Mass renaming and standardizing (#46)
robdoesstuff Nov 29, 2023
eab1d00
V2 test coverage (#48)
robdoesstuff Nov 30, 2023
39e1965
some ascii fun (#49)
robdoesstuff Nov 30, 2023
a7245fc
natspec completion (#50)
robdoesstuff Nov 30, 2023
de74d01
Patchwork721 is ownable (#51)
robdoesstuff Nov 30, 2023
efb7dd3
small bugfix in test (#52)
robdoesstuff Nov 30, 2023
e65b645
Protocol fee overrides (#53)
robdoesstuff Dec 1, 2023
6cf8c9c
Patch burns (#54)
robdoesstuff Dec 1, 2023
51648f9
Target scope unassign (#55)
robdoesstuff Dec 1, 2023
93d146b
Fixed out of bounds array access (#56)
robdoesstuff Jan 5, 2024
c4880f6
ERC165 optimizations (#57)
robdoesstuff Jan 5, 2024
851b09b
all calls to getScopeName are memoized (#58)
robdoesstuff Jan 6, 2024
c26198a
Gas tests to prove/disprove some potential optimizations (#59)
robdoesstuff Jan 7, 2024
485e076
Revert "ERC165 optimizations (#57)" (#60)
robdoesstuff Jan 8, 2024
072fd68
private modifiers (#61)
robdoesstuff Jan 8, 2024
2e22155
Fee change timelock (#62)
robdoesstuff Jan 10, 2024
120299e
Handle invalid fee configurations (#63)
robdoesstuff Jan 11, 2024
08ea99e
Add assignment check to unassign (#64)
robdoesstuff Jan 11, 2024
7cc5068
Added fee change events (#65)
robdoesstuff Jan 11, 2024
e1f83c3
Refactored into reversible account patch subclass (#66)
robdoesstuff Jan 12, 2024
bd4e8da
Validate redact/unredact (#68)
robdoesstuff Jan 12, 2024
da81765
Bugfix in patch burn (#69)
robdoesstuff Jan 12, 2024
dad0816
Clean up getScopeName interface and test impls (#70)
robdoesstuff Jan 12, 2024
7a68de3
use mustBeManager instead of adhoc (#71)
robdoesstuff Jan 12, 2024
02303ff
proto fee ceiling (#67)
robdoesstuff Jan 13, 2024
9a8da1d
Struct cleanup (#72)
robdoesstuff Jan 13, 2024
a5ff036
More reversibles (#73)
robdoesstuff Jan 13, 2024
eeac217
added some indices to events (#74)
robdoesstuff Jan 13, 2024
d0b144f
Some natspec improvements (#75)
robdoesstuff Jan 16, 2024
a53f7e4
Several improvement requests (#76)
robdoesstuff Jan 16, 2024
2c10215
small fix (#79)
robdoesstuff Jan 16, 2024
cfda945
Open zeppelin 5 (#80)
robdoesstuff Jan 17, 2024
214593f
Create2 support (#81)
robdoesstuff Jan 17, 2024
06c25cf
Event fees (#82)
robdoesstuff Jan 19, 2024
3aecbdd
Refactored doAssign for readability and object bytesize optimization …
robdoesstuff Jan 21, 2024
c6a2cab
Fixed recursive burn bug (#85)
robdoesstuff Jan 24, 2024
0de949d
Assigner delegate contract (#86)
robdoesstuff Jan 26, 2024
4549d82
Deploy and Verify using create2 (#87)
robdoesstuff Jan 26, 2024
3f52cea
Fixed fee handling issue with batch assign (#89)
robdoesstuff Feb 1, 2024
4e0efdb
Add base sepolia and deploy latest to testnets
donaldinho Feb 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ out/
!/broadcast
/broadcast/*/31337/
/broadcast/**/dry-run/
**/broadcast/**


# Docs
docs/
Expand Down
4 changes: 2 additions & 2 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[submodule "lib/openzeppelin-contracts"]
branch = v4.8.2
branch = v5.0.1
path = lib/openzeppelin-contracts
url = https://github.com/openzeppelin/openzeppelin-contracts
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
branch = v1.5.2
branch = v1.7.6
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ out = 'out'
test = 'test'
cache_path = 'cache'
script = 'script'
solc_version = '0.8.23'

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
2 changes: 1 addition & 1 deletion lib/openzeppelin-contracts
14 changes: 14 additions & 0 deletions management/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# .env file
PRIVATE_KEY=your_private_key_here
BASE_RPC_URL=your_base_network_rpc_url
BASE_PATCHWORK_OWNER=base_patchwork_owner_address
BASE_PATCHWORK_ADDRESS=base_patchwork_address
BASE_CHAIN_ID=8453
SEPOLIA_RPC_URL=your_sepolia_network_rpc_url
SEPOLIA_PATCHWORK_OWNER=sepolia_patchwork_owner_address
SEPOLIA_CHAIN_ID=11155111
SEPOLIA_PATCHWORK_ADDRESS=0xeAB0ceC50d344c1256fB983fee6f87D6A040d329
BASE_SEPOLIA_RPC_URL=https://base-sepolia.g.alchemy.com/v2/6p1q3ciiOzYUwMaNdysskDHdLLV56sGx
BASE_SEPOLIA_PATCHWORK_OWNER=0x435498Afe7E9b01f92D673fADA429fAeA08870aA
BASE_SEPOLIA_CHAIN_ID=11155111
BASE_SEPOLIA_PATCHWORK_ADDRESS=0xeAB0ceC50d344c1256fB983fee6f87D6A040d329
23 changes: 23 additions & 0 deletions management/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Create a .env file in the format of .env.example

To deoploy on sepolia:
./deploy.sh sepolia

To deploy on base:
./deploy.sh base

Include --broadcast when you are ready to deploy

To verify on ether scan:

./verify.sh base

or

./verify.sh sepolia

manual verification:

forge verify-contract 0x635BDfB811Ef377a759231Ac3A2746814A93a7B8 src/PatchworkProtocol.sol:PatchworkProtocol --optimizer-runs 200 --constructor-args "0x0000000000000000000000007239aec2fa59303ba68bece386be2a9ddc72e63b" --show-standard-json-input > etherscan.json
patch manually etherscan.json : "optimizer":{"enabled":true,"runs":100} -> "optimizer":{"enabled":true,"runs":100},"viaIR":true (or something of that sort)
upload json to etherscan manually
1 change: 1 addition & 0 deletions management/constructor-args.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0x7239aEc2fA59303BA68BEcE386BE2A9dDC72e63B
33 changes: 33 additions & 0 deletions management/deploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import { Script } from "forge-std/Script.sol";
import "forge-std/console.sol";
import { PatchworkProtocol } from "../src/PatchworkProtocol.sol";
import { PatchworkProtocolAssigner } from "../src/PatchworkProtocolAssigner.sol";

contract DeterministicPatchworkDeploy is Script {

address internal constant _DETERMINISTIC_CREATE2_FACTORY = 0x7A0D94F55792C434d74a40883C6ed8545E406D12;

function run() public {
address patchworkOwner = vm.envAddress("PATCHWORK_OWNER");
vm.startBroadcast();

bytes memory creationCode = type(PatchworkProtocolAssigner).creationCode;
bytes memory creationBytecode = abi.encodePacked(creationCode, abi.encode(patchworkOwner));
(bool success, bytes memory returnData) = _DETERMINISTIC_CREATE2_FACTORY.call(creationBytecode);
require(success, "Failed to deploy Assigner Module");
address assignerAddress = address(uint160(bytes20(returnData)));
console.log("Deployed Assigner module contract at: ", assignerAddress);

creationCode = type(PatchworkProtocol).creationCode;
creationBytecode = abi.encodePacked(creationCode, abi.encode(patchworkOwner), abi.encode(assignerAddress));
(success, returnData) = _DETERMINISTIC_CREATE2_FACTORY.call(creationBytecode);
require(success, "Failed to deploy Patchwork");
address patchworkAddress = address(uint160(bytes20(returnData)));
console.log("Deployed Patchwork contract at: ", patchworkAddress);

vm.stopBroadcast();
}
}
55 changes: 55 additions & 0 deletions management/deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/bin/bash

# deploy.sh

# Usage instructions
if [ $# -lt 1 ]; then
echo "Usage: $0 <network> [--broadcast]"
echo "Supported networks: base, sepolia"
exit 1
fi

# Load the .env file
if [ -f .env ]; then
export $(grep -v '^#' .env | xargs)
else
echo ".env file not found"
exit 1
fi

NETWORK=$1
PATCHWORK_OWNER=""
RPC_URL=""

case $NETWORK in
"base")
PATCHWORK_OWNER=$BASE_PATCHWORK_OWNER
RPC_URL=$BASE_RPC_URL
;;
"sepolia")
PATCHWORK_OWNER=$SEPOLIA_PATCHWORK_OWNER
RPC_URL=$SEPOLIA_RPC_URL
;;
"base-sepolia")
PATCHWORK_OWNER=$BASE_SEPOLIA_PATCHWORK_OWNER
RPC_URL=$BASE_SEPOLIA_RPC_URL
;;
*)
echo "Network not supported"
exit 1
;;
esac

# Check for broadcast flag
if [[ " $* " =~ " --broadcast " ]]; then
echo "Broadcasting is enabled"
forge_options="$forge_options --broadcast"
fi

# Export the owner address as an environment variable
export PATCHWORK_OWNER

# Execute the Solidity script with the environment variable
forge script $forge_options --optimize --optimizer-runs 200 ./deploy.s.sol:DeterministicPatchworkDeploy \
--rpc-url $RPC_URL \
--private-key $PRIVATE_KEY
13 changes: 13 additions & 0 deletions management/encodeConstructorArgs.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "forge-std/Script.sol";
import { PatchworkProtocol } from "src/PatchworkProtocol.sol";

contract EncodeConstructorArgs is Script {
function run() public {
address patchworkOwner = 0x7239aEc2fA59303BA68BEcE386BE2A9dDC72e63B;
bytes memory encodedArgs = abi.encode(patchworkOwner);
console.log("Encoded Constructor Args:", vm.toString(encodedArgs));
}
}
65 changes: 65 additions & 0 deletions management/verify.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/bin/bash

# verify.sh

# Usage instructions
if [ $# -lt 1 ]; then
echo "Usage: $0 <network>"
echo "Supported networks: base, sepolia"
exit 1
fi

NETWORK=$1

# Load the .env file
if [ -f .env ]; then
export $(grep -v '^#' .env | xargs)
else
echo ".env file not found"
exit 1
fi

# Set the network-specific contract address and chain ID
CONTRACT_ADDRESS=""
ASSIGNER_CONTRACT_ADDRESS=""
CHAIN_ID=""

case $NETWORK in
"base")
CONTRACT_ADDRESS=$BASE_PATCHWORK_ADDRESS
ASSIGNER_CONTRACT_ADDRESS=$BASE_PATCHWORK_ASSIGNER_ADDRESS
CHAIN_ID=$BASE_CHAIN_ID
;;
"sepolia")
CONTRACT_ADDRESS=$SEPOLIA_PATCHWORK_ADDRESS
ASSIGNER_CONTRACT_ADDRESS=$SEPOLIA_PATCHWORK_ASSIGNER_ADDRESS
CHAIN_ID=$SEPOLIA_CHAIN_ID
;;
*)
echo "Network not supported"
exit 1
;;
esac


COMPILER_VERSION="0.8.23+commit.f704f362"
OPTIMIZER_RUNS=200

forge verify-contract $ASSIGNER_CONTRACT_ADDRESS src/PatchworkProtocolAssigner.sol:PatchworkProtocolAssigner \
--constructor-args "0x0000000000000000000000007239aec2fa59303ba68bece386be2a9ddc72e63b" \
--chain-id $CHAIN_ID \
--compiler-version $COMPILER_VERSION \
--optimizer-runs $OPTIMIZER_RUNS \
--etherscan-api-key $ETHERSCAN_API_KEY \
--watch

CLEANED_ASSIGNER_CONTRACT_ADDRESS=$(echo "$ASSIGNER_CONTRACT_ADDRESS" | sed 's/^0x//')

forge verify-contract $CONTRACT_ADDRESS src/PatchworkProtocol.sol:PatchworkProtocol \
--constructor-args "0x0000000000000000000000007239aec2fa59303ba68bece386be2a9ddc72e63b000000000000000000000000$CLEANED_ASSIGNER_CONTRACT_ADDRESS"\
--chain-id $CHAIN_ID \
--compiler-version $COMPILER_VERSION \
--optimizer-runs $OPTIMIZER_RUNS \
--etherscan-api-key $ETHERSCAN_API_KEY \
--watch

1 change: 0 additions & 1 deletion remappings.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
@openzeppelin/=lib/openzeppelin-contracts/
@patchwork/=src/
forge-std/=lib/forge-std/src/
89 changes: 89 additions & 0 deletions src/Patchwork1155Patch.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import "./Patchwork721.sol";
import "./interfaces/IPatchwork1155Patch.sol";

/**
@title Patchwork1155Patch
@dev Base implementation of IPatchwork1155Patch
@dev It extends the functionalities of Patchwork721 and implements the IPatchwork1155Patch interface.
*/
abstract contract Patchwork1155Patch is Patchwork721, IPatchwork1155Patch {

/// @dev Mapping from token ID to the canonical address of the NFT that this patch is applied to.
mapping(uint256 => PatchTarget) internal _targetsById;

/**
@dev See {IERC165-supportsInterface}
*/
function supportsInterface(bytes4 interfaceID) public view virtual override returns (bool) {
return interfaceID == type(IPatchwork1155Patch).interfaceId ||
super.supportsInterface(interfaceID);
}

/**
@notice stores a patch
@param tokenId the tokenId of the patch
@param target the patch target
*/
function _storePatch(uint256 tokenId, PatchTarget memory target) internal virtual {
_targetsById[tokenId] = target;
}

/**
@dev See {ERC721-_burn}
*/
function _burnPatch(uint256 tokenId) internal virtual {
PatchTarget storage target = _targetsById[tokenId];
address originalAddress = target.addr;
uint256 originalTokenId = target.tokenId;
address account = target.account;
IPatchworkProtocol(_manager).patchBurned1155(originalAddress, originalTokenId, account, address(this));
delete _targetsById[tokenId];
_burn(tokenId);
}
}

/**
@title PatchworkReversible1155Patch
@dev Patchwork1155Patch with reverse lookup function
*/
abstract contract PatchworkReversible1155Patch is Patchwork1155Patch, IPatchworkReversible1155Patch {
/// @dev Mapping of hash of original address + token ID + account for reverse lookups
mapping(bytes32 => uint256) internal _idsByTargetHash; // hash of patched addr+tokenid+account to tokenId

/**
@dev See {IERC165-supportsInterface}
*/
function supportsInterface(bytes4 interfaceID) public view virtual override returns (bool) {
return interfaceID == type(IPatchworkReversible1155Patch).interfaceId ||
super.supportsInterface(interfaceID);
}

/**
@dev See {IPatchwork1155Patch-getTokenIdByTarget}
*/
function getTokenIdByTarget(PatchTarget memory target) public view virtual returns (uint256 tokenId) {
return _idsByTargetHash[keccak256(abi.encode(target))];
}

/**
@notice stores a patch
@param tokenId the tokenId of the patch
@param target the patch target
*/
function _storePatch(uint256 tokenId, PatchTarget memory target) internal virtual override {
_targetsById[tokenId] = target;
_idsByTargetHash[keccak256(abi.encode(target))] = tokenId;
}

/**
@dev See {ERC721-_burn}
*/
function _burnPatch(uint256 tokenId) internal virtual override {
PatchTarget storage target = _targetsById[tokenId];
delete _idsByTargetHash[keccak256(abi.encode(target))];
super._burnPatch(tokenId);
}
}
Loading