diff --git a/justfile b/justfile deleted file mode 100644 index 789b1ea..0000000 --- a/justfile +++ /dev/null @@ -1,2 +0,0 @@ -default: - echo 'Hello, world!' diff --git a/package.json b/package.json index bb5ad9d..9b9365b 100644 --- a/package.json +++ b/package.json @@ -8,22 +8,9 @@ "license": "MIT", "type": "module", "scripts": { - "abi": "node ./test/abigen.js", - "gen": "node ./test/recgen.js", "local": "anvil --fork-url https://rpc.ankr.com/eth_goerli", "localDeploy": "forge fmt && source .env && forge script ./script/Deploy.s.sol --rpc-url http://127.0.0.1:8545 --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 --broadcast -vvvv", "test": "forge fmt && source .env && forge test --fork-url $GOERLI_RPC_URL -vvvv --fork-block-number 8897000 --gas-report", "dev": "forge fmt && source .env && forge test --fork-url $GOERLI_RPC_URL -vvv --fork-block-number 8897000 --gas-report --watch" - }, - "devDependencies": { - "concurrently": "^8.1.0", - "jest": "^29.5.0", - "nodemon": "^2.0.22" - }, - "dependencies": { - "@noble/curves": "^1.1.0", - "@noble/hashes": "^1.3.1", - "@noble/secp256k1": "^1.7.1", - "viem": "^1.0.2" } } diff --git a/src/CCIP2ETH.sol b/src/CCIP2ETH.sol index 4213c0a..a359beb 100644 --- a/src/CCIP2ETH.sol +++ b/src/CCIP2ETH.sol @@ -22,11 +22,11 @@ contract CCIP2ETH is iCCIP2ETH { /// Events event ThankYou(address indexed addr, uint256 indexed value); - event UpdatedGatewayManager(address indexed oldAddr, address indexed newAddr); + event GatewayUpdated(address indexed oldAddr, address indexed newAddr); event RecordhashChanged(address indexed owner, bytes32 indexed node, bytes contenthash); event UpdatedWrapper(address indexed newAddr, bool indexed status); event ApprovedSigner(address owner, bytes32 indexed node, address indexed delegate, bool indexed approved); - event UpdatedSupportedInterface(bytes4 indexed sig, bool indexed status); + event InterfaceUpdated(bytes4 indexed sig, bool indexed status); /// Errors error InvalidSignature(string message); @@ -68,59 +68,33 @@ contract CCIP2ETH is iCCIP2ETH { supportsInterface[iCCIP2ETH.setRecordhash.selector] = true; } - /** - * @dev Checks if a manager is authorised by the owner of ENS domain - * @param _node - Namehash of ENS domain - * @param _owner - Owner of ENS domain - * @param _manager - Manager address to check - */ - function isAuthorized(bytes32 _node, address _owner, address _manager) public view returns (bool) { - return (isApprovedSigner[_owner][_node][_manager] || ENS.isApprovedForAll(_owner, _manager)); - } - - /** - * @dev Set new Gateway Manager Contract - * @param _gateway - Address of new Gateway Manager Contract - */ - function updateGatewayManager(address _gateway) external { - require(msg.sender == gateway.owner(), "ONLY_DEV"); - require(msg.sender == iGatewayManager(_gateway).owner(), "BAD_GATEWAY"); - emit UpdatedGatewayManager(address(gateway), _gateway); - gateway = iGatewayManager(_gateway); - } - /** * @dev Sets recordhash for a (sub)node or ownerhash for an owner * Note - Only ENS owner or manager of node can call - * @param _subdomain - Subdomain labels; a.b.c.domain.eth = [a, b, c] * Note - Provide '[]' value for setting recordhash for domain.eth * @param _node - Namehash of domain.eth * Note - Provide 'bytes32(0)' for setting ownerhash - * @param _contenthash - Contenthash to set as recordhash or ownerhash + * @param _recordhash - Contenthash to set as recordhash or ownerhash */ - function setRecordhash(string[] calldata _subdomain, bytes32 _node, bytes calldata _contenthash) external { - bytes32 _namehash = _node; - if (_node == bytes32(0)) { - // Set ownerhash if no node is provided - ownerhash[keccak256(abi.encodePacked(msg.sender))] = _contenthash; - } else { - // Set recordhash otherwise - address _owner = ENS.owner(_node); - if (isWrapper[_owner]) { - _owner = iToken(_owner).ownerOf(uint256(_node)); - } - require(msg.sender == _owner || isApprovedSigner[_owner][_node][msg.sender], "NOT_AUTHORIZED"); - // Update sub(domain) namehash if subdomain labels are provided - uint256 len = _subdomain.length; - unchecked { - while (len > 0) { - _namehash = keccak256(abi.encodePacked(_namehash, keccak256(bytes(_subdomain[--len])))); - } - } - // Set recordhash for the (sub)node - recordhash[_namehash] = _contenthash; + function setRecordhash(bytes32 _node, bytes calldata _recordhash) external { + address _owner = ENS.owner(_node); + if (isWrapper[_owner]) { + _owner = iToken(_owner).ownerOf(uint256(_node)); } - emit RecordhashChanged(msg.sender, _namehash, _contenthash); + require(msg.sender == _owner || isApprovedSigner[_owner][_node][msg.sender], "NOT_AUTHORIZED"); + recordhash[_node] = _recordhash; + emit RecordhashChanged(msg.sender, _node, _recordhash); + } + + function setOwnerhash(bytes calldata _recordhash) external payable { + require(msg.value >= ownerhashFees, "PLS_FUNDU_DEVS"); + recordhash[keccak256(abi.encodePacked(msg.sender))] = _recordhash; + emit RecordhashChanged(msg.sender, bytes32(type(uint).max), _recordhash); + } + + uint ownerhashFees = 0.001 ether; + function updateOwnerhashFees(uint _fees) external OnlyDev { + ownerhashFees = _fees; } /** @@ -135,7 +109,7 @@ contract CCIP2ETH is iCCIP2ETH { /// @dev - DNSDecode() routine uint256 index = 1; uint256 n = 1; - uint256 len = uint8(bytes1(name[:1])); + uint256 len = uint8(bytes1(name[0])); bytes[] memory _labels = new bytes[](42); _labels[0] = name[1:n += len]; string memory _path = string(_labels[0]); @@ -152,36 +126,34 @@ contract CCIP2ETH is iCCIP2ETH { while (index > 0) { _namehash = keccak256(abi.encodePacked(_namehash, keccak256(_labels[--index]))); // Check if sub(domain) exists on-chain or off-chain - if (ENS.recordExists(_namehash) || bytes(recordhash[_namehash]).length > 0) { + if (ENS.recordExists(_namehash)) { _node = _namehash; _recordhash = recordhash[_namehash]; + } else if(bytes(recordhash[_namehash]).length > 0){ + _recordhash = recordhash[_namehash]; } } address _owner = ENS.owner(_node); + if (isWrapper[_owner]) { + _owner = iToken(_owner).ownerOf(uint256(_node)); + } if (_recordhash.length == 0) { - // Check if recordhash exists - bytes32 _addrhash = keccak256(abi.encodePacked(_owner)); - if (ownerhash[_addrhash].length == 0) { - // Check if ownerhash exists, if no recordhash is found + _recordhash = recordhash[keccak256(abi.encodePacked(_owner))]; + if (_recordhash.length == 0) { revert("RECORD_NOT_SET"); } - _recordhash = ownerhash[_addrhash]; // Fallback to ownerhash in absence of recordhash - } - string memory _recType = gateway.funcToJson(request); // Filename for the requested record - // Update ownership if domain is wrapped - if (isWrapper[_owner]) { - _owner = iToken(_owner).ownerOf(uint256(_node)); } + string memory _recType = gateway.funcToJson(request); bytes32 _checkHash = keccak256( abi.encodePacked(this, blockhash(block.number - 1), _owner, _domain, _path, request, _recType) ); revert OffchainLookup( - address(this), // Callback contract (= THIS, for this case) + address(this), gateway.randomGateways( _recordhash, string.concat("/.well-known/", _path, "/", _recType), uint256(_checkHash) - ), // Generate pseudo-random list of gateways for record resolution - abi.encodePacked(uint16(block.timestamp / 60)), // Cache = 60 seconds - iCCIP2ETH.__callback.selector, // Callback function + ), + abi.encodePacked(uint16(block.timestamp / 60)), + iCCIP2ETH.__callback.selector, abi.encode(_node, block.number - 1, _namehash, _checkHash, _domain, _path, request) ); } @@ -196,14 +168,14 @@ contract CCIP2ETH is iCCIP2ETH { * @return _redirectRequest - Redirected request * @return domain - String-formatted ENS domain */ - function redirectApplicationService(bytes calldata _encoded, bytes calldata _requested) + function redirectService(bytes calldata _encoded, bytes calldata _requested) external view returns (bytes4 _selector, bytes32 _namehash, bytes memory _redirectRequest, string memory domain) { uint256 index = 1; uint256 n = 1; - uint256 len = uint8(bytes1(_encoded[:1])); + uint256 len = uint8(bytes1(_encoded[0])); bytes[] memory _labels = new bytes[](42); _labels[0] = _encoded[1:n += len]; domain = string(_labels[0]); @@ -242,19 +214,19 @@ contract CCIP2ETH is iCCIP2ETH { bytes memory _signature, string memory _domain ) public view returns (bool) { - address _Signer = iCCIP2ETH(this).getSigner( + address _signer = iCCIP2ETH(this).getSigner( string.concat( - "Requesting Signature To Approve Records Signer\n", - "\nDomain: ", + "Requesting Signature To Approve Offchain ENS Records Signer\n", + "\nOrigin: ", _domain, "\nApproved Signer: eip155:1:", gateway.toChecksumAddress(_approvedSigner), - "\nOwner: eip155:1:", + "\nApproved By: eip155:1:", gateway.toChecksumAddress(_owner) ), _signature ); - return (_Signer == _owner || isApprovedSigner[_owner][_node][_Signer]); + return (_signer == _owner || isApprovedSigner[_owner][_node][_signer]); } /** @@ -290,20 +262,11 @@ contract CCIP2ETH is iCCIP2ETH { == keccak256(abi.encodePacked(this, blockhash(_blocknumber), _owner, _domain, _path, _request, _recType)), "INVALID_CHECKSUM/TIMEOUT" ); - // Signer could be: - // a) Owner - // OR, b) On-chain approved manager - // OR, c) Off-chain approved signer address _signer; - /// Signature associated with the record bytes memory _recordSignature; - /// Init off-chain manager's signature request string memory signRequest; - /// Get signer-type from response identifier bytes4 _type = bytes4(response[:4]); - /// Off-chain signature approving record signer (if signer != owner or on-chain manager) bytes memory _approvedSig; - /// @dev CCIP Response Decode (_signer, _recordSignature, _approvedSig, result) = abi.decode(response[4:], (address, bytes, bytes, bytes)); if (_approvedSig.length < 64) { require(_signer == _owner || isApprovedSigner[_owner][_node][_signer], "INVALID_CALLBACK"); @@ -311,58 +274,32 @@ contract CCIP2ETH is iCCIP2ETH { require(approvedSigner(_owner, _signer, _node, _approvedSig, _domain), "BAD_RECORD_APPROVAL"); } if (_type == iCallbackType.signedRecord.selector) { - /// @dev If 'signedRecord()' bytes4 selector; handles signed records signRequest = string.concat( - "Requesting Signature To Update Record\n", - "\nDomain: ", + "Requesting Signature To Update ENS Record\n", + "\nOrigin: ", _domain, "\nType: ", _recType, "\nExtradata: 0x", gateway.bytesToHexString(abi.encodePacked(keccak256(result)), 0), - "\nSigner: eip155:1:", + "\nSigned By: eip155:1:", gateway.toChecksumAddress(_signer) ); require(_signer == iCCIP2ETH(this).getSigner(signRequest, _recordSignature), "BAD_SIGNED_RECORD"); } else if (_type == iCallbackType.signedRedirect.selector) { - /// @dev If 'signedRedirect()' bytes4 selector; handles redirected records - if (result[0] == 0x0) { - signRequest = string.concat( - "Requesting Signature To Redirect Records\n", - "\nENS Domain: ", - _domain, // .domain.eth - "\nExtradata: ", - gateway.bytesToHexString(abi.encodePacked(keccak256(result)), 0), - "\nSigned By: eip155:1:", - gateway.toChecksumAddress(_signer) - ); - require(_signer == iCCIP2ETH(this).getSigner(signRequest, _recordSignature), "BAD_DAPP_SIGNATURE"); - // Signed IPFS redirect - revert OffchainLookup( - address(this), - gateway.randomGateways( - abi.decode(result, (bytes)), // ABI-decode as recordhash to redirect - string.concat("/.well-known/", _path, "/", _recType), - uint256(_checkHash) - ), - abi.encodePacked(uint16(block.timestamp / 60)), - gateway.__fallback.selector, // Fallback; 2nd Callback - abi.encode(_node, block.number - 1, _namehash, _checkHash, _domain, _path, _request) - ); + if(result[0] == 0x0){ + return gateway.__fallback(response, extradata); } - // ENS dApp redirect - // Result should be DNS encoded; result should NOT be ABI-encoded - // Note Last byte is 0x00, meaning end of DNS-encoded stream require(result[result.length - 1] == 0x0, "BAD_ENS_ENCODED"); (bytes4 _sig, bytes32 _redirectNamehash, bytes memory _redirectRequest, string memory _redirectDomain) = - CCIP2ETH(this).redirectApplicationService(result, _request); + iCCIP2ETH(this).redirectService(result, _request); signRequest = string.concat( - "Requesting Signature To Install dApp Service\n", - "\nDomain: ", + "Requesting Signature To Install DApp Service\n", + "\nOrigin: ", _domain, // e.g. ens.domain.eth - "\ndApp: ", + "\nDApp: ", _redirectDomain, // e.g. app.ens.eth - "\nSigner: eip155:1:", + "\nSigned By: eip155:1:", gateway.toChecksumAddress(_signer) ); require(_signer == iCCIP2ETH(this).getSigner(signRequest, _recordSignature), "BAD_DAPP_SIGNATURE"); @@ -386,29 +323,29 @@ contract CCIP2ETH is iCCIP2ETH { /** * @dev Checks if a signature is valid - * @param signRequest - String-formatted message that was signed - * @param signature - Compact signature to verify - * @return signer - Signer of message - * @notice - Signature Format: + * @param _message - String-formatted message that was signed + * @param _signature - Compact signature to verify + * @return _signer - Signer of message + * @notice Signature Format: * a) 64 bytes - bytes32(r) + bytes32(vs) ~ compact, or * b) 65 bytes - bytes32(r) + bytes32(s) + uint8(v) ~ packed, or * c) 96 bytes - bytes32(r) + bytes32(s) + uint256(v) ~ longest */ - function getSigner(string calldata signRequest, bytes calldata signature) external view returns (address signer) { - bytes32 r = bytes32(signature[:32]); + function getSigner(string calldata _message, bytes calldata _signature) external view returns (address _signer) { + bytes32 r = bytes32(_signature[:32]); bytes32 s; uint8 v; - uint256 len = signature.length; + uint256 len = _signature.length; if (len == 64) { - bytes32 vs = bytes32(signature[32:]); + bytes32 vs = bytes32(_signature[32:]); s = vs & bytes32(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); v = uint8((uint256(vs) >> 255) + 27); } else if (len == 65) { - s = bytes32(signature[32:64]); - v = uint8(bytes1(signature[64:])); + s = bytes32(_signature[32:64]); + v = uint8(bytes1(_signature[64:])); } else if (len == 96) { - s = bytes32(signature[32:64]); - v = uint8(uint256(bytes32(signature[64:]))); + s = bytes32(_signature[32:64]); + v = uint8(uint256(bytes32(_signature[64:]))); } else { revert InvalidSignature("BAD_SIG_LENGTH"); } @@ -417,11 +354,11 @@ contract CCIP2ETH is iCCIP2ETH { } bytes32 digest = keccak256( abi.encodePacked( - "\x19Ethereum Signed Message:\n", gateway.uintToString(bytes(signRequest).length), signRequest + "\x19Ethereum Signed Message:\n", gateway.uintToString(bytes(_message).length), _message ) ); - signer = ecrecover(digest, v, r, s); - require(signer != address(0), "ZERO_ADDR"); + _signer = ecrecover(digest, v, r, s); + require(_signer != address(0), "ZERO_ADDR"); } /** @@ -443,8 +380,8 @@ contract CCIP2ETH is iCCIP2ETH { */ function multiApprove(bytes32[] calldata _node, address[] calldata _signer, bool[] calldata _approval) external { uint256 len = _node.length; - require(len == _signer.length, "BAD_LENGTH"); - require(len == _approval.length, "BAD_LENGTH"); + //require(len == _signer.length, "BAD_LENGTH"); + //require(len == _approval.length, "BAD_LENGTH"); for (uint256 i = 0; i < len; i++) { isApprovedSigner[msg.sender][_node[i]][_signer[i]] = _approval[i]; emit ApprovedSigner(msg.sender, _node[i], _signer[i], _approval[i]); @@ -464,15 +401,32 @@ contract CCIP2ETH is iCCIP2ETH { return _owner == _signer || isApprovedSigner[_owner][_node][_signer]; } + + /// @dev : management functions + + modifier OnlyDev(){ + require(msg.sender == gateway.owner(), "ONLY_DEV"); + _; + } + + /** + * @dev Set new Gateway Manager Contract + * @param _gateway - Address of new Gateway Manager Contract + */ + function updateGateway(address _gateway) external OnlyDev { + require(msg.sender == iGatewayManager(_gateway).owner(), "BAD_GATEWAY"); + emit GatewayUpdated(address(gateway), _gateway); + gateway = iGatewayManager(_gateway); + } + /** * @dev Updates supported interfaces * @param _sig - 4-byte interface selector * @param _set - State to set for selector */ - function updateSupportedInterface(bytes4 _sig, bool _set) external { - require(msg.sender == gateway.owner(), "ONLY_DEV"); + function updateInterface(bytes4 _sig, bool _set) external OnlyDev { supportsInterface[_sig] = _set; - emit UpdatedSupportedInterface(_sig, _set); + emit InterfaceUpdated(_sig, _set); } /** @@ -480,9 +434,8 @@ contract CCIP2ETH is iCCIP2ETH { * @param _addr - Address of ENS wrapper * @param _set - State to set for new ENS wrapper */ - function updateWrapper(address _addr, bool _set) external { - require(msg.sender == gateway.owner(), "ONLY_DEV"); - require(!_set || _addr.code.length > 0, "ONLY_CONTRACT"); + function updateWrapper(address _addr, bool _set) external OnlyDev { + require(_addr.code.length > 0, "ONLY_CONTRACT"); isWrapper[_addr] = _set; emit UpdatedWrapper(_addr, _set); } @@ -503,19 +456,19 @@ contract CCIP2ETH is iCCIP2ETH { /** * @dev To be used for tips or in case some fungible tokens get locked in the contract - * @param _tokenContract - Token contract address + * @param _contract - Token contract address * @param _balance - Amount to release */ - function withdraw(address _tokenContract, uint256 _balance) external { - iToken(_tokenContract).transferFrom(address(this), gateway.owner(), _balance); + function withdraw(address _contract, uint256 _balance) external { + iToken(_contract).transferFrom(address(this), gateway.owner(), _balance); } /** * @dev To be used for tips or in case some non-fungible tokens get locked in the contract - * @param _tokenContract - Token contract address - * @param _tokenID - Token ID to release + * @param _contract - Token contract address + * @param _token - Token ID to release */ - function safeWithdraw(address _tokenContract, uint256 _tokenID) external { - iToken(_tokenContract).safeTransferFrom(address(this), gateway.owner(), _tokenID); + function safeWithdraw(address _contract, uint256 _token) external { + iToken(_contract).safeTransferFrom(address(this), gateway.owner(), _token); } } diff --git a/src/Interface.sol b/src/Interface.sol index a32c034..c7a0677 100644 --- a/src/Interface.sol +++ b/src/Interface.sol @@ -36,7 +36,12 @@ interface iCCIP2ETH is iENSIP10 { external view returns (address _signer); - function setRecordhash(string[] memory _subdomains, bytes32 _node, bytes calldata _contenthash) external; + function setRecordhash(bytes32 _node, bytes calldata _recordhash) external; + function setOwnerhash(bytes calldata _recordhash) external payable; + function redirectService(bytes calldata _encoded, bytes calldata _requested) + external + view + returns (bytes4 _selector, bytes32 _namehash, bytes memory _redirectRequest, string memory domain); } interface iGatewayManager is iERC173 { @@ -101,6 +106,6 @@ interface iCallbackType { address recordSigner, // Owner OR On-chain Manager OR Off-chain Manager bytes memory recordSignature, // Signature from signer for redirect value bytes memory approvedSignature, // bytes1(..) IF signer is owner or on-chain manager - bytes memory redirect // ABI-encoded recordhash OR DNS-encoded domain.eth to redirect + bytes memory redirect // DNS-encoded domain.eth to redirect ) external view returns (bytes memory); } diff --git a/test/CCIP2ETH.t.sol b/test/CCIP2ETH.t.sol index 80abaa7..f40579f 100644 --- a/test/CCIP2ETH.t.sol +++ b/test/CCIP2ETH.t.sol @@ -52,7 +52,6 @@ contract CCIP2ETHTest is Test { /// @dev Test CCIP-Read call for a domain function test2_ResolveLevel2() public { - string[] memory _subdomains = new string[](0); bytes[] memory _name = new bytes[](2); _name[0] = "ccip2"; _name[1] = "eth"; @@ -63,7 +62,7 @@ contract CCIP2ETHTest is Test { vm.prank(_addr); //ENS.setOwner(_namehash, address(this)); //ENS.setResolver(_namehash, address(ccip2eth)); - ccip2eth.setRecordhash(_subdomains, _namehash, _recordhash); + ccip2eth.setRecordhash(_namehash, _recordhash); (string memory _path, string memory _domain) = utils.Format(_encoded); bytes memory _request = abi.encodePacked(iResolver.addr.selector, _namehash); string memory _recType = gateway.funcToJson(_request); @@ -87,7 +86,6 @@ contract CCIP2ETHTest is Test { /// @dev Test subdomain-level CCIP-Read call function test3_ResolveLevel3() public { - string[] memory _subdomains = new string[](0); bytes[] memory _name = new bytes[](3); _name[0] = "blog"; _name[1] = "vitalik"; @@ -98,7 +96,7 @@ contract CCIP2ETHTest is Test { ENS.setOwner(_namehash, address(this)); bytes memory _recordhash = hex"e50101720024080112203c5aba6c9b5055a5fa12281c486188ed8ae2b6ef394b3d981b00d17a4b51735c"; - ccip2eth.setRecordhash(_subdomains, _namehash, _recordhash); + ccip2eth.setRecordhash(_namehash, _recordhash); (string memory _path, string memory _domain) = utils.Format(_encoded); bytes memory _request = abi.encodePacked(iResolver.text.selector, _namehash, abi.encode(string("avatar"))); string memory _recType = gateway.funcToJson(_request); @@ -124,7 +122,6 @@ contract CCIP2ETHTest is Test { /// @dev Test deep CCIP-Read call function test4_ResolveLevel7() public { - string[] memory _subdomains = new string[](0); bytes[] memory _base = new bytes[](2); _base[0] = "vitalik"; _base[1] = "eth"; @@ -134,7 +131,7 @@ contract CCIP2ETHTest is Test { ENS.setOwner(_baseNode, address(this)); // Owner records set at level 2 only bytes memory _recordhash = hex"e50101720024080112203c5aba6c9b5055a5fa12281c486188ed8ae2b6ef394b3d981b00d17a4b51735c"; - ccip2eth.setRecordhash(_subdomains, _baseNode, _recordhash); + ccip2eth.setRecordhash(_baseNode, _recordhash); bytes[] memory _name = new bytes[](7); _name[0] = "never"; @@ -171,7 +168,6 @@ contract CCIP2ETHTest is Test { /// @dev CCIP end-to-end test with on-chain signer function test5_CCIPCallbackApprovedOnChain() public { - string[] memory _subdomains = new string[](0); bytes[] memory _name = new bytes[](2); _name[0] = "domain"; _name[1] = "eth"; @@ -185,7 +181,7 @@ contract CCIP2ETHTest is Test { ccip2eth.approve(_node, _signer, true); bytes memory _recordhash = hex"e50101720024080112203c5aba6c9b5055a5fa12281c486188ed8ae2b6ef394b3d981b00d17a4b51735c"; - ccip2eth.setRecordhash(_subdomains, _node, _recordhash); + ccip2eth.setRecordhash(_node, _recordhash); (string memory _path, string memory _domain) = utils.Format(_encoded); bytes memory _request = abi.encodePacked(iResolver.addr.selector, _node); @@ -211,13 +207,13 @@ contract CCIP2ETHTest is Test { ccip2eth.resolve(_encoded, _request); bytes memory _result = abi.encode(address(this)); string memory signRequest = string.concat( - "Requesting Signature To Update Record\n", - "\nDomain: ", + "Requesting Signature To Update ENS Record\n", + "\nOrigin: ", _domain, "\nType: address/60", "\nExtradata: 0x", gateway.bytesToHexString(abi.encodePacked(keccak256(_result)), 0), - "\nSigner: eip155:1:", + "\nSigned By: eip155:1:", gateway.toChecksumAddress(address(_signer)) ); bytes32 _digest = keccak256( @@ -236,7 +232,6 @@ contract CCIP2ETHTest is Test { /// @dev CCIP end-to-end test with off-chain signer (with fake parameters) function test6_CCIPCallbackApprovedOffChain() public { - string[] memory _subdomains = new string[](0); bytes[] memory _name = new bytes[](2); _name[0] = "domain"; _name[1] = "eth"; @@ -251,7 +246,7 @@ contract CCIP2ETHTest is Test { bytes memory _recordhash = hex"e50101720024080112203c5aba6c9b5055a5fa12281c486188ed8ae2b6ef394b3d981b00d17a4b51735c"; vm.prank(_owner); - ccip2eth.setRecordhash(_subdomains, _node, _recordhash); + ccip2eth.setRecordhash(_node, _recordhash); (string memory _path, string memory _domain) = utils.Format(_encoded); bytes memory _request = abi.encodePacked(iResolver.addr.selector, _node); @@ -275,13 +270,13 @@ contract CCIP2ETHTest is Test { ccip2eth.resolve(_encoded, _request); bytes memory _result = abi.encode(address(this)); string memory signRequest = string.concat( - "Requesting Signature To Update Record\n", - "\nDomain: ", + "Requesting Signature To Update ENS Record\n", + "\nOrigin: ", _domain, "\nType: address/60", "\nExtradata: 0x", gateway.bytesToHexString(abi.encodePacked(keccak256(_result)), 0), - "\nSigner: eip155:1:", + "\nSigned By: eip155:1:", gateway.toChecksumAddress(address(_signer)) ); bytes32 _digest = keccak256( @@ -294,11 +289,11 @@ contract CCIP2ETHTest is Test { (uint8 v, bytes32 r, bytes32 s) = vm.sign(SignerKey, _digest); bytes memory _recordSig = abi.encodePacked(r, s, v); signRequest = string.concat( - "Requesting Signature To Approve Records Signer\n", - "\nDomain: domain.eth", + "Requesting Signature To Approve Offchain ENS Records Signer\n", + "\nOrigin: domain.eth", "\nApproved Signer: eip155:1:", gateway.toChecksumAddress(_signer), - "\nOwner: eip155:1:", + "\nApproved By: eip155:1:", gateway.toChecksumAddress(_owner) ); _digest = keccak256( @@ -315,7 +310,6 @@ contract CCIP2ETHTest is Test { /// @dev CCIP end-to-end with off-chain signer and real parameters function test7_CCIPCallbackApprovedOffChain_WithRealParameters() public { - string[] memory _subdomains = new string[](0); bytes[] memory _name = new bytes[](2); _name[0] = "00081"; _name[1] = "eth"; @@ -330,7 +324,7 @@ contract CCIP2ETHTest is Test { bytes memory _recordhash = hex"e501017200240801122008dd085b86d16226791544f4628c4efc0936c69221fef17dfac843d9713233bb"; vm.prank(_owner); - ccip2eth.setRecordhash(_subdomains, _node, _recordhash); // Set recordhash + ccip2eth.setRecordhash(_node, _recordhash); // Set recordhash (string memory _path, string memory _domain) = utils.Format(_encoded); bytes memory _request = abi.encodePacked(iResolver.addr.selector, _node); @@ -354,13 +348,13 @@ contract CCIP2ETHTest is Test { ccip2eth.resolve(_encoded, _request); bytes memory _result = abi.encode(address(0x1111000000000000000000000000000000000001)); string memory signRequest = string.concat( - "Requesting Signature To Update Record\n", - "\nDomain: ", + "Requesting Signature To Update ENS Record\n", + "\nOrigin: ", _domain, "\nType: address/60", "\nExtradata: 0x", gateway.bytesToHexString(abi.encodePacked(keccak256(_result)), 0), - "\nSigner: eip155:1:", + "\nSigned By: eip155:1:", gateway.toChecksumAddress(address(_signer)) ); bytes32 _digest = keccak256( @@ -373,12 +367,12 @@ contract CCIP2ETHTest is Test { (uint8 v, bytes32 r, bytes32 s) = vm.sign(SignerKey, _digest); bytes memory _recordSig = abi.encodePacked(r, s, v); signRequest = string.concat( - "Requesting Signature To Approve Records Signer\n", - "\nDomain: ", + "Requesting Signature To Approve Offchain ENS Records Signer\n", + "\nOrigin: ", _domain, "\nApproved Signer: eip155:1:", gateway.toChecksumAddress(_signer), - "\nOwner: eip155:1:", + "\nApproved By: eip155:1:", gateway.toChecksumAddress(_owner) ); _digest = keccak256( @@ -394,8 +388,7 @@ contract CCIP2ETHTest is Test { } /// @dev Test setting deep recordhash - function test8_setDeepRecordhash() public { - string[] memory _subdomains = new string[](2); + /*function test8_setDeepRecordhash() public { _subdomains[0] = "hello"; _subdomains[1] = "world"; bytes[] memory _name = new bytes[](2); @@ -410,16 +403,16 @@ contract CCIP2ETHTest is Test { bytes memory _recordhash = hex"e501017200240801122008dd085b86d16226791544f4628c4efc0936c69221fef17dfac843d9713233bb"; vm.prank(_owner); - ccip2eth.setRecordhash(_subdomains, _node, _recordhash); // Set recordhash for 'hello.world.domain.eth' + ccip2eth.setRecordhash(_node, _recordhash); // Set recordhash for 'hello.world.domain.eth' _encoded; - } + }*/ } /// @dev Utility functions contract Utils { function Format(bytes calldata _encoded) external pure returns (string memory _path, string memory _domain) { uint256 n = 1; - uint256 len = uint8(bytes1(_encoded[:1])); + uint256 len = uint8(bytes1(_encoded[0])); bytes memory _label; _label = _encoded[1:n += len]; _path = string(_label); diff --git a/test/genABI.js b/test/genABI.js deleted file mode 100644 index dee7d1c..0000000 --- a/test/genABI.js +++ /dev/null @@ -1,6 +0,0 @@ -import * as ccip2 from "../out/CCIP2ETH.sol/CCIP2ETH.json" assert { type: "json" }; -import fs from 'fs'; -fs.writeFile('./test/ccip2abi.js', `export const ccip2abi = ${JSON.stringify(ccip2.default.abi)};`,()=>{console.log}); - -import * as gateway from "../out/GatewayManager.sol/GatewayManager.json" assert { type: "json" }; -fs.writeFile('./test/gatewayabi.js', `export const gatewayabi = ${JSON.stringify(gateway.default.abi)};`,()=>{console.log}); \ No newline at end of file diff --git a/test/t2.js b/test/t2.js deleted file mode 100644 index 25ed0da..0000000 --- a/test/t2.js +++ /dev/null @@ -1,8 +0,0 @@ -import { createTestClient, http } from 'viem' -import { foundry } from 'viem/chains' - -const client = createTestClient({ - chain: foundry, - mode: 'anvil', - transport: http(), -}) diff --git a/test/t3.js b/test/t3.js deleted file mode 100644 index 75d9e8d..0000000 --- a/test/t3.js +++ /dev/null @@ -1,220 +0,0 @@ -//import "./style.css"; -//import { -// BrowserProvider, InfuraProvider -//} from "ethers"; // add viem - -const secp256k1 = require('@noble/secp256k1'); -import * as secp256k1 from '@noble/secp256k1' -import {hkdf} from '@noble/hashes/hkdf' -import {sha256} from '@noble/hashes/sha256' -const { - hexToBytes, - bytesToHex -} = require('@noble/hashes/utils'); -const { - hkdf -} = require('@noble/hashes/hkdf'); -const { - sha256 -} = require('@noble/hashes/sha256'); - -import { - ed25519 -} from '@noble/curves/ed25519' -import { - hashToPrivateScalar -} from '@noble/curves/abstract/modular'; -//import {ed25519} from '@noble/curves/'; -import * as x3Name from 'w3name'; - -import { - gossipsub -} from '@chainsafe/libp2p-gossipsub' - -import { - kadDHT -} from '@libp2p/kad-dht' - -import { - createLibp2p -} from 'libp2p' - -import { - createHelia -} from 'helia' - -import { - ipns, - ipnsValidator, - ipnsSelector -} from '@helia/ipns' -import { - dht, - pubsub -} from '@helia/ipns/routing' -import { - unixfs -} from '@helia/unixfs' -import { - encode, - decode -} from '@ipld/dag-cbor' - -import * as DAG from '@ipld/dag-cbor' -import { - CID -} from 'multiformats' - -//import * as cbor from 'multiformats/codecs/cbor' - -let App = { - ED: false, - SIGNER: false, - ADDR: false, - LOG: document.getElementById("logbook"), - connect: async () => { - if (window.ethereum) { - let wallet = new BrowserProvider(window.ethereum) - //new ethers.providers.Web3Provider(window.ethereum); - let x = await wallet.send("eth_requestAccounts", []); - App.SIGNER = await wallet.getSigner(); - App.ADDR = x[0]; - App.LOG.innerHTML += "
Address: " + x[0] + "
"; - document.getElementById("_connect").toggleAttribute("disabled") - document.getElementById("_sign").toggleAttribute("disabled") - App.ED = ed25519 - let _contenthashRecord = { - data: "0x+" - } - let contenthash = {}; - //_ipfs.dag.put(_contenthash, { - // storeCodec: 'dag-json' - //}).then((e)=> {contenthash = e}); - - let _avatarRecord = { - "avatar.json": { - data: "0x+" - } - } - //let resolver = await wallet.getResolver("bafybeiee2lzvemjxesych64jw75cypjvce7nzvcyznbl3ogrztrmz2vnii.ipfs2.istest.eth"); - //console.log(wallet, "Resolver:", resolver) - //let content = await resolver.getContenthash(); - //console.log("IPFS", content) - - let avatar = {}; - //_ipfs.dag.put(_avatar, { - // storeCodec: 'dag-json' - //}).then((e) => { - // avatar = e - //}); - - let _record = { - ".well-known": { - eth: { - domain: { - "contenthash.json": { - contenthash - }, - avatar - } - } - } - } - let record = {}; - //_ipfs.dag.put(_record, { - // storeCodec: 'dag-json' - //}).then((e)=> {record = e}); - - const obj = { - x: 1, - /* CID instances are encoded as links */ - y: [2, 3, CID.parse('QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4')], - z: { - a: CID.parse('QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L4'), - b: null, - c: 'string' - } - } - let data = encode(obj) - let decoded = decode(data) - //decoded.y[0] // 2 - const hash = await sha256(data) - //let cid = CID.create(1, json.code, hash) - console.log("hash", bytesToHex(hash), CID.asCID(decoded.z.a).toString()) // cid instance - console.log(DAG, data, decoded) - } else { - console.log("NO MM") - } - }, - test1: async () => { - //let msg = `Generate IPNS Keys for domain.eth\n\nSigned By: eip155:1:${App.ADDR}`; - //let sig = await App.SIGNER.signMessage(msg); - //App.LOG.innerHTML += `
Signature: ${sig}
`; - let provider = new InfuraProvider("mainnet"); // mainnet - let resolver = await provider.getResolver( - "freetibet.istest.eth" - ); - console.log("Resolver:", resolver); - let content = {}; - resolver.getContentHash().then(((e) => { - console.log("IPFS", e); - content = e; - App.LOG.innerHTML += `
xIPFS: ${JSON.stringify(content)}
`; - })); - App.LOG.innerHTML += `
IPFS: ${JSON.stringify(content)}
`; - }, - w3n: async () => { - - //const myName = await Name.create() - // myName.key.bytes can now be written to disk / database, etc. - // App.LOG.innerHTML += `
IPNS: ${myName.toString()}
Key: ` + Buffer(myName.key.bytes).toString('hex') - // let's pretend some time has passed and we want to load the - let x = "080112400132f293196df88df8fd916d1ed8be07f69109cc7516aa9ab8e5bde6c7a04f5fb48b94cf6818573d58e71cfd2070920a11e5850394a1f69cbf4131e7755ee57d"; - // key from disk: - //const loadedBytes = await fs.promises.readFile('myName.key') - const myName2 = await x3Name.from(hexToBytes(x)) - App.LOG.innerHTML += `
IPNS: ${myName2.toString()}
Key: ` + Buffer(myName2.key.bytes).toString('hex') - - }, - edx: async () => { - console.log(ed25519) - let caip10 = `eip155:1:${App.ADDR}` - let domain = "domain.eth" - let password = "pass12#$" - let msg = `Requesting Signature to Generate Deterministic IPNS Keys for "${domain}"\n\nWARNING:........\n\nExtradata: 0x${bytesToHex(await sha256(domain, password, caip10))}\nSigned By: ${caip10}`; - let sig = await App.SIGNER.signMessage(msg); - let inputKey = sha256( - hexToBytes( - sig.toLowerCase().startsWith('0x') ? sig.slice(2) : sig - ) - ) - let info = `${caip10}:${domain}` - let salt = await sha256(`${info}:${password ? password : ''}:${sig.slice(-64)}`) - let hashKey = await hkdf(sha256, inputKey, salt, info, 42) - let privateKey = hashToPrivateScalar(hashKey, ed25519.CURVE.n, true).toString(16).padStart(64, "0") - App.LOG.innerHTML += `
privkey: ${privateKey} -- ${privateKey.length}` - let publicKey = bytesToHex(await ed25519.getPublicKey(privateKey)) - App.LOG.innerHTML += `
pubkey: ${publicKey} -- ${publicKey.length}` - let key = `08011240${privateKey}${publicKey}` - let w3Name = await x3Name.from(hexToBytes(key)) - App.LOG.innerHTML += `
IPNS: ${w3Name.toString()}
Key: ` + Buffer(w3Name.key.bytes).toString('hex') - //console.log(w3Name, await x3Name.resolve(w3Name)) - //let revision = await x3Name.v0(w3Name, "/ipfs/bafybeiee2lzvemjxesych64jw75cypjvce7nzvcyznbl3ogrztrmz2vnii") - let revision = await x3Name.resolve(w3Name); - let _hash = '/ipfs/bafybeiee2lzvemjxesych64jw75cypjvce7nzvcyznbl3ogrztrmz2vnii'; - if (revision.value && revision.value != _hash) { - revision = await x3Name.increment(revision, _hash); - let k = await x3Name.publish(revision, w3Name.key); - console.log("published", _hash, k) - } else { - //revision = await x3Name.v0(w3Name, _hash) - //await x3Name.publish(revision, w3Name.key); - } - console.log(revision) - //return [Stringify(privateKey), ed25519.utils.bytesToHex(publicKey)] - } -} - -window.App = App - -// 080112409b9da2926c90c2b592d129c74a7a1a91d84a0448a53cb89fc890ea5a00698154ffa142ada9a422283e65bcbd04a3f8f0432a8be799b3afc751ddd874d931bae6 \ No newline at end of file