Commit a4315c8c authored by Mark Tyneway's avatar Mark Tyneway

contracts-bedrock: port op-nft

parent fe3359bb
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol";
import { Semver } from "../../universal/Semver.sol";
/**
* @title AttestationStation
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol";
import { Semver } from "../../universal/Semver.sol";
import {
ERC721BurnableUpgradeable
} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol";
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol";
import { Semver } from "../../universal/Semver.sol";
import { AttestationStation } from "./AttestationStation.sol";
import { OptimistConstants } from "./libraries/OptimistConstants.sol";
......
......@@ -2,7 +2,7 @@
pragma solidity 0.8.15;
import { OptimistConstants } from "./libraries/OptimistConstants.sol";
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol";
import { Semver } from "../../universal/Semver.sol";
import { AttestationStation } from "./AttestationStation.sol";
import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import {
......
......@@ -3,7 +3,7 @@ pragma solidity 0.8.15;
/* Testing utilities */
import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../universal/op-nft/AttestationStation.sol";
import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
contract AttestationStation_Initializer is Test {
address alice_attestor = address(128);
......
......@@ -3,6 +3,10 @@ pragma solidity ^0.8.0;
import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol";
import { ERC721 } from "@rari-capital/solmate/src/tokens/ERC721.sol";
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import { OptimistInviter } from "../periphery/op-nft/OptimistInviter.sol";
import { IERC1271 } from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
contract TestERC20 is ERC20 {
constructor() ERC20("TEST", "TST", 18) {}
......@@ -57,3 +61,164 @@ contract SimpleStorage {
return db[_key];
}
}
/**
* Simple helper contract that helps with testing flow and signature for OptimistInviter contract.
* Made this a separate contract instead of including in OptimistInviter.t.sol for reusability.
*/
contract OptimistInviterHelper {
/**
* @notice EIP712 typehash for the ClaimableInvite type.
*/
bytes32 public constant CLAIMABLE_INVITE_TYPEHASH =
keccak256("ClaimableInvite(address issuer,bytes32 nonce)");
/**
* @notice EIP712 typehash for the EIP712Domain type that is included as part of the signature.
*/
bytes32 public constant EIP712_DOMAIN_TYPEHASH =
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
/**
* @notice Address of OptimistInviter contract we are testing.
*/
OptimistInviter public optimistInviter;
/**
* @notice OptimistInviter contract name. Used to construct the EIP-712 domain.
*/
string public name;
/**
* @notice Keeps track of current nonce to generate new nonces for each invite.
*/
uint256 public currentNonce;
constructor(OptimistInviter _optimistInviter, string memory _name) {
optimistInviter = _optimistInviter;
name = _name;
}
/**
* @notice Returns the hash of the struct ClaimableInvite.
*
* @param _claimableInvite ClaimableInvite struct to hash.
*
* @return EIP-712 typed struct hash.
*/
function getClaimableInviteStructHash(OptimistInviter.ClaimableInvite memory _claimableInvite)
public
pure
returns (bytes32)
{
return
keccak256(
abi.encode(
CLAIMABLE_INVITE_TYPEHASH,
_claimableInvite.issuer,
_claimableInvite.nonce
)
);
}
/**
* @notice Returns a bytes32 nonce that should change everytime. In practice, people should use
* pseudorandom nonces.
*
* @return Nonce that should be used as part of ClaimableInvite.
*/
function consumeNonce() public returns (bytes32) {
return bytes32(keccak256(abi.encode(currentNonce++)));
}
/**
* @notice Returns a ClaimableInvite with the issuer and current nonce.
*
* @param _issuer Issuer to include in the ClaimableInvite.
*
* @return ClaimableInvite that can be hashed & signed.
*/
function getClaimableInviteWithNewNonce(address _issuer)
public
returns (OptimistInviter.ClaimableInvite memory)
{
return OptimistInviter.ClaimableInvite(_issuer, consumeNonce());
}
/**
* @notice Computes the EIP712 digest with default correct parameters.
*
* @param _claimableInvite ClaimableInvite struct to hash.
*
* @return EIP-712 compatible digest.
*/
function getDigest(OptimistInviter.ClaimableInvite calldata _claimableInvite)
public
view
returns (bytes32)
{
return
getDigestWithEIP712Domain(
_claimableInvite,
bytes(name),
bytes(optimistInviter.EIP712_VERSION()),
block.chainid,
address(optimistInviter)
);
}
/**
* @notice Computes the EIP712 digest with the given domain parameters.
* Used for testing that different domain parameters fail.
*
* @param _claimableInvite ClaimableInvite struct to hash.
* @param _name Contract name to use in the EIP712 domain.
* @param _version Contract version to use in the EIP712 domain.
* @param _chainid Chain ID to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
*
* @return EIP-712 compatible digest.
*/
function getDigestWithEIP712Domain(
OptimistInviter.ClaimableInvite calldata _claimableInvite,
bytes memory _name,
bytes memory _version,
uint256 _chainid,
address _verifyingContract
) public pure returns (bytes32) {
bytes32 domainSeparator = keccak256(
abi.encode(
EIP712_DOMAIN_TYPEHASH,
keccak256(_name),
keccak256(_version),
_chainid,
_verifyingContract
)
);
return
ECDSA.toTypedDataHash(domainSeparator, getClaimableInviteStructHash(_claimableInvite));
}
}
// solhint-disable max-line-length
/**
* Simple ERC1271 wallet that can be used to test the ERC1271 signature checker.
* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/mocks/ERC1271WalletMock.sol
*/
contract TestERC1271Wallet is Ownable, IERC1271 {
constructor(address originalOwner) {
transferOwnership(originalOwner);
}
function isValidSignature(bytes32 hash, bytes memory signature)
public
view
override
returns (bytes4 magicValue)
{
return
ECDSA.recover(hash, signature) == owner() ? this.isValidSignature.selector : bytes4(0);
}
}
......@@ -3,11 +3,11 @@ pragma solidity >=0.6.2 <0.9.0;
/* Testing utilities */
import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../universal/op-nft/AttestationStation.sol";
import { Optimist } from "../universal/op-nft/Optimist.sol";
import { OptimistAllowlist } from "../universal/op-nft/OptimistAllowlist.sol";
import { OptimistInviter } from "../universal/op-nft/OptimistInviter.sol";
import { OptimistInviterHelper } from "../testing/helpers/OptimistInviterHelper.sol";
import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
import { Optimist } from "../periphery/op-nft/Optimist.sol";
import { OptimistAllowlist } from "../periphery/op-nft/OptimistAllowlist.sol";
import { OptimistInviter } from "../periphery/op-nft/OptimistInviter.sol";
import { OptimistInviterHelper } from "./Helpers.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
......
......@@ -3,11 +3,11 @@ pragma solidity 0.8.15;
/* Testing utilities */
import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../universal/op-nft/AttestationStation.sol";
import { OptimistAllowlist } from "../universal/op-nft/OptimistAllowlist.sol";
import { OptimistInviter } from "../universal/op-nft/OptimistInviter.sol";
import { OptimistInviterHelper } from "../testing/helpers/OptimistInviterHelper.sol";
import { OptimistConstants } from "../universal/op-nft/libraries/OptimistConstants.sol";
import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
import { OptimistAllowlist } from "../periphery/op-nft/OptimistAllowlist.sol";
import { OptimistInviter } from "../periphery/op-nft/OptimistInviter.sol";
import { OptimistInviterHelper } from "./Helpers.sol";
import { OptimistConstants } from "../periphery/op-nft/libraries/OptimistConstants.sol";
contract OptimistAllowlist_Initializer is Test {
event AttestationCreated(
......
......@@ -3,13 +3,13 @@ pragma solidity 0.8.15;
/* Testing utilities */
import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../universal/op-nft/AttestationStation.sol";
import { OptimistInviter } from "../universal/op-nft/OptimistInviter.sol";
import { Optimist } from "../universal/op-nft/Optimist.sol";
import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
import { OptimistInviter } from "../periphery/op-nft/OptimistInviter.sol";
import { Optimist } from "../periphery/op-nft/Optimist.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { TestERC1271Wallet } from "../testing/helpers/TestERC1271Wallet.sol";
import { OptimistInviterHelper } from "../testing/helpers/OptimistInviterHelper.sol";
import { OptimistConstants } from "../universal/op-nft/libraries/OptimistConstants.sol";
import { TestERC1271Wallet } from "./Helpers.sol";
import { OptimistInviterHelper } from "./Helpers.sol";
import { OptimistConstants } from "../periphery/op-nft/libraries/OptimistConstants.sol";
contract OptimistInviter_Initializer is Test {
event InviteClaimed(address indexed issuer, address indexed claimer);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment