Skip to content

Commit

Permalink
Merge pull request #50 from catalystdao/documentation-updates
Browse files Browse the repository at this point in the history
Update Documentation
  • Loading branch information
reednaa authored May 15, 2024
2 parents fdda9c6 + fdb2057 commit ac8754b
Show file tree
Hide file tree
Showing 18 changed files with 277 additions and 175 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Contracts within this repo have not been audited and should not be used in production.
This repository has been audited 3 times, twice by Veridise and once by Ackee. You can find the audits in `/audits`.

# Generalised Incentive Escrow

Expand Down
2 changes: 1 addition & 1 deletion script/BaseMultiChainDeployer.s.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
pragma solidity ^0.8.22;

import "forge-std/Script.sol";

Expand Down
4 changes: 2 additions & 2 deletions script/Deploy.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
pragma solidity ^0.8.22;

import "forge-std/Script.sol";
import {stdJson} from "forge-std/StdJson.sol";
Expand Down Expand Up @@ -159,7 +159,7 @@ contract DeployGeneralisedIncentives is BaseMultiChainDeployer {
}

function deployEscrow(string[] memory bridges) forEachBridge(bridges) internal {
address escrow = deployGeneralisedIncentives(incentiveVersion);
deployGeneralisedIncentives(incentiveVersion);
}

function _deploy(string[] memory bridges) internal {
Expand Down
361 changes: 219 additions & 142 deletions src/IncentivizedMessageEscrow.sol

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/apps/polymer/APolymerEscrow.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
pragma solidity ^0.8.22;

import {IncentivizedMessageEscrow} from "../../IncentivizedMessageEscrow.sol";
import "../../MessagePayload.sol";
Expand Down
2 changes: 1 addition & 1 deletion src/apps/polymer/vIBCEscrow.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
pragma solidity ^0.8.22;

import { APolymerEscrow } from "./APolymerEscrow.sol";
import "../../MessagePayload.sol";
Expand Down
35 changes: 28 additions & 7 deletions src/apps/wormhole/IncentivizedWormholeEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,20 @@ import { SmallStructs } from "./external/callworm/SmallStructs.sol";
import { WormholeVerifier } from "./external/callworm/WormholeVerifier.sol";
import { IWormhole } from "./interfaces/IWormhole.sol";

// This is a mock contract which should only be used for testing.
/**
* @title Incentivized Wormhole Message Escrow
* @notice Incentivizes Wormhole messages through Generalised Incentives.
* Wormhole does not have any native way of relaying messages, this implemention adds one.
*
* When using Wormhole with Generalised Incentives and you don't want to lose message, be very careful regarding
* emitting messages to destinationChainIdentifiers that does not exist. Wormhole has no way to verify if a
* chain identifier exists or not. If the chain identifier does not exist, it is not possible to get a timeout or ack back.
*
* @dev This implementation only uses the Wormhole contracts to emit messages, it does not use the Wormhole contracts
* to verify if messages are authentic. A custom verification library is used that is more gas efficient and skips
* parts of the VAA that is not relevant to us. This provides significant gas savings compared to verifying packages
* against the Wormhole implementation.
*/
contract IncentivizedWormholeEscrow is IncentivizedMessageEscrow, WormholeVerifier {
error BadChainIdentifier();

Expand All @@ -32,6 +45,7 @@ contract IncentivizedWormholeEscrow is IncentivizedMessageEscrow, WormholeVerifi
amount = WORMHOLE.messageFee();
}

/** @notice Wormhole proofs are valid until the guardian set is changed. The new guradian set may sign a new VAA */
function _proofValidPeriod(bytes32 /* destinationIdentifier */) override internal pure returns(uint64) {
return 0;
}
Expand All @@ -40,25 +54,29 @@ contract IncentivizedWormholeEscrow is IncentivizedMessageEscrow, WormholeVerifi
return sourceIdentifier = UNIQUE_SOURCE_IDENTIFIER;
}

/** @dev _message is the entire Wormhole VAA. It contains both the proof & the message as a slice. */
function _verifyPacket(bytes calldata /* _metadata */, bytes calldata _message) internal view override returns(bytes32 sourceIdentifier, bytes memory implementationIdentifier, bytes calldata message_) {

// Decode & verify the VAA.
// This uses the custom verification logic found in ./external/callworm/WormholeVerifier.sol.
(
SmallStructs.SmallVM memory vm,
bytes calldata payload,
bool valid,
string memory reason
) = parseAndVerifyVM(_message);

// This is the preferred flow used by Wormhole.
require(valid, reason);


// Local "supposedly" this chain identifier.
bytes32 thisChainIdentifier = bytes32(payload[0:32]);
// We added the destination chain to the payload since Wormhole messages are broadcast.
// Get the chain identifier for the destination chain according to the payload.
bytes32 destinationChainIdentifier = bytes32(payload[0:32]);

// Check that the message is intended for this chain.
if (thisChainIdentifier != UNIQUE_SOURCE_IDENTIFIER) revert BadChainIdentifier();
if (destinationChainIdentifier != UNIQUE_SOURCE_IDENTIFIER) revert BadChainIdentifier();

// Local the identifier for the source chain.
// Get the identifier for the source chain.
sourceIdentifier = bytes32(uint256(vm.emitterChainId));

// Load the identifier for the calling contract.
Expand All @@ -68,11 +86,14 @@ contract IncentivizedWormholeEscrow is IncentivizedMessageEscrow, WormholeVerifi
message_ = payload[32:];
}

/**
* @dev Wormhole messages are broadcast, as a result we set destinationChainIdentifier in the message.
*/
function _sendPacket(bytes32 destinationChainIdentifier, bytes memory /* destinationImplementation */, bytes memory message, uint64 /* deadline */) internal override returns(uint128 costOfsendPacketInNativeToken) {
// Get the cost of sending wormhole messages.
costOfsendPacketInNativeToken = uint128(WORMHOLE.messageFee());

// Relayers can collect the destination chain from the payload and destination address from storage.
// Relayers can collect the destination chain from the payload and destinationImplementation from storage / their whitelist.

// Handoff the message to wormhole.
WORMHOLE.publishMessage{value: costOfsendPacketInNativeToken}(
Expand Down
2 changes: 1 addition & 1 deletion src/apps/wormhole/external/callworm/README.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
This is an alternative implementation of the wormhole message verification with the purpose of significantly reducing gas cost but also simplify integration by always keeping the message in calldata.
This is an alternative implementation of the wormhole message verification with the purpose of significantly reducing gas cost but also simplify integration by decoding the message as a calldata slice.
4 changes: 4 additions & 0 deletions src/apps/wormhole/external/callworm/WormholeVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import "./SmallStructs.sol";
import "../wormhole/libraries/external/BytesLib.sol";


/**
* @notice Optimised message verifier for Wormhole
* @dev Is based on the Wormhole verification library.
*/
contract WormholeVerifier is GettersGetter {
using BytesLib for bytes;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ contract EscrowInformationTest is TestCommon {
IncentiveDescription storage incentive = _INCENTIVE;
incentive.refundGasTo = address(0);
vm.expectRevert();
(, bytes32 messageIdentifier) = escrow.submitMessage{value: _getTotalIncentive(_INCENTIVE)}(
escrow.submitMessage{value: _getTotalIncentive(_INCENTIVE)}(
bytes32(uint256(0x123123) + uint256(2**255)),
_DESTINATION_ADDRESS_THIS,
_MESSAGE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ contract AckReentryTest is TestCommon, ICrossChainReceiver {

bool flag;

function receiveAck(bytes32 /* destinationIdentifier */, bytes32 /* messageIdentifier */, bytes calldata acknowledgement) external {
function receiveAck(bytes32 /* destinationIdentifier */, bytes32 /* messageIdentifier */, bytes calldata /* acknowledgement */) external {
vm.expectRevert(
abi.encodeWithSignature("MessageAlreadyAcked()")
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ contract CallReentryTest is TestCommon, ICrossChainReceiver {
bool flag;

// Receive the message and reentry.
function receiveMessage(bytes32 /* sourceIdentifierbytes */, bytes32 /* messageIdentifier */, bytes calldata /* fromApplication */, bytes calldata message) external returns(bytes memory acknowledgement) {
function receiveMessage(bytes32 /* sourceIdentifierbytes */, bytes32 /* messageIdentifier */, bytes calldata /* fromApplication */, bytes calldata /* message */) external returns(bytes memory acknowledgement) {
vm.expectRevert(
abi.encodeWithSignature("MessageAlreadySpent()")
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ contract sendPacketPaymentTest is TestCommon {
IncentiveDescription storage incentive = _INCENTIVE;

vm.recordLogs();
(, bytes32 messageIdentifier) = escrow.submitMessage{value: _getTotalIncentive(_INCENTIVE) + SEND_MESSAGE_PAYMENT_COST}(
escrow.submitMessage{value: _getTotalIncentive(_INCENTIVE) + SEND_MESSAGE_PAYMENT_COST}(
bytes32(uint256(0x123123) + uint256(2**255)),
_DESTINATION_ADDRESS_THIS,
_MESSAGE,
Expand Down Expand Up @@ -103,7 +103,7 @@ contract sendPacketPaymentTest is TestCommon {
IncentiveDescription storage incentive = _INCENTIVE;

vm.recordLogs();
(, bytes32 messageIdentifier) = escrow.submitMessage{value: _getTotalIncentive(_INCENTIVE) + SEND_MESSAGE_PAYMENT_COST}(
escrow.submitMessage{value: _getTotalIncentive(_INCENTIVE) + SEND_MESSAGE_PAYMENT_COST}(
bytes32(uint256(0x123123) + uint256(2**255)),
_DESTINATION_ADDRESS_THIS,
_MESSAGE,
Expand Down Expand Up @@ -132,7 +132,7 @@ contract sendPacketPaymentTest is TestCommon {
IncentiveDescription storage incentive = _INCENTIVE;

vm.recordLogs();
(, bytes32 messageIdentifier) = escrow.submitMessage{value: _getTotalIncentive(_INCENTIVE) + SEND_MESSAGE_PAYMENT_COST}(
escrow.submitMessage{value: _getTotalIncentive(_INCENTIVE) + SEND_MESSAGE_PAYMENT_COST}(
bytes32(uint256(0x123123) + uint256(2**255)),
_DESTINATION_ADDRESS_THIS,
_MESSAGE,
Expand Down Expand Up @@ -180,7 +180,7 @@ contract sendPacketPaymentTest is TestCommon {
vm.warp(1000000);
IncentiveDescription storage incentive = _INCENTIVE;

(, bytes32 messageIdentifier) = escrow.submitMessage{value: _getTotalIncentive(_INCENTIVE) + SEND_MESSAGE_PAYMENT_COST}(
escrow.submitMessage{value: _getTotalIncentive(_INCENTIVE) + SEND_MESSAGE_PAYMENT_COST}(
bytes32(uint256(0x123123) + uint256(2**255)),
_DESTINATION_ADDRESS_THIS,
_MESSAGE,
Expand Down
Empty file.
2 changes: 1 addition & 1 deletion test/wormhole/(wh)messages.t.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// test/Messages.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;
pragma solidity ^0.8.22;

import "../../src/apps/wormhole/external/wormhole/Messages.sol";
import "../../src/apps/wormhole/external/wormhole/Setters.sol";
Expand Down
6 changes: 3 additions & 3 deletions test/wormhole/roundtrip.t.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// test/Messages.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;
pragma solidity ^0.8.22;

import "../../src/apps/wormhole/external/wormhole/Messages.sol";
import "../../src/apps/wormhole/external/wormhole/Setters.sol";
Expand Down Expand Up @@ -100,7 +100,7 @@ contract TestRoundtrip is Test, IMessageEscrowStructs, Bytes65 {
messages.storeGuardianSetPub(initialGuardianSet, uint32(0));
}

function makeValidVM(bytes memory payload, uint16 emitterChainid, bytes32 emitterAddress) internal returns(bytes memory validVM) {
function makeValidVM(bytes memory payload, uint16 emitterChainid, bytes32 emitterAddress) view internal returns(bytes memory validVM) {
bytes memory presigsVM = abi.encodePacked(
uint8(1), // version
uint32(0), // guardianSetIndex
Expand Down Expand Up @@ -132,7 +132,7 @@ contract TestRoundtrip is Test, IMessageEscrowStructs, Bytes65 {
IncentiveDescription storage incentive = _INCENTIVE;

vm.recordLogs();
(uint256 gasRefund, bytes32 messageIdentifier) = escrow.submitMessage{value: _getTotalIncentive(_INCENTIVE)}(
escrow.submitMessage{value: _getTotalIncentive(_INCENTIVE)}(
_DESTINATION_IDENTIFIER,
convertEVMTo65(address(this)),
message,
Expand Down
8 changes: 4 additions & 4 deletions test/wormhole/verifyMessage2.t.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// test/Messages.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;
pragma solidity ^0.8.22;

import "../../src/apps/wormhole/external/wormhole/Messages.sol";
import "../../src/apps/wormhole/external/wormhole/Setters.sol";
Expand Down Expand Up @@ -129,10 +129,10 @@ contract TestMessagesC2Sigs is Test {
bytes memory invalidVM = abi.encodePacked(validVM, uint8(1));

// Confirm that the test VM is valid
(Structs.VM memory parsedInValidVm, bool valid, string memory reason) = messages.parseAndVerifyVM(invalidVM);
(, bool valid, string memory reason) = messages.parseAndVerifyVM(invalidVM);
(
SmallStructs.SmallVM memory smallVM,
bytes memory payload,
,
,
bool valid2,
string memory reason2
) = messages2.parseAndVerifyVM(invalidVM);
Expand Down
8 changes: 4 additions & 4 deletions test/wormhole/verifyMessages.t.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// test/Messages.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;
pragma solidity ^0.8.22;

import "../../src/apps/wormhole/external/wormhole/Messages.sol";
import "../../src/apps/wormhole/external/wormhole/Setters.sol";
Expand Down Expand Up @@ -105,10 +105,10 @@ contract TestMessagesC is Test {
bytes memory invalidVM = abi.encodePacked(validVM, uint8(1));

// Confirm that the test VM is valid
(Structs.VM memory parsedInValidVm, bool valid, string memory reason) = messages.parseAndVerifyVM(invalidVM);
(, bool valid, string memory reason) = messages.parseAndVerifyVM(invalidVM);
(
SmallStructs.SmallVM memory smallVM,
bytes memory payload,
,
,
bool valid2,
string memory reason2
) = messages2.parseAndVerifyVM(invalidVM);
Expand Down

0 comments on commit ac8754b

Please sign in to comment.