diff --git a/contracts/dapp/Application.sol b/contracts/dapp/Application.sol index 04fb4fb1..cb93cc6a 100644 --- a/contracts/dapp/Application.sol +++ b/contracts/dapp/Application.sol @@ -15,6 +15,7 @@ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import {BitMaps} from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; @@ -33,6 +34,10 @@ contract Application is /// @dev See the `getTemplateHash` function. bytes32 internal immutable _templateHash; + /// @notice The data availability solution. + /// @dev See the `getDataAvailability` function. + IERC165 internal immutable _dataAvailability; + /// @notice Keeps track of which outputs have been executed. /// @dev See the `wasOutputExecuted` function. BitMaps.BitMap internal _executed; @@ -41,10 +46,6 @@ contract Application is /// @dev See the `getConsensus` and `migrateToConsensus` functions. IConsensus internal _consensus; - /// @notice The data availability solution. - /// @dev See the `getDataAvailability` function. - bytes internal _dataAvailability; - /// @notice Creates an `Application` contract. /// @param consensus The initial consensus contract /// @param initialOwner The initial application owner @@ -54,11 +55,11 @@ contract Application is IConsensus consensus, address initialOwner, bytes32 templateHash, - bytes memory dataAvailability + IERC165 dataAvailability ) Ownable(initialOwner) { _templateHash = templateHash; - _consensus = consensus; _dataAvailability = dataAvailability; + _consensus = consensus; } /// @notice Accept Ether transfers. @@ -146,7 +147,7 @@ contract Application is external view override - returns (bytes memory) + returns (IERC165) { return _dataAvailability; } diff --git a/contracts/dapp/ApplicationFactory.sol b/contracts/dapp/ApplicationFactory.sol index a4740fb9..b79343de 100644 --- a/contracts/dapp/ApplicationFactory.sol +++ b/contracts/dapp/ApplicationFactory.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.8; import {Create2} from "@openzeppelin/contracts/utils/Create2.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {IApplicationFactory} from "./IApplicationFactory.sol"; import {IConsensus} from "../consensus/IConsensus.sol"; @@ -17,7 +18,7 @@ contract ApplicationFactory is IApplicationFactory { IConsensus consensus, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability + IERC165 dataAvailability ) external override returns (IApplication) { IApplication appContract = new Application( consensus, @@ -41,7 +42,7 @@ contract ApplicationFactory is IApplicationFactory { IConsensus consensus, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) external override returns (IApplication) { IApplication appContract = new Application{salt: salt}( @@ -66,7 +67,7 @@ contract ApplicationFactory is IApplicationFactory { IConsensus consensus, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) external view override returns (address) { return diff --git a/contracts/dapp/IApplication.sol b/contracts/dapp/IApplication.sol index b1a2ea7c..23a28efe 100644 --- a/contracts/dapp/IApplication.sol +++ b/contracts/dapp/IApplication.sol @@ -3,6 +3,8 @@ pragma solidity ^0.8.8; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + import {IOwnable} from "../access/IOwnable.sol"; import {IConsensus} from "../consensus/IConsensus.sol"; import {OutputValidityProof} from "../common/OutputValidityProof.sol"; @@ -117,7 +119,6 @@ interface IApplication is IOwnable { function getConsensus() external view returns (IConsensus); /// @notice Get the data availability solution used by application. - /// @return Solidity ABI-encoded function call that describes - /// the source of inputs that should be fed to the application. - function getDataAvailability() external view returns (bytes memory); + /// @return ERC-165 contract that describes the data availability solution + function getDataAvailability() external view returns (IERC165); } diff --git a/contracts/dapp/IApplicationFactory.sol b/contracts/dapp/IApplicationFactory.sol index 5dff1520..9edbc2cd 100644 --- a/contracts/dapp/IApplicationFactory.sol +++ b/contracts/dapp/IApplicationFactory.sol @@ -3,6 +3,8 @@ pragma solidity ^0.8.8; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + import {IApplication} from "./IApplication.sol"; import {IConsensus} from "../consensus/IConsensus.sol"; @@ -14,13 +16,14 @@ interface IApplicationFactory { /// @param consensus The initial consensus contract /// @param appOwner The initial application owner /// @param templateHash The initial machine state hash + /// @param dataAvailability The data availability solution /// @param appContract The application contract /// @dev MUST be triggered on a successful call to `newApplication`. event ApplicationCreated( IConsensus indexed consensus, address appOwner, bytes32 templateHash, - bytes dataAvailability, + IERC165 dataAvailability, IApplication appContract ); @@ -30,6 +33,7 @@ interface IApplicationFactory { /// @param consensus The initial consensus contract /// @param appOwner The initial application owner /// @param templateHash The initial machine state hash + /// @param dataAvailability The data availability solution /// @return The application /// @dev On success, MUST emit an `ApplicationCreated` event. /// @dev Reverts if the application owner address is zero. @@ -37,13 +41,14 @@ interface IApplicationFactory { IConsensus consensus, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability + IERC165 dataAvailability ) external returns (IApplication); /// @notice Deploy a new application deterministically. /// @param consensus The initial consensus contract /// @param appOwner The initial application owner /// @param templateHash The initial machine state hash + /// @param dataAvailability The data availability solution /// @param salt The salt used to deterministically generate the application contract address /// @return The application /// @dev On success, MUST emit an `ApplicationCreated` event. @@ -52,7 +57,7 @@ interface IApplicationFactory { IConsensus consensus, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) external returns (IApplication); @@ -60,6 +65,7 @@ interface IApplicationFactory { /// @param consensus The initial consensus contract /// @param appOwner The initial application owner /// @param templateHash The initial machine state hash + /// @param dataAvailability The data availability solution /// @param salt The salt used to deterministically generate the application contract address /// @return The deterministic application contract address /// @dev Beware that only the `newApplication` function with the `salt` parameter @@ -68,7 +74,7 @@ interface IApplicationFactory { IConsensus consensus, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) external view returns (address); } diff --git a/contracts/dapp/ISelfHostedApplicationFactory.sol b/contracts/dapp/ISelfHostedApplicationFactory.sol index c1503c1b..5f18fadc 100644 --- a/contracts/dapp/ISelfHostedApplicationFactory.sol +++ b/contracts/dapp/ISelfHostedApplicationFactory.sol @@ -3,6 +3,8 @@ pragma solidity ^0.8.8; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + import {IAuthority} from "../consensus/authority/IAuthority.sol"; import {IAuthorityFactory} from "../consensus/authority/IAuthorityFactory.sol"; import {IApplication} from "./IApplication.sol"; @@ -26,6 +28,7 @@ interface ISelfHostedApplicationFactory { /// @param epochLength The epoch length /// @param appOwner The initial application owner /// @param templateHash The initial machine state hash + /// @param dataAvailability The data availability solution /// @param salt The salt used to deterministically generate the addresses /// @return The application contract /// @return The authority contract @@ -37,7 +40,7 @@ interface ISelfHostedApplicationFactory { uint256 epochLength, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) external returns (IApplication, IAuthority); @@ -47,6 +50,7 @@ interface ISelfHostedApplicationFactory { /// @param epochLength The epoch length /// @param appOwner The initial application owner /// @param templateHash The initial machine state hash + /// @param dataAvailability The data availability solution /// @param salt The salt used to deterministically generate the addresses /// @return The application address /// @return The authority address @@ -55,7 +59,7 @@ interface ISelfHostedApplicationFactory { uint256 epochLength, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) external view returns (address, address); } diff --git a/contracts/dapp/SelfHostedApplicationFactory.sol b/contracts/dapp/SelfHostedApplicationFactory.sol index c8fb1e5f..14988855 100644 --- a/contracts/dapp/SelfHostedApplicationFactory.sol +++ b/contracts/dapp/SelfHostedApplicationFactory.sol @@ -3,6 +3,8 @@ pragma solidity ^0.8.8; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + import {IConsensus} from "../consensus/IConsensus.sol"; import {IAuthority} from "../consensus/authority/IAuthority.sol"; import {IAuthorityFactory} from "../consensus/authority/IAuthorityFactory.sol"; @@ -50,7 +52,7 @@ contract SelfHostedApplicationFactory is ISelfHostedApplicationFactory { uint256 epochLength, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) external returns (IApplication application, IAuthority authority) { authority = _authorityFactory.newAuthority( @@ -73,7 +75,7 @@ contract SelfHostedApplicationFactory is ISelfHostedApplicationFactory { uint256 epochLength, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) external view returns (address application, address authority) { authority = _authorityFactory.calculateAuthorityAddress( diff --git a/test/dapp/Application.t.sol b/test/dapp/Application.t.sol index 811c646b..173e2c68 100644 --- a/test/dapp/Application.t.sol +++ b/test/dapp/Application.t.sol @@ -21,6 +21,7 @@ import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Re import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; import {IERC20Errors, IERC721Errors, IERC1155Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; @@ -54,7 +55,7 @@ contract ApplicationTest is TestBase, OwnableTest { address _authorityOwner; address _recipient; address _tokenOwner; - bytes _dataAvailability; + IERC165 _dataAvailability; string[] _outputNames; bytes4[] _interfaceIds; uint256[] _tokenIds; @@ -94,14 +95,14 @@ contract ApplicationTest is TestBase, OwnableTest { address(0) ) ); - new Application(_consensus, address(0), _templateHash, new bytes(0)); + new Application(_consensus, address(0), _templateHash, IERC165(address(0))); } function testConstructor( IConsensus consensus, address owner, bytes32 templateHash, - bytes calldata dataAvailability + IERC165 dataAvailability ) external { vm.assume(owner != address(0)); @@ -118,7 +119,7 @@ contract ApplicationTest is TestBase, OwnableTest { assertEq(address(appContract.getConsensus()), address(consensus)); assertEq(appContract.owner(), owner); assertEq(appContract.getTemplateHash(), templateHash); - assertEq(appContract.getDataAvailability(), dataAvailability); + assertEq(address(appContract.getDataAvailability()), address(dataAvailability)); } // ------------------- @@ -347,7 +348,7 @@ contract ApplicationTest is TestBase, OwnableTest { ); _inputBox = new InputBox(); _consensus = new Authority(_authorityOwner, _epochLength); - _dataAvailability = new bytes(0); + _dataAvailability = IERC165(address(0)); _appContract = new Application( _consensus, _appOwner, diff --git a/test/dapp/ApplicationFactory.t.sol b/test/dapp/ApplicationFactory.t.sol index d8d30d23..c3b533ab 100644 --- a/test/dapp/ApplicationFactory.t.sol +++ b/test/dapp/ApplicationFactory.t.sol @@ -4,6 +4,8 @@ /// @title Application Factory Test pragma solidity ^0.8.22; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + import {TestBase} from "../util/TestBase.sol"; import {ApplicationFactory, IApplicationFactory} from "contracts/dapp/ApplicationFactory.sol"; import {IApplication} from "contracts/dapp/IApplication.sol"; @@ -21,7 +23,7 @@ contract ApplicationFactoryTest is TestBase { IConsensus consensus, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability + IERC165 dataAvailability ) public { vm.assume(appOwner != address(0)); @@ -35,14 +37,14 @@ contract ApplicationFactoryTest is TestBase { assertEq(address(appContract.getConsensus()), address(consensus)); assertEq(appContract.owner(), appOwner); assertEq(appContract.getTemplateHash(), templateHash); - assertEq(appContract.getDataAvailability(), dataAvailability); + assertEq(address(appContract.getDataAvailability()), address(dataAvailability)); } function testNewApplicationDeterministic( IConsensus consensus, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) public { vm.assume(appOwner != address(0)); @@ -69,7 +71,7 @@ contract ApplicationFactoryTest is TestBase { assertEq(address(appContract.getConsensus()), address(consensus)); assertEq(appContract.owner(), appOwner); assertEq(appContract.getTemplateHash(), templateHash); - assertEq(appContract.getDataAvailability(), dataAvailability); + assertEq(address(appContract.getDataAvailability()), address(dataAvailability)); precalculatedAddress = _factory.calculateApplicationAddress( consensus, @@ -97,7 +99,7 @@ contract ApplicationFactoryTest is TestBase { IConsensus consensus, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability + IERC165 dataAvailability ) public { vm.assume(appOwner != address(0)); @@ -123,7 +125,7 @@ contract ApplicationFactoryTest is TestBase { IConsensus consensus, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) public { vm.assume(appOwner != address(0)); @@ -151,7 +153,7 @@ contract ApplicationFactoryTest is TestBase { IConsensus consensus, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, IApplication appContract ) internal { Vm.Log[] memory entries = vm.getRecordedLogs(); @@ -176,16 +178,16 @@ contract ApplicationFactoryTest is TestBase { ( address appOwner_, bytes32 templateHash_, - bytes memory dataAvailability_, + IERC165 dataAvailability_, IApplication app_ ) = abi.decode( entry.data, - (address, bytes32, bytes, IApplication) + (address, bytes32, IERC165, IApplication) ); assertEq(appOwner, appOwner_); assertEq(templateHash, templateHash_); - assertEq(dataAvailability, dataAvailability_); + assertEq(address(dataAvailability), address(dataAvailability_)); assertEq(address(appContract), address(app_)); } } diff --git a/test/dapp/SelfHostedApplicationFactory.t.sol b/test/dapp/SelfHostedApplicationFactory.t.sol index d8938c92..93f4e401 100644 --- a/test/dapp/SelfHostedApplicationFactory.t.sol +++ b/test/dapp/SelfHostedApplicationFactory.t.sol @@ -5,6 +5,7 @@ pragma solidity ^0.8.22; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {IAuthorityFactory} from "contracts/consensus/authority/IAuthorityFactory.sol"; import {AuthorityFactory} from "contracts/consensus/authority/AuthorityFactory.sol"; @@ -49,7 +50,7 @@ contract SelfHostedApplicationFactoryTest is TestBase { uint256 epochLength, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) external { vm.assume(appOwner != address(0)); @@ -75,7 +76,7 @@ contract SelfHostedApplicationFactoryTest is TestBase { address authorityOwner, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) external { vm.assume(appOwner != address(0)); @@ -96,7 +97,7 @@ contract SelfHostedApplicationFactoryTest is TestBase { address authorityOwner, uint256 epochLength, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) external { vm.assume(authorityOwner != address(0)); @@ -123,7 +124,7 @@ contract SelfHostedApplicationFactoryTest is TestBase { uint256 epochLength, address appOwner, bytes32 templateHash, - bytes calldata dataAvailability, + IERC165 dataAvailability, bytes32 salt ) external { vm.assume(appOwner != address(0)); @@ -163,6 +164,6 @@ contract SelfHostedApplicationFactoryTest is TestBase { assertEq(address(application.getConsensus()), authorityAddr); assertEq(application.owner(), appOwner); assertEq(application.getTemplateHash(), templateHash); - assertEq(application.getDataAvailability(), dataAvailability); + assertEq(address(application.getDataAvailability()), address(dataAvailability)); } }