From d9b07acaacc785479e3fee781f1b7df1cfa6b8d5 Mon Sep 17 00:00:00 2001 From: Benjamin Bollen Date: Tue, 30 Apr 2024 15:00:39 +0100 Subject: [PATCH] (test/names): cutting short effort to handle decoding base58 in tests --- ...nsfer => TCIP010-erc1155-path-transfer.md} | 0 test/names/Base58Helper.sol | 82 +++++++++++++++++++ test/names/MockNameRegistry.sol | 36 ++++++++ test/names/NameRegistry.t.sol | 44 +++++++++- 4 files changed, 160 insertions(+), 2 deletions(-) rename specifications/{TCIP010-erc1155-path-transfer => TCIP010-erc1155-path-transfer.md} (100%) create mode 100644 test/names/Base58Helper.sol diff --git a/specifications/TCIP010-erc1155-path-transfer b/specifications/TCIP010-erc1155-path-transfer.md similarity index 100% rename from specifications/TCIP010-erc1155-path-transfer rename to specifications/TCIP010-erc1155-path-transfer.md diff --git a/test/names/Base58Helper.sol b/test/names/Base58Helper.sol new file mode 100644 index 0000000..f247e20 --- /dev/null +++ b/test/names/Base58Helper.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.24; + +import "forge-std/console.sol"; + +/** + * Helper contract to do the base58 decoding in solidity unit tests; + * this should only be used for tests, in production this conversion to bytes + * should be done off-chain with a proper library. + */ +contract Base58Decode { + + function base58Decode(string memory source) public view returns (bytes memory) { + bytes memory bSource = bytes(source); + uint256 base = 58; + uint256 result = 0; + uint256 multi = 1; + + // Mapping of base58 characters to their integer values + uint8[58] memory base58Map = [ + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A + ]; + + // Adjust to ignore the "Qm" prefix if it exists and length is 34 bytes + uint256 startIndex = 0; + if (bSource.length == 46 && bSource[0] == 0x51 && bSource[1] == 0x6D) { // 'Q' == 0x51 and 'm' == 0x6D + startIndex = 2; + } else if (bSource.length != 44) { + revert("Invalid CIDv0 length for IPFS decoding."); + } + + console.log("startIndex:", startIndex); + console.log("CIDv0 inside length:", bSource.length); + + // for (uint256 i = startIndex; i < bSource.length; i++) { + // uint256 value = indexOf(uint8(bSource[i]), base58Map); + // result += value * multi; + // if (i ) + // multi *= base; + // console.log("index:", i - startIndex + 1); + // console.log("charater:", uint8(bSource[i]), "value:", value); + // console.log("result:", result, "multi:", multi); + // } + + uint256 j = 0; + for (uint256 i = bSource.length; i > startIndex; i--) { + uint256 value = indexOf(uint8(bSource[i - 1]), base58Map); + result += value * multi; + if (i > startIndex + 1) { + // skip the last iteration to avoid overflow + // 58^44 > 2^256 - 1 + multi *= base; + console.log("iteration:", j++); + } else { + console.log("last iteration"); + } + console.log("index:", bSource.length - i + 1); + console.log("charater:", uint8(bSource[i - 1]), "value:", value); + console.log("result:", result, "multi:", multi); + } + + return toBytes(result); + } + + function indexOf(uint8 char, uint8[58] memory map) private pure returns (uint256) { + for(uint i = 0; i < map.length; i++) { + if(map[i] == char) { + return i; + } + } + revert("Character not in base58 map."); + } + + function toBytes(uint256 x) private pure returns (bytes memory b) { + b = new bytes(32); + assembly { + mstore(add(b, 32), x) + } + } +} diff --git a/test/names/MockNameRegistry.sol b/test/names/MockNameRegistry.sol index dd331d6..7c53eda 100644 --- a/test/names/MockNameRegistry.sol +++ b/test/names/MockNameRegistry.sol @@ -5,4 +5,40 @@ import "../../src/names/NameRegistry.sol"; contract MockNameRegistry is NameRegistry { constructor() NameRegistry(IHubV2(address(1))) {} + + // External functions + + function registerShortNameNoChecks() external { + _registerShortName(); + } + + function registerShortNameWithNonceNoChecks(uint256 _nonce) external { + _registerShortNameWithNonce(_nonce); + } + + function registerCustomNameNoChecks(address _avatar, string calldata _name) external { + if (bytes(_name).length == 0) { + // if name is left empty, it will default to default name "Circles-" + return; + } + if (!isValidName(_name)) { + revert CirclesNamesInvalidName(_avatar, _name, 0); + } + customNames[_avatar] = _name; + } + + function registerCustomSymbolNoChecks(address _avatar, string calldata _symbol) external { + if (bytes(_symbol).length == 0) { + // if symbol is left empty, it will default to default symbol "CRC" + return; + } + if (!isValidSymbol(_symbol)) { + revert CirclesNamesInvalidName(_avatar, _symbol, 1); + } + customSymbols[_avatar] = _symbol; + } + + function setCidV0DigestNoChecks(address _avatar, bytes32 _dicV0Digest) external { + _setCidV0Digest(_avatar, _dicV0Digest); + } } diff --git a/test/names/NameRegistry.t.sol b/test/names/NameRegistry.t.sol index 5a07455..0847bdd 100644 --- a/test/names/NameRegistry.t.sol +++ b/test/names/NameRegistry.t.sol @@ -4,8 +4,48 @@ pragma solidity >=0.8.24; import {Test} from "forge-std/Test.sol"; import {StdCheats} from "forge-std/StdCheats.sol"; import "forge-std/console.sol"; +import "../setup/HumanRegistration.sol"; import "./MockNameRegistry.sol"; +import "./base58Helper.sol"; -contract NamesTest is Test { - function setUp() public {} +contract NamesTest is Test, HumanRegistration, Base58Decode { + // Constants + + // IPFS hash for Ubuntu 20.04, random CIDv0 + string constant IPFS_CID_V0 = "QmPK1s3pNYLi9ERiq3BDxKa4XosgWwFRQUydHUtz4YgpqB"; + // using https://cid.ipfs.tech/#QmPK1s3pNYLi9ERiq3BDxKa4XosgWwFRQUydHUtz4YgpqB + // this is the 32 bytes hash digest + bytes32 constant DECODED_UINT = 0x0E7071C59DF3B9454D1D18A15270AA36D54F89606A576DC621757AFD44AD1D2E; + + // State variables + + MockNameRegistry mockNameRegistry; + + bytes32 cidBytes; + + // Constructor + + constructor() HumanRegistration(4) {} + + // Setup + + function setUp() public { + mockNameRegistry = new MockNameRegistry(); + // Convert CIDv0 to bytes32 (should be done off-chain in production) + console.log("CIDv0 length", bytes(IPFS_CID_V0).length); + cidBytes = convertCidV0ToBytes32(IPFS_CID_V0); + } + + // Tests + + function testCidV0Digest() public { + mockNameRegistry.setCidV0DigestNoChecks(addresses[0], cidBytes); + } + + // Helper functions + + function convertCidV0ToBytes32(string memory _cidV0) internal view returns (bytes32) { + bytes memory decodedBytes = base58Decode(_cidV0); + console.log("CIDv0 length:", decodedBytes.length); + } }