Skip to content

Commit

Permalink
evm: enhance
Browse files Browse the repository at this point in the history
* more optimizations

* add back Redeemed event

* fix .gas-snapshot-current
  • Loading branch information
a5-pickle committed Dec 20, 2023
1 parent f6ddc22 commit da4e4e1
Show file tree
Hide file tree
Showing 12 changed files with 361 additions and 382 deletions.
59 changes: 36 additions & 23 deletions evm/.gas-snapshot-current
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
CircleIntegrationTest:testCannotTransferTokensWithPayloadInvalidMintRecipient() (gas: 198357)
CircleIntegrationTest:testCannotTransferTokensWithPayloadInvalidToken() (gas: 415812)
CircleIntegrationTest:testCannotTransferTokensWithPayloadZeroAmount() (gas: 231859)
CircleIntegrationTest:testCannotTransferWithPayloadInvalidMintRecipient() (gas: 348241)
CircleIntegrationTest:testCannotTransferWithPayloadInvalidToken() (gas: 415430)
CircleIntegrationTest:testCannotTransferWithPayloadZeroAmount() (gas: 231355)
CircleIntegrationTest:testTransferTokensWithPayload(uint256,bytes32) (runs: 256, μ: 495138, ~: 495102)
CircleIntegrationTest:testTransferWithPayload(uint256,bytes32) (runs: 256, μ: 494306, ~: 494270)
GovernanceTest:testCannotConsumeGovernanceMessageInvalidAction(uint8,uint8) (runs: 256, μ: 79947, ~: 79947)
GovernanceTest:testCannotConsumeGovernanceMessageInvalidGovernanceChainId(uint16,uint8) (runs: 256, μ: 77947, ~: 77947)
GovernanceTest:testCannotConsumeGovernanceMessageInvalidGovernanceContract(bytes32,uint8) (runs: 256, μ: 78028, ~: 78028)
GovernanceTest:testCannotConsumeGovernanceMessageInvalidModule(bytes32,uint8) (runs: 256, μ: 79828, ~: 79828)
GovernanceTest:testCannotRegisterEmitterAndDomainInvalidDomain(uint16,bytes32) (runs: 256, μ: 114608, ~: 114608)
GovernanceTest:testCannotRegisterEmitterAndDomainInvalidEmitterAddress(uint16,uint32) (runs: 256, μ: 115229, ~: 115229)
GovernanceTest:testCannotRegisterEmitterAndDomainInvalidForeignChain(bytes32,uint32) (runs: 256, μ: 188094, ~: 188094)
GovernanceTest:testCannotRegisterEmitterAndDomainInvalidLength(uint16,bytes32,uint32) (runs: 256, μ: 116044, ~: 116044)
GovernanceTest:testCannotRegisterEmitterAndDomainInvalidTargetChain(uint16,uint16,bytes32,uint32) (runs: 256, μ: 115677, ~: 115677)
GovernanceTest:testCannotUpdateWormholeFinalityUnsupportedGovernanceAction(uint8) (runs: 256, μ: 52630, ~: 52630)
GovernanceTest:testCannotUpgradeContractInvalidImplementation(bytes12,address) (runs: 256, μ: 237587, ~: 237587)
GovernanceTest:testRegisterEmitterAndDomain(uint16,bytes32,uint32) (runs: 256, μ: 262308, ~: 262308)
GovernanceTest:testRegisterEmitterAndDomainNoTarget() (gas: 196595)
GovernanceTest:testUpgradeContract() (gas: 2499821)
MessagesTest:testDepositWithPayloadSerde(bytes32,uint256,uint32,uint32,uint64,bytes32,bytes32,bytes) (runs: 256, μ: 17925, ~: 17556)
CircleIntegrationComparison:test_Composed__RedeemUsdc(uint256,bytes32,bytes32) (runs: 256, μ: 271959, ~: 271835)
CircleIntegrationComparison:test_Composed__TransferUsdc(uint256,bytes32,bytes32) (runs: 256, μ: 393812, ~: 393808)
CircleIntegrationComparison:test_Control__RedeemTokensWithPayload(uint256,bytes32,bytes32) (runs: 256, μ: 73879, ~: 73746)
CircleIntegrationComparison:test_Control__TransferTokensWithPayload(uint256,bytes32,bytes32) (runs: 256, μ: 211909, ~: 211921)
CircleIntegrationComparison:test_Fork__RedeemTokensWithPayload(uint256,bytes32,bytes32) (runs: 256, μ: 278944, ~: 278895)
CircleIntegrationComparison:test_Fork__TransferTokensWithPayload(uint256,bytes32,bytes32) (runs: 256, μ: 369996, ~: 369998)
CircleIntegrationComparison:test_Inherited__RedeemUsdc(uint256,bytes32,bytes32) (runs: 256, μ: 230401, ~: 230271)
CircleIntegrationComparison:test_Inherited__TransferUsdc(uint256,bytes32,bytes32) (runs: 256, μ: 345229, ~: 345220)
CircleIntegrationComparison:test_Latest__RedeemTokensWithPayload(uint256,bytes32,bytes32) (runs: 256, μ: 255620, ~: 255666)
CircleIntegrationComparison:test_Latest__TransferTokensWithPayload(uint256,bytes32,bytes32) (runs: 256, μ: 361165, ~: 361164)
CircleIntegrationTest:test_CannotRedeemTokensWithPayloadCallerMustBeMintRecipient(address) (runs: 256, μ: 76122, ~: 76122)
CircleIntegrationTest:test_CannotRedeemTokensWithPayloadInvalidMessagePair() (gas: 95754)
CircleIntegrationTest:test_CannotRedeemTokensWithPayloadMintTokenNotSupported(bytes32) (runs: 256, μ: 143314, ~: 143314)
CircleIntegrationTest:test_CannotRedeemTokensWithPayloadUnknownEmitter(bytes32) (runs: 256, μ: 206424, ~: 206417)
CircleIntegrationTest:test_CannotTransferTokensWithPayloadInvalidMintRecipient() (gas: 247193)
CircleIntegrationTest:test_CannotTransferTokensWithPayloadInvalidToken() (gas: 250248)
CircleIntegrationTest:test_CannotTransferTokensWithPayloadTargetContractNotRegistered() (gas: 199868)
CircleIntegrationTest:test_CannotTransferTokensWithPayloadZeroAmount() (gas: 55797)
CircleIntegrationTest:test_RedeemTokensWithPayload() (gas: 244194)
CircleIntegrationTest:test_TransferTokensWithPayload(uint256,bytes32) (runs: 256, μ: 491809, ~: 491772)
GovernanceTest:test_CannotConsumeGovernanceMessageInvalidAction(uint8,uint8) (runs: 256, μ: 80055, ~: 80055)
GovernanceTest:test_CannotConsumeGovernanceMessageInvalidGovernanceChainId(uint16,uint8) (runs: 256, μ: 77936, ~: 77936)
GovernanceTest:test_CannotConsumeGovernanceMessageInvalidGovernanceContract(bytes32,uint8) (runs: 256, μ: 77665, ~: 77665)
GovernanceTest:test_CannotConsumeGovernanceMessageInvalidModule(bytes32,uint8) (runs: 256, μ: 79779, ~: 79779)
GovernanceTest:test_CannotRegisterEmitterAndDomainInvalidDomain(uint16,bytes32) (runs: 256, μ: 113833, ~: 113833)
GovernanceTest:test_CannotRegisterEmitterAndDomainInvalidEmitterAddress(uint16,uint32) (runs: 256, μ: 114714, ~: 114714)
GovernanceTest:test_CannotRegisterEmitterAndDomainInvalidForeignChain(bytes32,uint32) (runs: 256, μ: 187311, ~: 187311)
GovernanceTest:test_CannotRegisterEmitterAndDomainInvalidLength(uint16,bytes32,uint32) (runs: 256, μ: 115441, ~: 115441)
GovernanceTest:test_CannotRegisterEmitterAndDomainInvalidTargetChain(uint16,uint16,bytes32,uint32) (runs: 256, μ: 115162, ~: 115162)
GovernanceTest:test_CannotUpdateWormholeFinalityUnsupportedGovernanceAction(uint8) (runs: 256, μ: 52501, ~: 52501)
GovernanceTest:test_CannotUpgradeContractInvalidImplementation(bytes12,address) (runs: 256, μ: 237166, ~: 237166)
GovernanceTest:test_RegisterEmitterAndDomain(uint16,bytes32,uint32) (runs: 256, μ: 260950, ~: 260950)
GovernanceTest:test_RegisterEmitterAndDomainNoTarget() (gas: 196350)
GovernanceTest:test_UpgradeContract() (gas: 2387383)
InheritingWormholeCctpTest:test_TransferUsdc(uint256,bytes32) (runs: 256, μ: 364187, ~: 364148)
MessagesTest:test_DepositWithPayloadSerde(bytes32,uint256,uint32,uint32,uint64,bytes32,bytes32,bytes) (runs: 256, μ: 7871, ~: 7706)
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 da4e4e1

Please sign in to comment.