Skip to content

Commit da622c5

Browse files
committed
evm: enhance; fix Redeemed event
1 parent c43e1bf commit da622c5

11 files changed

+325
-359
lines changed

evm/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ forge-test: dependencies
3333

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

3838
.PHONY: gas-snapshot
3939
gas-snapshot: dependencies

evm/forge/tests/CircleIntegration.t.sol

+10-11
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {IWormhole} from "src/interfaces/IWormhole.sol";
1111
import {ICircleIntegration} from "src/interfaces/ICircleIntegration.sol";
1212

1313
import {Utils} from "src/libraries/Utils.sol";
14-
import {Deposit, WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
14+
import {WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
1515

1616
import {Setup} from "src/contracts/CircleIntegration/Setup.sol";
1717
import {Implementation} from "src/contracts/CircleIntegration/Implementation.sol";
@@ -239,17 +239,16 @@ contract CircleIntegrationTest is Test {
239239
assertEq(
240240
keccak256(fetchedPayloads[i]),
241241
keccak256(
242-
Deposit({
243-
token: USDC_ADDRESS.toUniversalAddress(),
244-
amount: amount,
245-
sourceCctpDomain: circleIntegration.circleBridge().localMessageTransmitter()
246-
.localDomain(),
247-
targetCctpDomain: targetDomain,
248-
cctpNonce: circleIntegration.circleBridge().localMessageTransmitter()
242+
USDC_ADDRESS.encodeDeposit(
243+
amount,
244+
circleIntegration.circleBridge().localMessageTransmitter().localDomain(),
245+
targetDomain,
246+
circleIntegration.circleBridge().localMessageTransmitter()
249247
.nextAvailableNonce() - 2 + uint64(i),
250-
burnSource: address(this).toUniversalAddress(),
251-
mintRecipient: mintRecipient
252-
}).encodeWithPayload(payloads[i])
248+
address(this).toUniversalAddress(),
249+
mintRecipient,
250+
payloads[i]
251+
)
253252
)
254253
);
255254
unchecked {

evm/forge/tests/InheritingWormholeCctp.t.sol

+11-11
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {ICircleIntegration} from "src/interfaces/ICircleIntegration.sol";
1111
import {IWormhole} from "src/interfaces/IWormhole.sol";
1212

1313
import {Utils} from "src/libraries/Utils.sol";
14-
import {Deposit, WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
14+
import {WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
1515

1616
import {Setup} from "src/contracts/CircleIntegration/Setup.sol";
1717
import {Implementation} from "src/contracts/CircleIntegration/Implementation.sol";
@@ -115,16 +115,16 @@ contract InheritingWormholeCctpTest is Test {
115115
assertEq(
116116
keccak256(fetchedPayloads[0]),
117117
keccak256(
118-
Deposit({
119-
token: USDC_ADDRESS.toUniversalAddress(),
120-
amount: amount,
121-
sourceCctpDomain: 0,
122-
targetCctpDomain: inheritedContract.myBffDomain(),
123-
cctpNonce: circleIntegration.circleBridge().localMessageTransmitter()
124-
.nextAvailableNonce() - 1,
125-
burnSource: address(this).toUniversalAddress(),
126-
mintRecipient: mintRecipient
127-
}).encodeWithPayload(payload)
118+
USDC_ADDRESS.encodeDeposit(
119+
amount,
120+
0, // sourceCctpDomain
121+
inheritedContract.myBffDomain(), // targetCctpDomain
122+
circleIntegration.circleBridge().localMessageTransmitter().nextAvailableNonce()
123+
- 1,
124+
address(this).toUniversalAddress(),
125+
mintRecipient,
126+
payload
127+
)
128128
)
129129
);
130130

evm/forge/tests/WormholeCctpMessages.t.sol

+41-16
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ pragma solidity ^0.8.19;
55
import "forge-std/Test.sol";
66
import "forge-std/console.sol";
77

8-
import {Deposit, WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
8+
import {IWormhole} from "src/interfaces/IWormhole.sol";
9+
10+
import {WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
911

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

27-
Deposit memory deposit = Deposit({
28-
token: token,
29-
amount: amount,
30-
sourceCctpDomain: sourceCctpDomain,
31-
targetCctpDomain: targetCctpDomain,
32-
cctpNonce: cctpNonce,
33-
burnSource: burnSource,
34-
mintRecipient: mintRecipient
35-
});
36-
37-
bytes memory encoded = deposit.encodeWithPayload(payload);
38-
assertEq(encoded.length, 147 + payload.length);
29+
IWormhole.VM memory fakeVaa;
30+
fakeVaa.payload = token.encodeDeposit(
31+
amount,
32+
sourceCctpDomain,
33+
targetCctpDomain,
34+
cctpNonce,
35+
burnSource,
36+
mintRecipient,
37+
payload
38+
);
39+
assertEq(fakeVaa.payload.length, 147 + payload.length);
3940

40-
uint8 payloadId = uint8(bytes1(encoded));
41+
uint8 payloadId = uint8(bytes1(fakeVaa.payload));
4142
assertEq(payloadId, 1);
4243

43-
(Deposit memory decoded, bytes memory takenPayload) = encoded.decodeDepositWithPayload();
44-
assertEq(keccak256(abi.encode(decoded)), keccak256(abi.encode(deposit)));
44+
bytes32 decodedToken;
45+
uint256 decodedAmount;
46+
uint32 decodedSourceCctpDomain;
47+
uint32 decodedTargetCctpDomain;
48+
uint64 decodedCctpNonce;
49+
bytes32 decodedBurnSource;
50+
bytes32 decodedMintRecipient;
51+
bytes memory takenPayload;
52+
(
53+
decodedToken,
54+
decodedAmount,
55+
decodedSourceCctpDomain,
56+
decodedTargetCctpDomain,
57+
decodedCctpNonce,
58+
decodedBurnSource,
59+
decodedMintRecipient,
60+
takenPayload
61+
) = fakeVaa.decodeDeposit();
62+
63+
assertEq(decodedToken, token);
64+
assertEq(decodedAmount, amount);
65+
assertEq(decodedSourceCctpDomain, sourceCctpDomain);
66+
assertEq(decodedTargetCctpDomain, targetCctpDomain);
67+
assertEq(decodedCctpNonce, cctpNonce);
68+
assertEq(decodedBurnSource, burnSource);
69+
assertEq(decodedMintRecipient, mintRecipient);
4570
assertEq(keccak256(abi.encode(takenPayload)), keccak256(abi.encode(payload)));
4671
}
4772
}

evm/forge/tests/gas/CircleIntegrationComparison.t.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {IWormhole} from "src/interfaces/IWormhole.sol";
1111
import {ICircleIntegration} from "src/interfaces/ICircleIntegration.sol";
1212

1313
import {Utils} from "src/libraries/Utils.sol";
14-
import {Deposit, WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
14+
import {WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
1515

1616
import {Setup} from "src/contracts/CircleIntegration/Setup.sol";
1717
import {Implementation} from "src/contracts/CircleIntegration/Implementation.sol";

evm/forge/tests/helpers/libraries/CircleIntegrationOverride.sol

+10-10
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {IWormhole} from "src/interfaces/IWormhole.sol";
77

88
import {BytesParsing} from "src/libraries/BytesParsing.sol";
99
import {Utils} from "src/libraries/Utils.sol";
10-
import {Deposit, WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
10+
import {WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
1111

1212
import "forge-std/Test.sol";
1313
import "forge-std/console.sol";
@@ -332,15 +332,15 @@ library CircleIntegrationOverride {
332332
vaaParams.emitterChain,
333333
burnMsg.messageSender,
334334
vaaParams.sequence,
335-
Deposit({
336-
token: burnMsg.burnToken,
337-
amount: burnMsg.amount,
338-
sourceCctpDomain: burnMsg.header.sourceDomain,
339-
targetCctpDomain: burnMsg.header.destinationDomain,
340-
cctpNonce: burnMsg.header.nonce,
341-
burnSource: burnSource,
342-
mintRecipient: burnMsg.mintRecipient
343-
}).encodeWithPayload(payload)
335+
burnMsg.burnToken.encodeDeposit(
336+
burnMsg.amount,
337+
burnMsg.header.sourceDomain,
338+
burnMsg.header.destinationDomain,
339+
burnMsg.header.nonce,
340+
burnSource,
341+
burnMsg.mintRecipient,
342+
payload
343+
)
344344
);
345345
}
346346

evm/src/contracts/CircleIntegration/Logic.sol

+47-39
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {ITokenMinter} from "src/interfaces/ITokenMinter.sol";
99
import {ICircleIntegration} from "src/interfaces/ICircleIntegration.sol";
1010

1111
import {Utils} from "src/libraries/Utils.sol";
12-
import {Deposit, WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
12+
import {WormholeCctpMessages} from "src/libraries/WormholeCctpMessages.sol";
1313

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

66-
uint16 chain;
67-
bytes32 emitter;
68-
bytes32 vaaHash;
69-
Deposit memory depositHeader;
70-
(chain, emitter, vaaHash, depositHeader, deposit.payload) =
71-
verifyVaaAndMintLegacy(params.cctpMessage, params.cctpAttestation, params.encodedVaa);
66+
IWormhole.VM memory vaa;
67+
(
68+
vaa,
69+
deposit.token,
70+
deposit.amount,
71+
deposit.sourceDomain,
72+
deposit.targetDomain,
73+
deposit.nonce,
74+
deposit.fromAddress,
75+
deposit.mintRecipient,
76+
deposit.payload
77+
) = verifyVaaAndMintLegacy(params.cctpMessage, params.cctpAttestation, params.encodedVaa);
7278

7379
// NOTE: Reverting with Error(string) comes from the old implementation, so we preserve it.
74-
require(emitter != 0 && emitter == getRegisteredEmitters()[chain], "unknown emitter");
80+
require(
81+
vaa.emitterAddress != 0
82+
&& vaa.emitterAddress == getRegisteredEmitters()[vaa.emitterChainId],
83+
"unknown emitter"
84+
);
7585

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

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

8494
// Mark as consumed.
85-
consumedVaas[vaaHash] = true;
95+
consumedVaas[vaa.hash] = true;
8696

87-
// Set remaining deposit vars.
88-
deposit.token = depositHeader.token;
89-
deposit.amount = depositHeader.amount;
90-
deposit.sourceDomain = depositHeader.sourceCctpDomain;
91-
deposit.targetDomain = depositHeader.targetCctpDomain;
92-
deposit.nonce = depositHeader.cctpNonce;
93-
deposit.fromAddress = depositHeader.burnSource;
94-
deposit.mintRecipient = depositHeader.mintRecipient;
97+
// Emit Redeemed event.
98+
emit Redeemed(vaa.emitterChainId, vaa.emitterAddress, vaa.sequence);
9599
}
96100

97101
// getters
@@ -116,18 +120,22 @@ abstract contract Logic is ICircleIntegration, Governance {
116120
pure
117121
returns (DepositWithPayload memory deposit)
118122
{
119-
Deposit memory depositHeader;
120-
(depositHeader, deposit.payload) = encoded.decodeDepositWithPayload(
121-
false // revertCustomErrors
122-
);
123-
124-
deposit.token = depositHeader.token;
125-
deposit.amount = depositHeader.amount;
126-
deposit.sourceDomain = depositHeader.sourceCctpDomain;
127-
deposit.targetDomain = depositHeader.targetCctpDomain;
128-
deposit.nonce = depositHeader.cctpNonce;
129-
deposit.fromAddress = depositHeader.burnSource;
130-
deposit.mintRecipient = depositHeader.mintRecipient;
123+
// This is a hack to get around using the decodeDeposit method. This is not a real VM
124+
// obviously.
125+
//
126+
// Plus, this getter should never be used in practice.
127+
IWormhole.VM memory fakeVaa;
128+
fakeVaa.payload = encoded;
129+
(
130+
deposit.token,
131+
deposit.amount,
132+
deposit.sourceDomain,
133+
deposit.targetDomain,
134+
deposit.nonce,
135+
deposit.fromAddress,
136+
deposit.mintRecipient,
137+
deposit.payload
138+
) = fakeVaa.decodeDeposit();
131139
}
132140

133141
/// @inheritdoc ICircleIntegration
@@ -136,15 +144,15 @@ abstract contract Logic is ICircleIntegration, Governance {
136144
pure
137145
returns (bytes memory encoded)
138146
{
139-
encoded = Deposit({
140-
token: message.token,
141-
amount: message.amount,
142-
sourceCctpDomain: message.sourceDomain,
143-
targetCctpDomain: message.targetDomain,
144-
cctpNonce: message.nonce,
145-
burnSource: message.fromAddress,
146-
mintRecipient: message.mintRecipient
147-
}).encodeWithPayload(message.payload);
147+
encoded = message.token.encodeDeposit(
148+
message.amount,
149+
message.sourceDomain,
150+
message.targetDomain,
151+
message.nonce,
152+
message.fromAddress,
153+
message.mintRecipient,
154+
message.payload
155+
);
148156
}
149157

150158
/// @inheritdoc ICircleIntegration

0 commit comments

Comments
 (0)