Commit b025a7b9 authored by James Kim's avatar James Kim

update comments and make one call to AttestationStation in bulk

parent 36c95f4b
......@@ -20,7 +20,6 @@ contract OptimistInviter_Initializer is Test {
bytes val
);
bytes32 CLAIMABLE_INVITE_TYPEHASH;
bytes32 EIP712_DOMAIN_TYPEHASH;
address internal alice_inviteGranter;
......@@ -63,7 +62,6 @@ contract OptimistInviter_Initializer is Test {
vm.deal(ted, 1 ether);
vm.deal(eve, 1 ether);
CLAIMABLE_INVITE_TYPEHASH = keccak256("ClaimableInvite(address issuer,bytes32 nonce)");
EIP712_DOMAIN_TYPEHASH = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
......@@ -99,7 +97,7 @@ contract OptimistInviter_Initializer is Test {
bytes memory attestation = attestationStation.attestations(
address(optimistInviter),
_issuer,
bytes32("optimist.can-invite")
optimistInviter.CAN_INVITE_ATTESTATION_KEY()
);
return abi.decode(attestation, (uint256));
}
......@@ -111,7 +109,7 @@ contract OptimistInviter_Initializer is Test {
bytes memory attestation = attestationStation.attestations(
address(optimistInviter),
_claimer,
bytes32("optimist.can-mint-from-invite")
optimistInviter.CAN_MINT_FROM_INVITE_ATTESTATION_KEY()
);
return attestation.length > 0;
}
......@@ -221,7 +219,7 @@ contract OptimistInviter_Initializer is Test {
emit AttestationCreated(
address(optimistInviter),
_claimer,
bytes32("optimist.can-mint-from-invite"),
optimistInviter.CAN_MINT_FROM_INVITE_ATTESTATION_KEY(),
abi.encode(issuer)
);
......@@ -230,7 +228,7 @@ contract OptimistInviter_Initializer is Test {
emit AttestationCreated(
address(optimistInviter),
issuer,
bytes32("optimist.can-invite"),
optimistInviter.CAN_INVITE_ATTESTATION_KEY(),
abi.encode(prevInviteCount - 1)
);
......@@ -265,7 +263,7 @@ contract OptimistInviter_Initializer is Test {
emit AttestationCreated(
address(optimistInviter),
_to,
bytes32("optimist.can-invite"),
optimistInviter.CAN_INVITE_ATTESTATION_KEY(),
abi.encode(3)
);
......@@ -286,7 +284,7 @@ contract OptimistInviter_Initializer is Test {
return
keccak256(
abi.encode(
CLAIMABLE_INVITE_TYPEHASH,
optimistInviter.CLAIMABLE_INVITE_TYPEHASH(),
_claimableInvite.issuer,
_claimableInvite.nonce
)
......@@ -341,7 +339,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
emit AttestationCreated(
address(optimistInviter),
bob,
bytes32("optimist.can-invite"),
optimistInviter.CAN_INVITE_ATTESTATION_KEY(),
abi.encode(3)
);
......@@ -349,7 +347,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
emit AttestationCreated(
address(optimistInviter),
sally,
bytes32("optimist.can-invite"),
optimistInviter.CAN_INVITE_ATTESTATION_KEY(),
abi.encode(3)
);
......@@ -357,7 +355,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
emit AttestationCreated(
address(optimistInviter),
address(carolERC1271Wallet),
bytes32("optimist.can-invite"),
optimistInviter.CAN_INVITE_ATTESTATION_KEY(),
abi.encode(3)
);
......@@ -438,7 +436,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
emit AttestationCreated(
address(optimistInviter),
sally,
bytes32("optimist.can-mint-from-invite"),
optimistInviter.CAN_MINT_FROM_INVITE_ATTESTATION_KEY(),
abi.encode(bob)
);
......@@ -447,7 +445,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
emit AttestationCreated(
address(optimistInviter),
bob,
bytes32("optimist.can-invite"),
optimistInviter.CAN_INVITE_ATTESTATION_KEY(),
abi.encode(2)
);
......@@ -588,7 +586,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
emit AttestationCreated(
address(optimistInviter),
sally,
bytes32("optimist.can-mint-from-invite"),
optimistInviter.CAN_MINT_FROM_INVITE_ATTESTATION_KEY(),
abi.encode(address(carolERC1271Wallet))
);
......@@ -597,7 +595,7 @@ contract OptimistInviterTest is OptimistInviter_Initializer {
emit AttestationCreated(
address(optimistInviter),
address(carolERC1271Wallet),
bytes32("optimist.can-invite"),
optimistInviter.CAN_INVITE_ATTESTATION_KEY(),
abi.encode(2)
);
......
......@@ -15,6 +15,24 @@ import {
* "optimist.can-mint-from-invite" attestations. Accounts that have a "optimist.can-invite"
* attestation can issue signatures that allow other accounts to claim an invite. The
* invitee uses a claim and reveal flow to claim the invite to an address of their choosing.
*
* Parties involved:
* 1) INVITE_GRANTER: trusted account that can allow accounts to issue invites
* 2) issuer: account that is allowed to issue invites
* 3) claimer: account that receives the invites
*
* Flow:
* 1) INVITE_GRANTER calls _setInviteCount to allow an issuer to issue a certain number
* of invites, creating "optimist.can-invite" attestations for the issuer
* 2) Off-chain, the issuer signs (EIP-712) a ClaimableInvite to produce a signature
* 3) Off-chain, invite issuer sends the plaintext ClaimableInvite and the signature
* to the recipient
* 4) claimer chooses an address they want to receive the invite on
* 5) claimer commits the hash of the address they want to receive the invite on and the
received signature [keccak256(abi.encode(addressToReceiveTo, receivedSignature))]
* using the commitInvite function
* 6) claimer reveals the plaintext ClaimableInvite and the signature using the
* claimInvite function, receiving the "optimist.can-mint-from-invite" attestation
*/
contract OptimistInviter is Semver, EIP712Upgradeable {
/**
......@@ -27,24 +45,20 @@ contract OptimistInviter is Semver, EIP712Upgradeable {
/**
* @notice EIP712 typehash for the ClaimableInvite type.
* keccak256("ClaimableInvite(address issuer,bytes32 nonce)")
*/
bytes32 public constant CLAIMABLE_INVITE_TYPEHASH =
0x6529fd129351e725d7bcbc468b0b0b4675477e56b58514e69ab7e66ddfd20fce;
keccak256("ClaimableInvite(address issuer,bytes32 nonce)");
/**
* @notice Attestation key for granting invites.
* bytes32("optimist.can-invite")
*/
bytes32 public constant CAN_INVITE_ATTESTATION_KEY =
0x6f7074696d6973742e63616e2d696e7669746500000000000000000000000000;
bytes32 public constant CAN_INVITE_ATTESTATION_KEY = bytes32("optimist.can-invite");
/**
* @notice Attestation key allowing the attested account to mint.
* bytes32("optimist.can-mint-from-invite")
*/
bytes32 public constant CAN_MINT_FROM_INVITE_ATTESTATION_KEY =
0x6f7074696d6973742e63616e2d6d696e742d66726f6d2d696e76697465000000;
bytes32("optimist.can-mint-from-invite");
/**
* @notice Granter who can set accounts' invite counts.
......@@ -116,25 +130,48 @@ contract OptimistInviter is Semver, EIP712Upgradeable {
uint256 length = _accounts.length;
AttestationStation.AttestationData[]
memory attestations = new AttestationStation.AttestationData[](length);
for (uint256 i; i < length; ) {
// The granted invites are stored as an attestation from this contract on the
// AttestationStation contract. Number of invites is stored as a encoded uint256 in the
// data field of the attestation.
ATTESTATION_STATION.attest(
_accounts[i],
CAN_INVITE_ATTESTATION_KEY,
abi.encode(_inviteCount)
);
attestations[i] = AttestationStation.AttestationData({
about: _accounts[i],
key: CAN_INVITE_ATTESTATION_KEY,
val: abi.encode(_inviteCount)
});
unchecked {
++i;
}
}
ATTESTATION_STATION.attest(attestations);
}
function attest(AttestationStation.AttestationData[] calldata _attestations) public {
// Only invite granter can grant invites
require(
msg.sender == INVITE_GRANTER,
"OptimistInviter: only invite granter can issue attestations"
);
ATTESTATION_STATION.attest(_attestations);
}
/**
* @notice Allows anyone to commit a received signature along with the address to claim to.
* This is necessary to prevent front-running when the invitee is claiming the invite.
* @notice Allows anyone (but likely the claimer) to commit a received signature along with the
* address to claim to.
*
* Before calling this function, the claimer should have received a signature from the
* issuer off-chain. The claimer then calls this function with the hash of the
* claimer's address and the received signature. This is necessary to prevent
* front-running when the invitee is claiming the invite. Without a commit and reveal
* scheme, anyone who is watching the mempool can take the signature being submitted
* and front run the transaction to claim the invite to their own address.
*
*
* @param _commitment A hash of the claimer and signature concatenated.
* keccak256(abi.encode(_claimer, _signature))
......@@ -145,8 +182,15 @@ contract OptimistInviter is Semver, EIP712Upgradeable {
/**
* @notice Allows anyone to reveal a commitment and claim an invite.
* The claimer ++ signature pair should have been previously committed using
* commitInvite. Doesn't require that the claimer is calling this function.
*
* The hash, keccak256(abi.encode(_claimer, _signature)), should have been already
* committed using commitInvite. Before issuing the "optimist.can-mint-from-invite"
* attestation, this function checks that
* 1) the hash corresponding to the _claimer and the _signature was committed
* 2) the _signature is signed correctly by the issuer
* 3) the _signature hasn't already been used to claim an invite before
* 4) the _signature issuer has not used up all of their invites
* This function doesn't require that the _claimer is calling this function.
*
* @param _claimer Address that will be granted the invite.
* @param _claimableInvite ClaimableInvite struct containing the issuer and nonce.
......@@ -218,7 +262,7 @@ contract OptimistInviter is Semver, EIP712Upgradeable {
);
// Reduce the issuer's invite count by 1 by re-attesting the optimist.can-invite attestation
// with the new count.
// with the new count. Can be unchecked because we check that the count is > 0 above.
unchecked {
--count;
}
......
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