Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REG-1449] feat: Update ENSCustody contract to support wallet migration #370

Merged
merged 7 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## v0.9.35

- Added ability to internalTransfer parked domains in `ENSCustody`
- Added `multicall` to ENSCustody

## v0.9.34

- Add `.lfg`, `.dream` Polygon TLD
Expand Down
41 changes: 39 additions & 2 deletions artifacts/ENSCustody.json

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions artifacts/IENSCustody.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,24 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "internalTransfer",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
2 changes: 1 addition & 1 deletion artifacts/abi/ENSCustody.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion artifacts/abi/IENSCustody.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"Parked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"commit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"bytes32","name":"secret","type":"bytes32"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"reverseRecord","type":"bool"},{"internalType":"uint16","name":"ownerControlledFuses","type":"uint16"},{"internalType":"bool","name":"selfCustody","type":"bool"}],"name":"makeCommitment","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"bytes32","name":"secret","type":"bytes32"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"reverseRecord","type":"bool"},{"internalType":"uint16","name":"ownerControlledFuses","type":"uint16"},{"internalType":"bool","name":"selfCustody","type":"bool"}],"name":"register","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"renew","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"rentPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"Parked","type":"event"},{"inputs":[{"internalType":"bytes32","name":"commitment","type":"bytes32"}],"name":"commit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"internalTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"bytes32","name":"secret","type":"bytes32"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"reverseRecord","type":"bool"},{"internalType":"uint16","name":"ownerControlledFuses","type":"uint16"},{"internalType":"bool","name":"selfCustody","type":"bool"}],"name":"makeCommitment","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"bytes32","name":"secret","type":"bytes32"},{"internalType":"address","name":"resolver","type":"address"},{"internalType":"bytes[]","name":"data","type":"bytes[]"},{"internalType":"bool","name":"reverseRecord","type":"bool"},{"internalType":"uint16","name":"ownerControlledFuses","type":"uint16"},{"internalType":"bool","name":"selfCustody","type":"bool"}],"name":"register","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"renew","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"rentPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
23 changes: 22 additions & 1 deletion contracts/custody/ENSCustody.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {IENSCustody, Unauthorised, InvalidToken, UnknownToken, CustodyNotEnoughB
import {InvalidForwardedToken, ERC2771RegistryContext} from '../metatx/ERC2771RegistryContext.sol';
import {Forwarder} from '../metatx/Forwarder.sol';
import {MinterRole} from '../roles/MinterRole.sol';
import {Multicall} from '../utils/Multicall.sol';

contract ENSCustody is
Initializable,
Expand All @@ -27,10 +28,11 @@ contract ENSCustody is
ERC2771RegistryContext,
Forwarder,
MinterRole,
Multicall,
IENSCustody
{
string public constant NAME = 'ENS Custody';
string public constant VERSION = '0.1.3';
string public constant VERSION = '0.1.4';

bytes32 private constant _ETH_NODE = 0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae;
// This is the keccak-256 hash of "ens.owner." subtracted by 1
Expand Down Expand Up @@ -216,14 +218,33 @@ contract ENSCustody is

function safeTransfer(address to, uint256 tokenId) external onlyTokenOwner(tokenId) {
_protectTokenOperation(tokenId);

StorageSlotUpgradeable.getAddressSlot(keccak256(abi.encodePacked(_OWNER_PREFIX_SLOT, tokenId))).value = address(0);

INameWrapper _wrapper = INameWrapper(StorageSlotUpgradeable.getAddressSlot(_ENS_WRAPPER_SLOT).value);

_wrapper.safeTransferFrom(address(this), to, tokenId, 1, '');
}

function internalTransfer(address to, uint256 tokenId) external onlyTokenOwner(tokenId) {
_protectTokenOperation(tokenId);
_park(tokenId, to);
}

receive() external payable {}

function multicall(bytes[] calldata data) public returns (bytes[] memory results) {
bytes[] memory _data = data;

if (isTrustedForwarder(msg.sender)) {
for (uint256 i = 0; i < data.length; i++) {
_data[i] = _buildData(_msgSender(), _msgToken(), data[i], '');
}
}

return _multicall(_data);
}

function _register(
string calldata name,
address owner,
Expand Down
7 changes: 7 additions & 0 deletions contracts/custody/IENSCustody.sol
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ interface IENSCustody is IERC1155ReceiverUpgradeable {
*/
function safeTransfer(address to, uint256 tokenId) external;

/**
* @dev Transfers of internal ownership of a given token ID to another address.
* @param to The address to receive the ownership of the given token ID
* @param tokenId uint256 ID of the token to transfer of
*/
function internalTransfer(address to, uint256 tokenId) external;

/**
* @dev Fallback function to receive ETH.
*/
Expand Down
1 change: 1 addition & 0 deletions contracts/utils/Multicall.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import '@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol';
abstract contract Multicall {
/**
* @dev Receives and executes a batch of function calls on this contract.
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function _multicall(bytes[] memory data) internal returns (bytes[] memory results) {
results = new bytes[](data.length);
Expand Down
2 changes: 1 addition & 1 deletion dist/sandbox/state.json

Large diffs are not rendered by default.

30 changes: 25 additions & 5 deletions dist/types/contracts/custody/ENSCustody.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export declare namespace IForwarder {
};
}
export interface ENSCustodyInterface extends Interface {
getFunction(nameOrSignature: "DEFAULT_ADMIN_ROLE" | "MINTER_ROLE" | "NAME" | "VERSION" | "addMinter" | "addMinters" | "closeMinter" | "commit" | "execute" | "getRoleAdmin" | "grantRole" | "hasRole" | "initialize" | "isMinter" | "isTrustedForwarder" | "makeCommitment" | "nonceOf" | "onERC1155BatchReceived" | "onERC1155Received" | "onERC721Received" | "owner" | "ownerOf" | "register" | "removeMinter" | "removeMinters" | "renew" | "renounceMinter" | "renounceOwnership" | "renounceRole" | "rentPrice" | "revokeRole" | "rotateMinter" | "safeTransfer" | "setBaseRegistrar" | "supportsInterface" | "transferOwnership" | "verify"): FunctionFragment;
getFunction(nameOrSignature: "DEFAULT_ADMIN_ROLE" | "MINTER_ROLE" | "NAME" | "VERSION" | "addMinter" | "addMinters" | "closeMinter" | "commit" | "execute" | "getRoleAdmin" | "grantRole" | "hasRole" | "initialize" | "isMinter" | "isTrustedForwarder" | "makeCommitment" | "multicall" | "nonceOf" | "onERC1155BatchReceived" | "onERC1155Received" | "onERC721Received" | "owner" | "ownerOf" | "register" | "removeMinter" | "removeMinters" | "renew" | "renounceMinter" | "renounceOwnership" | "renounceRole" | "rentPrice" | "revokeRole" | "rotateMinter" | "safeTransfer(address,uint256,bool)" | "safeTransfer(address,uint256)" | "setBaseRegistrar" | "supportsInterface" | "transferOwnership" | "verify"): FunctionFragment;
getEvent(nameOrSignatureOrTopic: "Initialized" | "OwnershipTransferred" | "Parked" | "RoleAdminChanged" | "RoleGranted" | "RoleRevoked"): EventFragment;
encodeFunctionData(functionFragment: "DEFAULT_ADMIN_ROLE", values?: undefined): string;
encodeFunctionData(functionFragment: "MINTER_ROLE", values?: undefined): string;
Expand Down Expand Up @@ -48,6 +48,7 @@ export interface ENSCustodyInterface extends Interface {
BigNumberish,
boolean
]): string;
encodeFunctionData(functionFragment: "multicall", values: [BytesLike[]]): string;
encodeFunctionData(functionFragment: "nonceOf", values: [BigNumberish]): string;
encodeFunctionData(functionFragment: "onERC1155BatchReceived", values: [
AddressLike,
Expand Down Expand Up @@ -80,7 +81,8 @@ export interface ENSCustodyInterface extends Interface {
encodeFunctionData(functionFragment: "rentPrice", values: [string, BigNumberish]): string;
encodeFunctionData(functionFragment: "revokeRole", values: [BytesLike, AddressLike]): string;
encodeFunctionData(functionFragment: "rotateMinter", values: [AddressLike]): string;
encodeFunctionData(functionFragment: "safeTransfer", values: [AddressLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "safeTransfer(address,uint256,bool)", values: [AddressLike, BigNumberish, boolean]): string;
encodeFunctionData(functionFragment: "safeTransfer(address,uint256)", values: [AddressLike, BigNumberish]): string;
encodeFunctionData(functionFragment: "setBaseRegistrar", values: [AddressLike]): string;
encodeFunctionData(functionFragment: "supportsInterface", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "transferOwnership", values: [AddressLike]): string;
Expand All @@ -101,6 +103,7 @@ export interface ENSCustodyInterface extends Interface {
decodeFunctionResult(functionFragment: "isMinter", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "isTrustedForwarder", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "makeCommitment", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "multicall", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "nonceOf", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "onERC1155BatchReceived", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "onERC1155Received", data: BytesLike): Result;
Expand All @@ -117,7 +120,8 @@ export interface ENSCustodyInterface extends Interface {
decodeFunctionResult(functionFragment: "rentPrice", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "revokeRole", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "rotateMinter", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "safeTransfer", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "safeTransfer(address,uint256,bool)", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "safeTransfer(address,uint256)", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "setBaseRegistrar", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "supportsInterface", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "transferOwnership", data: BytesLike): Result;
Expand Down Expand Up @@ -283,6 +287,7 @@ export interface ENSCustody extends BaseContract {
], [
string
], "view">;
multicall: TypedContractMethod<[data: BytesLike[]], [string[]], "nonpayable">;
nonceOf: TypedContractMethod<[tokenId: BigNumberish], [bigint], "view">;
onERC1155BatchReceived: TypedContractMethod<[
arg0: AddressLike,
Expand Down Expand Up @@ -362,7 +367,14 @@ export interface ENSCustody extends BaseContract {
void
], "nonpayable">;
rotateMinter: TypedContractMethod<[receiver: AddressLike], [void], "payable">;
safeTransfer: TypedContractMethod<[
"safeTransfer(address,uint256,bool)": TypedContractMethod<[
to: AddressLike,
tokenId: BigNumberish,
internalTransfer: boolean
], [
void
], "nonpayable">;
"safeTransfer(address,uint256)": TypedContractMethod<[
to: AddressLike,
tokenId: BigNumberish
], [
Expand Down Expand Up @@ -439,6 +451,7 @@ export interface ENSCustody extends BaseContract {
], [
string
], "view">;
getFunction(nameOrSignature: "multicall"): TypedContractMethod<[data: BytesLike[]], [string[]], "nonpayable">;
getFunction(nameOrSignature: "nonceOf"): TypedContractMethod<[tokenId: BigNumberish], [bigint], "view">;
getFunction(nameOrSignature: "onERC1155BatchReceived"): TypedContractMethod<[
arg0: AddressLike,
Expand Down Expand Up @@ -510,7 +523,14 @@ export interface ENSCustody extends BaseContract {
void
], "nonpayable">;
getFunction(nameOrSignature: "rotateMinter"): TypedContractMethod<[receiver: AddressLike], [void], "payable">;
getFunction(nameOrSignature: "safeTransfer"): TypedContractMethod<[
getFunction(nameOrSignature: "safeTransfer(address,uint256,bool)"): TypedContractMethod<[
to: AddressLike,
tokenId: BigNumberish,
internalTransfer: boolean
], [
void
], "nonpayable">;
getFunction(nameOrSignature: "safeTransfer(address,uint256)"): TypedContractMethod<[
to: AddressLike,
tokenId: BigNumberish
], [
Expand Down
2 changes: 1 addition & 1 deletion dist/types/contracts/custody/ENSCustody.d.ts.map

Large diffs are not rendered by default.

34 changes: 33 additions & 1 deletion dist/types/factories/contracts/custody/ENSCustody__factory.d.ts

Large diffs are not rendered by default.

Loading
Loading