Skip to content

Commit

Permalink
Merge branch 'staging' into feature/better-offchain-dns
Browse files Browse the repository at this point in the history
  • Loading branch information
mdtanrikulu committed Apr 25, 2024
2 parents b479cd2 + c15e4af commit d3d6b70
Show file tree
Hide file tree
Showing 20 changed files with 804 additions and 130 deletions.
17 changes: 16 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,25 @@ name: CI

on:
push:
branches: [master]
branches: [staging, mainnet]
pull_request:

jobs:
wiki_address_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Use Node.js 16
uses: actions/setup-node@v3
with:
node-version: 16
cache: 'yarn'

- run: yarn install --frozen-lockfile

- name: Run wikiCheck
run: yarn wikiCheck
test:
runs-on: ubuntu-latest
steps:
Expand Down
1 change: 1 addition & 0 deletions contracts/dnssec-oracle/RRUtils.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "../utils/BytesUtils.sol";
Expand Down
4 changes: 0 additions & 4 deletions contracts/ethregistrar/ETHRegistrarController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ error CommitmentTooOld(bytes32 commitment);
error NameNotAvailable(string name);
error DurationTooShort(uint256 duration);
error ResolverRequiredWhenDataSupplied();
error ResolverRequiredWhenReverseRecord();
error UnexpiredCommitmentExists(bytes32 commitment);
error InsufficientValue();
error Unauthorised(bytes32 node);
Expand Down Expand Up @@ -121,9 +120,6 @@ contract ETHRegistrarController is
uint16 ownerControlledFuses
) public pure override returns (bytes32) {
bytes32 label = keccak256(bytes(name));
if (resolver == address(0) && reverseRecord == true) {
revert ResolverRequiredWhenReverseRecord();
}
if (data.length > 0 && resolver == address(0)) {
revert ResolverRequiredWhenDataSupplied();
}
Expand Down
1 change: 1 addition & 0 deletions contracts/registry/ENS.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;

interface ENS {
Expand Down
1 change: 1 addition & 0 deletions contracts/resolvers/OwnedResolver.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import "./profiles/ABIResolver.sol";
Expand Down
1 change: 1 addition & 0 deletions contracts/utils/BytesUtils.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

library BytesUtils {
Expand Down
6 changes: 2 additions & 4 deletions contracts/utils/UniversalResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -320,9 +320,7 @@ contract UniversalResolver is ERC165, Ownable {

Result memory result = results[0];

if (!result.success) {
revert ResolverError(result.returnData);
}
_checkResolveSingle(result);

if (metaData.length > 0) {
(string memory resolvedName, address reverseResolverAddress) = abi
Expand Down Expand Up @@ -658,7 +656,7 @@ contract UniversalResolver is ERC165, Ownable {
returnData = abi.decode(returnData, (bytes));
}
results[i] = Result(success, returnData);
extraDatas[i].data = multicallData.data[i];
extraDatas[i].data = item;
}

if (offchainCount == 0) {
Expand Down
10 changes: 6 additions & 4 deletions deploy/utils/00_deploy_universal_resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
log: true,
})

const UR = await ethers.getContract('UniversalResolver')
const tx = await UR.transferOwnership(owner)
console.log(`Transfer ownership to ${owner} (tx: ${tx.hash})...`)
await tx.wait()
if (owner !== undefined && owner !== deployer) {
const UR = await ethers.getContract('UniversalResolver')
const tx = await UR.transferOwnership(owner)
console.log(`Transfer ownership to ${owner} (tx: ${tx.hash})...`)
await tx.wait()
}
}

func.id = 'universal-resolver'
Expand Down
46 changes: 23 additions & 23 deletions deployments/goerli/UniversalResolver.json

Large diffs are not rendered by default.

101 changes: 101 additions & 0 deletions deployments/goerli/solcInputs/49f758ec505ff69b72f3179ac11d7cfc.json

Large diffs are not rendered by default.

58 changes: 29 additions & 29 deletions deployments/holesky/UniversalResolver.json

Large diffs are not rendered by default.

101 changes: 101 additions & 0 deletions deployments/holesky/solcInputs/49f758ec505ff69b72f3179ac11d7cfc.json

Large diffs are not rendered by default.

54 changes: 27 additions & 27 deletions deployments/mainnet/UniversalResolver.json

Large diffs are not rendered by default.

101 changes: 101 additions & 0 deletions deployments/mainnet/solcInputs/49f758ec505ff69b72f3179ac11d7cfc.json

Large diffs are not rendered by default.

54 changes: 27 additions & 27 deletions deployments/sepolia/UniversalResolver.json

Large diffs are not rendered by default.

101 changes: 101 additions & 0 deletions deployments/sepolia/solcInputs/49f758ec505ff69b72f3179ac11d7cfc.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"format": "prettier --write .",
"prepublishOnly": "yarn build",
"pub": "yarn publish --access public",
"prepare": "husky install"
"prepare": "husky install",
"wikiCheck": "node wikiCheck.js "
},
"files": [
"build",
Expand Down
135 changes: 127 additions & 8 deletions test/utils/TestUniversalResolver.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { solidity } = require('ethereum-waffle')
const { use, expect } = require('chai')
const namehash = require('eth-ens-namehash')
const { hexDataSlice } = require('ethers/lib/utils')
const { hexDataSlice, concat } = require('ethers/lib/utils')
const sha3 = require('web3-utils').sha3
const { Contract } = require('ethers')
const { ethers } = require('hardhat')
Expand Down Expand Up @@ -194,6 +194,12 @@ contract('UniversalResolver', function (accounts) {
4,
)

const resolveSig = ethers.utils.hexDataSlice(
ethers.utils.id('resolve(bytes,bytes)'),
0,
4,
)

describe('findResolver()', () => {
it('should find an exact match resolver', async () => {
const result = await universalResolver.findResolver(
Expand Down Expand Up @@ -451,6 +457,63 @@ contract('UniversalResolver', function (accounts) {
}
})

it('should return a wrapped revert with resolve() wrapped calls in extraData when combining onchain and offchain lookups', async () => {
const addrData = publicResolver.interface.encodeFunctionData(
'addr(bytes32)',
[namehash.hash('offchain.test.eth')],
)
const onchainDataCall = '0x12345678'

try {
await universalResolver['resolve(bytes,bytes[])'](
dns.hexEncodeName('offchain.test.eth'),
[addrData, onchainDataCall],
)
expect(false).to.be.true
} catch (e) {
expect(e.errorName).to.equal('OffchainLookup')
expect(e.errorArgs.sender).to.equal(universalResolver.address)
expect(e.errorArgs.urls).to.deep.equal([
'http://universal-offchain-resolver.local/',
])
const decodedCallData = batchGateway.decodeFunctionData(
'query',
e.errorArgs.callData,
)
expect(decodedCallData).to.deep.equal([
[[dummyOffchainResolver.address, ['https://example.com/'], addrData]],
])
expect(e.errorArgs.callbackFunction).to.equal(
ethers.utils.hexDataSlice(
ethers.utils.id('resolveCallback(bytes,bytes)'),
0,
4,
),
)
const decodedExtraData = ethers.utils.defaultAbiCoder.decode(
['bool', 'address', 'string[]', 'bytes', '(bytes4,bytes)[]'],
e.errorArgs.extraData,
)
expect(decodedExtraData).to.deep.equal([
false,
dummyOffchainResolver.address,
['http://universal-offchain-resolver.local/'],
'0x',
[
[resolveCallbackSig, addrData],
[
'0x00000000',
// just using the UR interface for ensip10
universalResolver.interface.encodeFunctionData(
'resolve(bytes,bytes)',
[dns.hexEncodeName('offchain.test.eth'), onchainDataCall],
),
],
],
])
}
})

describe('batch', () => {
it('should resolve multiple records onchain', async () => {
const textData = publicResolver.interface.encodeFunctionData(
Expand Down Expand Up @@ -515,7 +578,24 @@ contract('UniversalResolver', function (accounts) {
expect(false).to.be.true
} catch (e) {
expect(e.errorName).to.equal('OffchainLookup')
expect(e.errorArgs.callData).to.equal(callData)
const decodedCallData = batchGateway.decodeFunctionData(
'query',
e.errorArgs.callData,
)
expect(decodedCallData).to.deep.equal([
[
[
dummyOffchainResolver.address,
['https://example.com/'],
textData,
],
[
dummyOffchainResolver.address,
['https://example.com/'],
addrData,
],
],
])
expect(e.errorArgs.callbackFunction).to.equal(resolveCallbackSig)
expect(e.errorArgs.extraData).to.equal(extraData)
}
Expand Down Expand Up @@ -661,9 +741,9 @@ contract('UniversalResolver', function (accounts) {
expect(encodedRes.returnData).to.equal('0x')
})
it('should allow response at non-0 extraData index', async () => {
const addrData = publicResolver.interface.encodeFunctionData(
'addr(bytes32)',
[namehash.hash('offchain.test.eth')],
const onchainCall = universalResolver.interface.encodeFunctionData(
'resolve(bytes,bytes)',
[dns.hexEncodeName('offchain.test.eth'), '0x12345678'],
)
const textData = publicResolver.interface.encodeFunctionData(
'text(bytes32,string)',
Expand All @@ -677,7 +757,7 @@ contract('UniversalResolver', function (accounts) {
['http://universal-offchain-resolver.local/'],
'0x',
[
['0x00000000', addrData],
['0x00000000', onchainCall],
[resolveCallbackSig, textData],
],
],
Expand All @@ -690,15 +770,15 @@ contract('UniversalResolver', function (accounts) {
await universalResolver.callStatic.resolveCallback(responses, extraData)
expect(encodedRes.success).to.equal(true)
expect(encodedResTwo.success).to.equal(true)
const [addrRet] = ethers.utils.defaultAbiCoder.decode(
const [fooString] = ethers.utils.defaultAbiCoder.decode(
['bytes'],
encodedRes.returnData,
)
const [addrRetTwo] = publicResolver.interface.decodeFunctionResult(
'addr(bytes32)',
encodedResTwo.returnData,
)
expect(ethers.utils.toUtf8String(addrRet)).to.equal('onchain')
expect(ethers.utils.toUtf8String(fooString)).to.equal('foo')
expect(addrRetTwo).to.equal(dummyOffchainResolver.address)
expect(resolverAddress).to.equal(dummyOffchainResolver.address)
})
Expand Down Expand Up @@ -801,6 +881,45 @@ contract('UniversalResolver', function (accounts) {
expect(a2).to.equal(dummyOffchainResolver.address)
expect(a3).to.equal(dummyOffchainResolver.address)
})
it('should propagate HttpError', async () => {
const urWithHttpErrorAbi = new ethers.Contract(
universalResolver.address,
[
...universalResolver.interface.fragments,
'error HttpError((uint16,string)[])',
],
ethers.provider,
)
const errorData = urWithHttpErrorAbi.interface.encodeErrorResult(
'HttpError',
[[[404, 'Not Found']]],
)
const extraData = ethers.utils.defaultAbiCoder.encode(
['bool', 'address', 'string[]', 'bytes', '(bytes4,bytes)[]'],
[
false,
dummyOffchainResolver.address,
['http://universal-offchain-resolver.local/'],
'0x',
[[resolveCallbackSig, errorData]],
],
)
const responses = batchGateway.encodeFunctionResult('query', [
[true],
[errorData],
])

try {
await urWithHttpErrorAbi.callStatic.reverseCallback(
responses,
extraData,
)
expect(false).to.be.true
} catch (e) {
expect(e.errorName).to.equal('HttpError')
expect(e.errorArgs).to.deep.equal([[[404, 'Not Found']]])
}
})
})

describe('reverse()', () => {
Expand Down
9 changes: 7 additions & 2 deletions test/utils/mocks/DummyOffchainResolver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "../../../contracts/resolvers/profiles/ITextResolver.sol";
import "../../../contracts/resolvers/profiles/IExtendedResolver.sol";

error OffchainLookup(
Expand All @@ -27,6 +28,10 @@ contract DummyOffchainResolver is IExtendedResolver, ERC165 {
) external view returns (bytes memory) {
string[] memory urls = new string[](1);
urls[0] = "https://example.com/";

if (bytes4(data) == bytes4(0x12345678)) {
return abi.encode("foo");
}
revert OffchainLookup(
address(this),
urls,
Expand All @@ -36,8 +41,8 @@ contract DummyOffchainResolver is IExtendedResolver, ERC165 {
);
}

function addr(bytes32) external pure returns (bytes memory) {
return abi.encode("onchain");
function addr(bytes32) external pure returns (address) {
return 0x69420f05A11f617B4B74fFe2E04B2D300dFA556F;
}

function resolveCallback(
Expand Down
Loading

0 comments on commit d3d6b70

Please sign in to comment.