This repository was archived by the owner on Jun 20, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathFPValidator.sol
More file actions
143 lines (116 loc) · 5.93 KB
/
Copy pathFPValidator.sol
File metadata and controls
143 lines (116 loc) · 5.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
pragma abicoder v2;
import "./utility/LayerZeroPacket.sol";
import "../interfaces/ILayerZeroValidationLibrary.sol";
import "../interfaces/IValidationLibraryHelperV2.sol";
interface IStargate {
// Stargate objects for abi encoding / decoding
struct SwapObj {
uint amount;
uint eqFee;
uint eqReward;
uint lpFee;
uint protocolFee;
uint lkbRemove;
}
struct CreditObj {
uint credits;
uint idealBalance;
}
}
contract FPValidator is ILayerZeroValidationLibrary, IValidationLibraryHelperV2 {
uint8 public proofType = 2;
uint8 public utilsVersion = 1;
address public immutable stargateBridgeAddress;
address public immutable stargateTokenAddress;
constructor(address _stargateBridgeAddress, address _stargateTokenAddress) {
stargateBridgeAddress = _stargateBridgeAddress;
stargateTokenAddress = _stargateTokenAddress;
}
function validateProof(bytes32 _packetHash, bytes calldata _transactionProof, uint _remoteAddressSize) external view override returns (LayerZeroPacket.Packet memory packet) {
require(_remoteAddressSize > 0, "ProofLib: invalid address size");
// _transactionProof = srcUlnAddress (32 bytes) + lzPacket
require(_transactionProof.length > 32 && keccak256(_transactionProof) == _packetHash, "ProofLib: invalid transaction proof");
bytes memory ulnAddressBytes = bytes(_transactionProof[0:32]);
bytes32 ulnAddress;
assembly {
ulnAddress := mload(add(ulnAddressBytes, 32))
}
packet = LayerZeroPacket.getPacketV3(_transactionProof[32:], _remoteAddressSize, ulnAddress);
if (packet.dstAddress == stargateBridgeAddress) packet.payload = _secureStgPayload(packet.payload);
if (packet.dstAddress == stargateTokenAddress) packet.payload = _secureStgTokenPayload(packet.payload);
return packet;
}
function _secureStgTokenPayload(bytes memory _payload) internal pure returns (bytes memory) {
(bytes memory toAddressBytes, uint qty) = abi.decode(_payload, (bytes, uint));
address toAddress = address(0);
if (toAddressBytes.length > 0) {
assembly {
toAddress := mload(add(toAddressBytes, 20))
}
}
if (toAddress == address(0)) {
address deadAddress = address(0x000000000000000000000000000000000000dEaD);
bytes memory newToAddressBytes = abi.encodePacked(deadAddress);
return abi.encode(newToAddressBytes, qty);
}
// default to return the original payload
return _payload;
}
function _secureStgPayload(bytes memory _payload) internal view returns (bytes memory) {
// functionType is uint8 even though the encoding will take up the side of uint256
uint8 functionType;
assembly {
functionType := mload(add(_payload, 32))
}
// TYPE_SWAP_REMOTE == 1 && only if the payload has a payload
// only swapRemote inside of stargate can call sgReceive on a user supplied to address
// thus we do not care about the other type functions even if the toAddress is overly long.
if (functionType == 1) {
// decode the _payload with its types
(, uint srcPoolId, uint dstPoolId, uint dstGasForCall, IStargate.CreditObj memory c, IStargate.SwapObj memory s, bytes memory toAddressBytes, bytes memory contractCallPayload) = abi.decode(_payload, (uint8, uint, uint, uint, IStargate.CreditObj, IStargate.SwapObj, bytes, bytes));
// if contractCallPayload.length > 0 need to check if the to address is a contract or not
if (contractCallPayload.length > 0) {
// otherwise, need to check if the payload can be delivered to the toAddress
address toAddress = address(0);
if (toAddressBytes.length > 0) {
assembly {
toAddress := mload(add(toAddressBytes, 20))
}
}
// check if the toAddress is a contract. We are not concerned about addresses that pretend to be wallets. because worst case we just delete their payload if being malicious
// we can guarantee that if a size > 0, then the contract is definitely a contract address in this context
uint size;
assembly {
size := extcodesize(toAddress)
}
if (size == 0) {
// size == 0 indicates its not a contract, payload wont be delivered
// secure the _payload to make sure funds can be delivered to the toAddress
bytes memory newToAddressBytes = abi.encodePacked(toAddress);
bytes memory securePayload = abi.encode(functionType, srcPoolId, dstPoolId, dstGasForCall, c, s, newToAddressBytes, bytes(""));
return securePayload;
}
}
}
// default to return the original payload
return _payload;
}
function secureStgTokenPayload(bytes memory _payload) external pure returns (bytes memory) {
return _secureStgTokenPayload(_payload);
}
function secureStgPayload(bytes memory _payload) external view returns (bytes memory) {
return _secureStgPayload(_payload);
}
function getUtilsVersion() external view override returns (uint8) {
return utilsVersion;
}
function getProofType() external view override returns (uint8) {
return proofType;
}
function getVerifyLog(bytes32, uint[] calldata, uint, bytes[] calldata proof) external pure override returns (ULNLog memory log) {}
function getPacket(bytes memory data, uint sizeOfSrcAddress, bytes32 ulnAddress) external pure override returns (LayerZeroPacket.Packet memory) {
return LayerZeroPacket.getPacketV3(data, sizeOfSrcAddress, ulnAddress);
}
}