Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PAM coverage #15

Merged
merged 4 commits into from
Jul 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified docs/imgs/auth-01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion solidity/src/Adapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ contract Adapter is IAdapter, Ownable {
0,
data
);

if (!success) emit ReceiveUserDataFailed();
}

Expand Down
27 changes: 15 additions & 12 deletions solidity/src/PAM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ contract PAM is Ownable, IPAM {
address public teeAddress;
address public teeAddressNew;
uint256 public teeAddressChangeGraceThreshold;
mapping(bytes32 => bytes32) emitters;
mapping(bytes32 => bytes32) public emitters;
mapping(bytes32 => bool) public pastEvents;

error InvalidEventRLP();
error InvalidTeeSigner();
error InvalidSignature();
error UnsetTeeSigner();
error GracePeriodNotElapsed();
error InvalidNewTeeSigner();
error AlreadyProcessed(bytes32 eventId);
Expand Down Expand Up @@ -56,6 +55,9 @@ contract PAM is Ownable, IPAM {
} else {
// The new address will be set after a grace period of 48 hours
teeAddressNew = _getAddressFromPublicKey(pubKey);

if (teeAddressNew == address(0)) revert InvalidNewTeeSigner();

teeAddressChangeGraceThreshold =
block.timestamp +
TEE_ADDRESS_CHANGE_GRACE_PERIOD;
Expand All @@ -82,7 +84,6 @@ contract PAM is Ownable, IPAM {
function applyNewTeeSigner() external {
if (block.timestamp < teeAddressChangeGraceThreshold)
revert GracePeriodNotElapsed();
if (teeAddressNew == address(0)) revert InvalidNewTeeSigner();

teeAddress = teeAddressNew;
teeAddressNew = address(0);
Expand Down Expand Up @@ -124,7 +125,8 @@ contract PAM is Ownable, IPAM {
// Event Bytes content (see _finalizeSwap() in Adapter)
// | nonce | erc20 | destination | amount | sender | recipientLen | recipient | data |
// | 32B | 32B | 32B | 32B | 32B | 32B | varlen | varlen |
uint256 offset = 32; // skip the nonce
uint256 offset = 32;
uint256 nonce = uint256(bytes32(content[0:offset]));
bytes32 erc20 = bytes32(content[offset:offset += 32]);
bytes32 destinationChainId = bytes32(content[offset:offset += 32]);
uint256 amount = uint256(bytes32(content[offset:offset += 32]));
Expand All @@ -135,8 +137,10 @@ contract PAM is Ownable, IPAM {
);
bytes memory data = content[offset:];

return (erc20 == operation.erc20 &&
return (nonce == operation.nonce &&
erc20 == operation.erc20 &&
destinationChainId == operation.destinationChainId &&
destinationChainId == bytes32(block.chainid) &&
amount == operation.amount &&
sender == operation.sender &&
recipient == operation.recipient &&
Expand All @@ -146,9 +150,7 @@ contract PAM is Ownable, IPAM {
function _contextChecks(
IAdapter.Operation memory operation,
Metadata calldata metadata
) internal view returns (bool) {
if (teeAddress == address(0)) return false;

) internal pure returns (bool) {
uint16 offset = 2; // skip protocol, version
bytes32 originChainId = bytes32(metadata.preimage[offset:offset += 32]);

Expand All @@ -157,7 +159,7 @@ contract PAM is Ownable, IPAM {
bytes32 blockId = bytes32(metadata.preimage[offset:offset += 32]);
bytes32 txId = bytes32(metadata.preimage[offset:offset += 32]);

if (blockId != operation.blockId && txId != operation.txId)
if (blockId != operation.blockId || txId != operation.txId)
return false;

return true;
Expand All @@ -172,6 +174,8 @@ contract PAM is Ownable, IPAM {
// | 1B | 1B | 32B | 32B | 32B | varlen |
// +----------- context ---------+------------- event ---------------+

if (teeAddress == address(0)) revert UnsetTeeSigner();

if (!_contextChecks(operation, metadata)) return (false, bytes32(0));
bytes32 eventId = sha256(metadata.preimage);

Expand All @@ -192,7 +196,6 @@ contract PAM is Ownable, IPAM {
return (false, eventId);

offset += 32; // skip sha256(topics) part

if (!_doesContentMatchOperation(eventPayload[offset:], operation))
return (false, eventId);

Expand Down
133 changes: 97 additions & 36 deletions solidity/test/forge/Helper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -155,62 +155,123 @@ abstract contract Helper is Test {
return address(iaddr);
}

function _getOperationFromRecordedLogs(
bytes32 originChainId,
bytes32 blockHash,
bytes32 txHash
) internal returns (IAdapter.Operation memory operation) {
return
_getOperationFromRecordedLogs(
originChainId,
blockHash,
txHash,
false
);
function _findLogWithTopic(
Vm.Log[] memory logs,
bytes32 topic
) internal pure returns (Vm.Log memory) {
uint256 i;
for (i = 0; i < logs.length; i++) {
if (logs[i].topics[0] == topic) break;
}

assert(i < logs.length);

return logs[i];
}

function _getOperationFromRecordedLogs(
bytes32 originChainId,
bytes32 blockHash,
bytes32 txHash,
function _getOperationFromLogs(
Vm.Log[] memory logs,
bytes32 topic,
bool print
) internal returns (IAdapter.Operation memory operation) {
Vm.Log[] memory entries = vm.getRecordedLogs();
uint256 last = entries.length - 1;
) internal returns (IAdapter.Operation memory) {
Vm.Log memory log = _findLogWithTopic(logs, topic);
vm.roll(4);
bytes32 blockHash = blockhash(block.number - 2);
bytes32 txHash = blockhash(block.number - 1);

if (print) {
console.log("////////////////////////////////");
console.log(entries[last].emitter); // address
console.log(vm.toString(entries[last].data)); // data
console.log(vm.toString(entries[last].topics[0])); // topic0
console.log(vm.toString(entries[last].topics[1])); // topic1
console.log(
string.concat(
"./attestator.js ",
"metadata ",
" -b ",
vm.toString(blockHash),
" -t ",
vm.toString(txHash),
" ",
vm.toString(log.emitter),
" ",
vm.toString(log.data),
" ",
vm.toString(log.topics[0]),
" ",
vm.toString(log.topics[1])
)
);
console.log("");
}

bytes memory content = abi
.decode(entries[last].data, (IAdapter.EventBytes))
bytes memory eventBytes = abi
.decode(log.data, (IAdapter.EventBytes))
.content;

uint256 recipientLen = uint256(
bytes32(BytesLib.slice(content, 160, 32))
bytes32(BytesLib.slice(eventBytes, 160, 32))
);

uint256 dataLen = content.length - recipientLen - 192;
uint256 dataLen = eventBytes.length - recipientLen - 192;
return
IAdapter.Operation(
blockHash,
txHash,
uint256(entries[last].topics[1]), // nonce
bytes32(BytesLib.slice(content, 32, 32)), // erc20
originChainId,
bytes32(BytesLib.slice(content, 64, 32)), // destination chain id
uint256(bytes32(BytesLib.slice(content, 96, 32))), // amount
bytes32(BytesLib.slice(content, 128, 32)), // sender
uint256(log.topics[1]), // nonce
bytes32(BytesLib.slice(eventBytes, 32, 32)), // erc20
bytes32(block.chainid),
bytes32(BytesLib.slice(eventBytes, 64, 32)), // destination chain id
uint256(bytes32(BytesLib.slice(eventBytes, 96, 32))), // amount
bytes32(BytesLib.slice(eventBytes, 128, 32)), // sender
_hexStringToAddress(
string(BytesLib.slice(content, 192, recipientLen)) // recipient
string(BytesLib.slice(eventBytes, 192, recipientLen)) // recipient
),
BytesLib.slice(content, 192 + recipientLen, dataLen) // data
BytesLib.slice(eventBytes, 192 + recipientLen, dataLen) // data
);
}

function _getOperationFromLogs(
Vm.Log[] memory logs,
bytes32 topic
) internal returns (IAdapter.Operation memory) {
return _getOperationFromLogs(logs, topic, false);
}

function _getMetadataFromLogs(
Vm.Log[] memory logs,
bytes32 topic,
IAdapter.Operation memory operation,
string memory privateKey
) internal view returns (IPAM.Metadata memory) {
Vm.Log memory log = _findLogWithTopic(logs, topic);

bytes1 version = 0x01;
bytes1 protocolId = 0x01;
bytes memory context = bytes.concat(
version,
protocolId,
bytes32(block.chainid)
);

bytes memory eventBytes = abi
.decode(log.data, (IAdapter.EventBytes))
.content;

bytes memory eventPayload = bytes.concat(
bytes32(abi.encode(log.emitter)),
sha256(bytes.concat(log.topics[0], log.topics[1])),
eventBytes
);

bytes memory preimage = bytes.concat(
context,
operation.blockId,
operation.txId,
eventPayload
);
uint256 pk = uint256(vm.parseBytes32(privateKey));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(pk, sha256(preimage));
bytes memory signature = abi.encodePacked(r, s, v);
return IPAM.Metadata(preimage, signature);
}

function _getEventId(
bytes memory metadataPreImage
) internal pure returns (bytes32) {
Expand Down
Loading
Loading