Skip to content

Commit

Permalink
evm: enhance; fix Redeemed event
Browse files Browse the repository at this point in the history
  • Loading branch information
a5-pickle committed Dec 20, 2023
1 parent c43e1bf commit da622c5
Show file tree
Hide file tree
Showing 11 changed files with 325 additions and 359 deletions.
2 changes: 1 addition & 1 deletion evm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ forge-test: dependencies

.PHONY: gas-report
gas-report: dependencies
forge test --fork-url ${TESTING_FORK_RPC} --match-path forge/tests/gas/* --fuzz-runs 256 --gas-report
forge test --fork-url ${TESTING_FORK_RPC} --match-path forge/tests/gas/* --fuzz-runs 512 --gas-report

.PHONY: gas-snapshot
gas-snapshot: dependencies
Expand Down
21 changes: 10 additions & 11 deletions evm/forge/tests/CircleIntegration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {IWormhole} from "src/interfaces/IWormhole.sol";
import {ICircleIntegration} from "src/interfaces/ICircleIntegration.sol";

import {Utils} from "src/libraries/Utils.sol";
import {Deposit, WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
import {WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";

import {Setup} from "src/contracts/CircleIntegration/Setup.sol";
import {Implementation} from "src/contracts/CircleIntegration/Implementation.sol";
Expand Down Expand Up @@ -239,17 +239,16 @@ contract CircleIntegrationTest is Test {
assertEq(
keccak256(fetchedPayloads[i]),
keccak256(
Deposit({
token: USDC_ADDRESS.toUniversalAddress(),
amount: amount,
sourceCctpDomain: circleIntegration.circleBridge().localMessageTransmitter()
.localDomain(),
targetCctpDomain: targetDomain,
cctpNonce: circleIntegration.circleBridge().localMessageTransmitter()
USDC_ADDRESS.encodeDeposit(
amount,
circleIntegration.circleBridge().localMessageTransmitter().localDomain(),
targetDomain,
circleIntegration.circleBridge().localMessageTransmitter()
.nextAvailableNonce() - 2 + uint64(i),
burnSource: address(this).toUniversalAddress(),
mintRecipient: mintRecipient
}).encodeWithPayload(payloads[i])
address(this).toUniversalAddress(),
mintRecipient,
payloads[i]
)
)
);
unchecked {
Expand Down
22 changes: 11 additions & 11 deletions evm/forge/tests/InheritingWormholeCctp.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {ICircleIntegration} from "src/interfaces/ICircleIntegration.sol";
import {IWormhole} from "src/interfaces/IWormhole.sol";

import {Utils} from "src/libraries/Utils.sol";
import {Deposit, WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
import {WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";

import {Setup} from "src/contracts/CircleIntegration/Setup.sol";
import {Implementation} from "src/contracts/CircleIntegration/Implementation.sol";
Expand Down Expand Up @@ -115,16 +115,16 @@ contract InheritingWormholeCctpTest is Test {
assertEq(
keccak256(fetchedPayloads[0]),
keccak256(
Deposit({
token: USDC_ADDRESS.toUniversalAddress(),
amount: amount,
sourceCctpDomain: 0,
targetCctpDomain: inheritedContract.myBffDomain(),
cctpNonce: circleIntegration.circleBridge().localMessageTransmitter()
.nextAvailableNonce() - 1,
burnSource: address(this).toUniversalAddress(),
mintRecipient: mintRecipient
}).encodeWithPayload(payload)
USDC_ADDRESS.encodeDeposit(
amount,
0, // sourceCctpDomain
inheritedContract.myBffDomain(), // targetCctpDomain
circleIntegration.circleBridge().localMessageTransmitter().nextAvailableNonce()
- 1,
address(this).toUniversalAddress(),
mintRecipient,
payload
)
)
);

Expand Down
57 changes: 41 additions & 16 deletions evm/forge/tests/WormholeCctpMessages.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "forge-std/console.sol";

import {Deposit, WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
import {IWormhole} from "src/interfaces/IWormhole.sol";

import {WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";

contract MessagesTest is Test {
using WormholeCctpMessages for *;
Expand All @@ -24,24 +26,47 @@ contract MessagesTest is Test {
vm.assume(payload.length > 0);
vm.assume(payload.length < type(uint16).max);

Deposit memory deposit = Deposit({
token: token,
amount: amount,
sourceCctpDomain: sourceCctpDomain,
targetCctpDomain: targetCctpDomain,
cctpNonce: cctpNonce,
burnSource: burnSource,
mintRecipient: mintRecipient
});

bytes memory encoded = deposit.encodeWithPayload(payload);
assertEq(encoded.length, 147 + payload.length);
IWormhole.VM memory fakeVaa;
fakeVaa.payload = token.encodeDeposit(
amount,
sourceCctpDomain,
targetCctpDomain,
cctpNonce,
burnSource,
mintRecipient,
payload
);
assertEq(fakeVaa.payload.length, 147 + payload.length);

uint8 payloadId = uint8(bytes1(encoded));
uint8 payloadId = uint8(bytes1(fakeVaa.payload));
assertEq(payloadId, 1);

(Deposit memory decoded, bytes memory takenPayload) = encoded.decodeDepositWithPayload();
assertEq(keccak256(abi.encode(decoded)), keccak256(abi.encode(deposit)));
bytes32 decodedToken;
uint256 decodedAmount;
uint32 decodedSourceCctpDomain;
uint32 decodedTargetCctpDomain;
uint64 decodedCctpNonce;
bytes32 decodedBurnSource;
bytes32 decodedMintRecipient;
bytes memory takenPayload;
(
decodedToken,
decodedAmount,
decodedSourceCctpDomain,
decodedTargetCctpDomain,
decodedCctpNonce,
decodedBurnSource,
decodedMintRecipient,
takenPayload
) = fakeVaa.decodeDeposit();

assertEq(decodedToken, token);
assertEq(decodedAmount, amount);
assertEq(decodedSourceCctpDomain, sourceCctpDomain);
assertEq(decodedTargetCctpDomain, targetCctpDomain);
assertEq(decodedCctpNonce, cctpNonce);
assertEq(decodedBurnSource, burnSource);
assertEq(decodedMintRecipient, mintRecipient);
assertEq(keccak256(abi.encode(takenPayload)), keccak256(abi.encode(payload)));
}
}
2 changes: 1 addition & 1 deletion evm/forge/tests/gas/CircleIntegrationComparison.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {IWormhole} from "src/interfaces/IWormhole.sol";
import {ICircleIntegration} from "src/interfaces/ICircleIntegration.sol";

import {Utils} from "src/libraries/Utils.sol";
import {Deposit, WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
import {WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";

import {Setup} from "src/contracts/CircleIntegration/Setup.sol";
import {Implementation} from "src/contracts/CircleIntegration/Implementation.sol";
Expand Down
20 changes: 10 additions & 10 deletions evm/forge/tests/helpers/libraries/CircleIntegrationOverride.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {IWormhole} from "src/interfaces/IWormhole.sol";

import {BytesParsing} from "src/libraries/BytesParsing.sol";
import {Utils} from "src/libraries/Utils.sol";
import {Deposit, WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
import {WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";

import "forge-std/Test.sol";
import "forge-std/console.sol";
Expand Down Expand Up @@ -332,15 +332,15 @@ library CircleIntegrationOverride {
vaaParams.emitterChain,
burnMsg.messageSender,
vaaParams.sequence,
Deposit({
token: burnMsg.burnToken,
amount: burnMsg.amount,
sourceCctpDomain: burnMsg.header.sourceDomain,
targetCctpDomain: burnMsg.header.destinationDomain,
cctpNonce: burnMsg.header.nonce,
burnSource: burnSource,
mintRecipient: burnMsg.mintRecipient
}).encodeWithPayload(payload)
burnMsg.burnToken.encodeDeposit(
burnMsg.amount,
burnMsg.header.sourceDomain,
burnMsg.header.destinationDomain,
burnMsg.header.nonce,
burnSource,
burnMsg.mintRecipient,
payload
)
);
}

Expand Down
86 changes: 47 additions & 39 deletions evm/src/contracts/CircleIntegration/Logic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {ITokenMinter} from "src/interfaces/ITokenMinter.sol";
import {ICircleIntegration} from "src/interfaces/ICircleIntegration.sol";

import {Utils} from "src/libraries/Utils.sol";
import {Deposit, WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
import {WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";

import {Governance} from "./Governance.sol";
import {
Expand Down Expand Up @@ -63,35 +63,39 @@ abstract contract Logic is ICircleIntegration, Governance {
{
require(evmChain() == block.chainid, "invalid evm chain");

uint16 chain;
bytes32 emitter;
bytes32 vaaHash;
Deposit memory depositHeader;
(chain, emitter, vaaHash, depositHeader, deposit.payload) =
verifyVaaAndMintLegacy(params.cctpMessage, params.cctpAttestation, params.encodedVaa);
IWormhole.VM memory vaa;
(
vaa,
deposit.token,
deposit.amount,
deposit.sourceDomain,
deposit.targetDomain,
deposit.nonce,
deposit.fromAddress,
deposit.mintRecipient,
deposit.payload
) = verifyVaaAndMintLegacy(params.cctpMessage, params.cctpAttestation, params.encodedVaa);

// NOTE: Reverting with Error(string) comes from the old implementation, so we preserve it.
require(emitter != 0 && emitter == getRegisteredEmitters()[chain], "unknown emitter");
require(
vaa.emitterAddress != 0
&& vaa.emitterAddress == getRegisteredEmitters()[vaa.emitterChainId],
"unknown emitter"
);

mapping(bytes32 => bool) storage consumedVaas = getConsumedVaas();

// Revert if this message has been consumed already. This check is meant to prevent replay
// attacks, but it may not be necessary because the CCTP Message Transmitter already keeps
// track of used nonces.
// NOTE: Reverting with Error(string) comes from the old implementation, so we preserve it.
require(!consumedVaas[vaaHash], "message already consumed");
require(!consumedVaas[vaa.hash], "message already consumed");

// Mark as consumed.
consumedVaas[vaaHash] = true;
consumedVaas[vaa.hash] = true;

// Set remaining deposit vars.
deposit.token = depositHeader.token;
deposit.amount = depositHeader.amount;
deposit.sourceDomain = depositHeader.sourceCctpDomain;
deposit.targetDomain = depositHeader.targetCctpDomain;
deposit.nonce = depositHeader.cctpNonce;
deposit.fromAddress = depositHeader.burnSource;
deposit.mintRecipient = depositHeader.mintRecipient;
// Emit Redeemed event.
emit Redeemed(vaa.emitterChainId, vaa.emitterAddress, vaa.sequence);
}

// getters
Expand All @@ -116,18 +120,22 @@ abstract contract Logic is ICircleIntegration, Governance {
pure
returns (DepositWithPayload memory deposit)
{
Deposit memory depositHeader;
(depositHeader, deposit.payload) = encoded.decodeDepositWithPayload(
false // revertCustomErrors
);

deposit.token = depositHeader.token;
deposit.amount = depositHeader.amount;
deposit.sourceDomain = depositHeader.sourceCctpDomain;
deposit.targetDomain = depositHeader.targetCctpDomain;
deposit.nonce = depositHeader.cctpNonce;
deposit.fromAddress = depositHeader.burnSource;
deposit.mintRecipient = depositHeader.mintRecipient;
// This is a hack to get around using the decodeDeposit method. This is not a real VM
// obviously.
//
// Plus, this getter should never be used in practice.
IWormhole.VM memory fakeVaa;
fakeVaa.payload = encoded;
(
deposit.token,
deposit.amount,
deposit.sourceDomain,
deposit.targetDomain,
deposit.nonce,
deposit.fromAddress,
deposit.mintRecipient,
deposit.payload
) = fakeVaa.decodeDeposit();
}

/// @inheritdoc ICircleIntegration
Expand All @@ -136,15 +144,15 @@ abstract contract Logic is ICircleIntegration, Governance {
pure
returns (bytes memory encoded)
{
encoded = Deposit({
token: message.token,
amount: message.amount,
sourceCctpDomain: message.sourceDomain,
targetCctpDomain: message.targetDomain,
cctpNonce: message.nonce,
burnSource: message.fromAddress,
mintRecipient: message.mintRecipient
}).encodeWithPayload(message.payload);
encoded = message.token.encodeDeposit(
message.amount,
message.sourceDomain,
message.targetDomain,
message.nonce,
message.fromAddress,
message.mintRecipient,
message.payload
);
}

/// @inheritdoc ICircleIntegration
Expand Down
Loading

0 comments on commit da622c5

Please sign in to comment.