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

support web2 & web3 gateways #49

Merged
merged 2 commits into from
Aug 18, 2023
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
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:

- name: Run Forge tests
run: |
forge test --fork-url https://rpc.ankr.com/eth_goerli -vvvv --fork-block-number 8897000
forge test --fork-url https://rpc.ankr.com/eth_goerli -vvvv --fork-block-number 8897777
id: test

- name: Initialise status badge
Expand Down
31 changes: 14 additions & 17 deletions src/CCIP2ETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ contract CCIP2ETH is iCCIP2ETH {
/// @dev - Constructor
constructor(address _gateway) {
gateway = iGatewayManager(_gateway);
chainID = gateway.uintToString(block.chainid);
chainID = block.chainid == 1 ? "1" : "5"; // mainnet or goerli
/// @dev - Sets ENS Mainnet wrapper as Wrapper
isWrapper[0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401] = true;
emit UpdatedWrapper(0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401, true);
Expand All @@ -82,14 +82,6 @@ contract CCIP2ETH is iCCIP2ETH {
supportsInterface[iCallbackType.signedRedirect.selector] = true;
}

/// Note - Checks for admin privileges
modifier OnlyDev() {
if (msg.sender != gateway.owner()) {
revert NotAuthorised("NOT_DEV");
}
_;
}

/**
* @dev Gets recordhash for a node
* @param _node - Namehash of domain.eth, or bytes32(address _Owner)
Expand Down Expand Up @@ -268,9 +260,6 @@ contract CCIP2ETH is iCCIP2ETH {
}
if (_recordhash.length == 0) {
_recordhash = recordhash[bytes32(uint256(uint160(_owner)))];
if (_recordhash.length == 0) {
_recordhash = abi.encodePacked("https://ccip.namesys.xyz"); // Web2 fallback
}
}
string memory _recType = gateway.funcToJson(request); // Filename for the requested record
bytes32 _checkhash =
Expand Down Expand Up @@ -312,14 +301,14 @@ contract CCIP2ETH is iCCIP2ETH {
string memory _domain, // String-formatted complete 'a.b.c.domain.eth'
string memory _recType, // Record type
, // Complete reverse-DNS path for __fallback()
, // DNS-encoded domain.eth
, // DNS-encoded full domain.eth
bytes memory _request // Format: <bytes4> + <namehash> + <extradata>
) = abi.decode(extradata, (bytes32, uint256, bytes32, string, string, string, bytes, bytes));
address _owner = ENS.owner(_node);
if (isWrapper[_owner]) {
_owner = iToken(_owner).ownerOf(uint256(_node));
}
/// @dev - Timeout in 4 blocks (must be < 256 blocks)
/// @dev - Timeout in 4 blocks
if (block.number > _blocknumber + 5) {
revert InvalidRequest("BLOCK_TIMEOUT");
}
Expand Down Expand Up @@ -382,7 +371,7 @@ contract CCIP2ETH is iCCIP2ETH {
"Requesting Signature To Install dApp Service\n",
"\nOrigin: ",
_domain, // e.g. ens.domain.eth
"\ndApp: ",
"\nDApp: ",
_redirectDomain, // e.g. app.ens.eth
"\nExtradata: 0x",
gateway.bytesToHexString(abi.encodePacked(keccak256(result)), 0),
Expand Down Expand Up @@ -568,21 +557,29 @@ contract CCIP2ETH is iCCIP2ETH {

/// @dev : Management functions

/// @dev : Checks for admin privileges
modifier OnlyDev() {
if (msg.sender != gateway.owner()) {
revert NotAuthorised("NOT_DEV");
}
_;
}

/// @dev - Returns owner of the contract
function owner() public view returns (address) {
return gateway.owner();
}
/// @dev - Updates ChainID in case of a hardfork

/// @dev - Updates ChainID in case of a hardfork
function updateChainID() public {
chainID = gateway.uintToString(block.chainid);
}

/**
* @dev Sets fees for ownerhash
* Note - Set to 0 at launch
* @param _wei - Fees in WEI per EOA
*/

function updateOwnerhashFees(uint256 _wei) external OnlyDev {
ownerhashFees = _wei;
}
Expand Down
134 changes: 95 additions & 39 deletions src/GatewayManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ import "./Interface.sol";
*/
contract GatewayManager is iERC173, iGatewayManager {
/// @dev - Events
event AddGateway(string indexed domain);
event RemoveGateway(string indexed domain);
event UpdateFuncFile(bytes4 _func, string _name);

event Web3GatewayUpdated(string indexed domain);
event Web3GatewayRemoved(string indexed domain);
event FuncMapUpdated(bytes4 _func, string _name);
event Web2GatewayUpdated(string indexed domain);
event Web2GatewayRemoved(string indexed domain);
/// @dev - Errors

error ContenthashNotImplemented(bytes1 _type);
error InvalidRequest(string _message);
error UnimplementedFeature(bytes4 func);
error FeatureNotImplemented(bytes4 func);

/// @dev - Contract owner/multisig address
address public owner;
Expand All @@ -33,8 +35,11 @@ contract GatewayManager is iERC173, iGatewayManager {
address immutable THIS = address(this);
/// @dev - Primary IPFS gateway domain, ipfs2.eth.limo
string public PrimaryGateway = "ipfs2.eth.limo";
/// @dev - List of secondary gateway domains
string[] public Gateways;
/// @dev - List of secondary gateway domains (default)
string[] public Web3Gateways;
/// @dev - List of web2/L2 service gateway domains (fallback)
string[] public Web2Gateways;

/// @dev - Resolver function bytes4 selector → Off-chain record filename <name>.json
mapping(bytes4 => string) public funcMap;

Expand All @@ -49,10 +54,13 @@ contract GatewayManager is iERC173, iGatewayManager {
funcMap[iResolver.contenthash.selector] = "contenthash";
funcMap[iResolver.zonehash.selector] = "dns/zonehash";
/// @dev - Set initial list of secondary gateways
Gateways.push("dweb.link");
emit AddGateway("dweb.link");
Gateways.push("ipfs.io");
emit AddGateway("ipfs.io");
Web3Gateways.push("dweb.link");
emit Web3GatewayUpdated("dweb.link");
Web3Gateways.push("ipfs.io");
emit Web3GatewayUpdated("ipfs.io");

Web2Gateways.push("ccip.namesys.xyz");
emit Web2GatewayUpdated("ccip.namesys.xyz");
}

/**
Expand All @@ -69,20 +77,29 @@ contract GatewayManager is iERC173, iGatewayManager {
returns (string[] memory gateways)
{
/// @dev Filter recordhash vs. web2 gateway
if (_recordhash.length == 32) {
// Short IPNS hash
_recordhash = abi.encodePacked(hex"e5010172002408011220", _recordhash);
} else if (iGatewayManager(this).isWeb2(_recordhash)) {
// Web2 fallback
if (_recordhash.length == 0) {
// Default L2/Web2 service fallback
uint256 gateLen = Web2Gateways.length;
gateways = new string[](gateLen);
while (gateLen > 0) {
--gateLen;
gateways[gateLen] = string.concat(string("https://"), Web2Gateways[gateLen], _path, ".json?t={data}");
}
return gateways;
} else if (_recordhash[0] == bytes1("h") && iGatewayManager(this).isWeb2(_recordhash)) {
// Web2 set by owner
gateways = new string[](1);
gateways[0] = string.concat(string(_recordhash), _path, ".json?t={data}");
return gateways;
} else if (_recordhash.length == 32) {
// Short IPNS hash
_recordhash = abi.encodePacked(hex"e5010172002408011220", _recordhash);
}
unchecked {
uint256 gLen = Gateways.length;
uint256 gLen = Web3Gateways.length;
uint256 len = (gLen / 2) + 2;
if (len > 4) len = 4;
gateways = new string[](len);
if (len > 3) len = 3;
gateways = new string[](len+1);
uint256 i;
if (bytes(PrimaryGateway).length > 0) {
gateways[i++] = string.concat(
Expand Down Expand Up @@ -116,8 +133,9 @@ contract GatewayManager is iERC173, iGatewayManager {
}
while (i < len) {
seed = uint256(keccak256(abi.encodePacked(block.number * i, seed)));
gateways[i++] = string.concat("https://", Gateways[seed % gLen], _fullPath);
gateways[i++] = string.concat("https://", Web3Gateways[seed % gLen], _fullPath);
}
gateways[len] = string.concat("https://", Web2Gateways[0], _fullPath); // fallback,
}
}

Expand All @@ -128,7 +146,7 @@ contract GatewayManager is iERC173, iGatewayManager {
this;
response;
extradata;
revert UnimplementedFeature(iGatewayManager.__fallback.selector);
revert FeatureNotImplemented(iGatewayManager.__fallback.selector);
}

/**
Expand Down Expand Up @@ -170,7 +188,7 @@ contract GatewayManager is iERC173, iGatewayManager {
}
_jsonPath = string.concat("dns/", uintToString(resource));
} else {
revert UnimplementedFeature(func);
revert FeatureNotImplemented(func);
}
}

Expand Down Expand Up @@ -281,46 +299,84 @@ contract GatewayManager is iERC173, iGatewayManager {
*/
function addFuncMap(bytes4 _func, string calldata _name) external onlyDev {
funcMap[_func] = _name;
emit UpdateFuncFile(_func, _name);
emit FuncMapUpdated(_func, _name);
}

/**
* @dev Shows list of all available gateways
* @return list - List of gateways
* @dev Shows list of web3 gateways
* @return List of gateways
*/
function listGateways() external view returns (string[] memory list) {
return Gateways;
function listWeb3Gateways() external view returns (string[] memory) {
return Web3Gateways;
}

/**
* @dev Add a single gateway
* @param _domain - New gateway domain to add
*/
function addGateway(string calldata _domain) external onlyDev {
Gateways.push(_domain);
emit AddGateway(_domain);
function addWeb3Gateway(string calldata _domain) external onlyDev {
Web3Gateways.push(_domain);
emit Web3GatewayUpdated(_domain);
}

/**
* @dev Remove a single gateway
* @param _index - Gateway index to remove
*/
function removeWeb3Gateway(uint256 _index) external onlyDev {
require(Web3Gateways.length > 1, "Last Gateway");
emit Web3GatewayRemoved(Web3Gateways[_index]);
Web3Gateways[_index] = Web3Gateways[Web3Gateways.length - 1];
Web3Gateways.pop();
}

/**
* @dev Replace a single gateway
* @param _index : Gateway index to replace
* @param _domain : New gateway domain.tld
*/
function replaceWeb3Gateway(uint256 _index, string calldata _domain) external onlyDev {
emit Web3GatewayRemoved(Web3Gateways[_index]);
Web3Gateways[_index] = _domain;
emit Web3GatewayUpdated(_domain);
}

/**
* @dev Shows list of web2 gateways
* @return List of gateways
*/
function listWeb2Gateways() external view returns (string[] memory) {
return Web2Gateways;
}

/**
* @dev Add a single gateway
* @param _domain - New gateway domain to add
*/
function addWeb2Gateway(string calldata _domain) external onlyDev {
Web2Gateways.push(_domain);
emit Web2GatewayUpdated(_domain);
}
/**
* @dev Remove a single gateway
* @param _index - Gateway index to remove
*/
function removeGateway(uint256 _index) external onlyDev {
require(Gateways.length > 1, "Last Gateway");
emit RemoveGateway(Gateways[_index]);
Gateways[_index] = Gateways[Gateways.length - 1];
Gateways.pop();
function removeWeb2Gateway(uint256 _index) external onlyDev {
require(Web2Gateways.length > 1, "Last Gateway");
emit Web2GatewayRemoved(Web2Gateways[_index]);
Web2Gateways[_index] = Web2Gateways[Web2Gateways.length - 1];
Web2Gateways.pop();
}

/**
* @dev Replace a single gateway
* @param _index : Gateway index to replace
* @param _domain : New gateway domain.tld
*/
function replaceGateway(uint256 _index, string calldata _domain) external onlyDev {
emit RemoveGateway(Gateways[_index]);
Gateways[_index] = _domain;
emit AddGateway(_domain);
function replaceWeb2Gateway(uint256 _index, string calldata _domain) external onlyDev {
emit Web2GatewayRemoved(Web2Gateways[_index]);
Web2Gateways[_index] = _domain;
emit Web2GatewayUpdated(_domain);
}

/**
Expand Down
14 changes: 10 additions & 4 deletions src/Interface.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,24 @@ interface iGatewayManager is iERC173 {
function bytesToHexString(bytes calldata _buffer, uint256 _start) external pure returns (string memory);
function bytes32ToHexString(bytes32 _buffer) external pure returns (string memory);
function funcToJson(bytes calldata _request) external view returns (string memory _jsonPath);
function listGateways() external view returns (string[] memory list);
function toChecksumAddress(address _addr) external pure returns (string memory);
function __fallback(bytes calldata response, bytes calldata extradata)
external
view
returns (bytes memory result);
function addFuncMap(bytes4 _func, string calldata _name) external;
function addGateway(string calldata _domain) external;
function removeGateway(uint256 _index) external;
function replaceGateway(uint256 _index, string calldata _domain) external;
function formatSubdomain(bytes calldata _recordhash) external pure returns (string memory result);
function isWeb2(bytes calldata _recordhash) external pure returns (bool);

function listWeb2Gateways() external view returns (string[] memory list);
function addWeb2Gateway(string calldata _domain) external;
function removeWeb2Gateway(uint256 _index) external;
function replaceWeb2Gateway(uint256 _index, string calldata _domain) external;

function listWeb3Gateways() external view returns (string[] memory list);
function addWeb3Gateway(string calldata _domain) external;
function removeWeb3Gateway(uint256 _index) external;
function replaceWeb3Gateway(uint256 _index, string calldata _domain) external;
}

interface iResolver {
Expand Down
Loading