11// SPDX-License-Identifier: MIT
22
33/**
4- * @authors: [@shalzz*, @hrishibhat]
4+ * @authors: [@shalzz*, @hrishibhat*, @shotaronowhere ]
55 * @reviewers: []
66 * @auditors: []
77 * @bounties: []
@@ -25,9 +25,9 @@ contract FastBridgeReceiver is IFastBridgeReceiver {
2525
2626 struct Claim {
2727 address bridger;
28+ bytes32 messageHash;
2829 uint256 claimedAt;
2930 uint256 claimDeposit;
30- bool relayed;
3131 bool honest;
3232 }
3333
@@ -38,12 +38,13 @@ contract FastBridgeReceiver is IFastBridgeReceiver {
3838 bool honest;
3939 }
4040
41- // messageHash => Claim
42- mapping (bytes32 => Claim) public claims;
43- mapping (bytes32 => Challenge) public challenges;
41+ // fastMessageIndex => Claim[]
42+ mapping (uint256 => Claim[]) public claims;
43+ mapping (uint256 => Challenge[]) public challenges;
44+ mapping (uint256 => bool ) public relayed;
4445
45- event ClaimReceived (bytes32 messageHash , uint256 claimedAt );
46- event ClaimChallenged (bytes32 messageHash , uint256 challengedAt );
46+ event ClaimReceived (uint256 _fastMessageIndex , bytes32 _messageHash , uint256 claimedAt );
47+ event ClaimChallenged (uint256 _fastMessageIndex , uint256 _claimIndex , bytes32 _messageHash , uint256 challengedAt );
4748
4849 modifier onlyByGovernor () {
4950 require (governor == msg .sender , "Access not allowed: Governor only. " );
@@ -66,136 +67,170 @@ contract FastBridgeReceiver is IFastBridgeReceiver {
6667 challengeDuration = _challengeDuration;
6768 }
6869
69- function claim (bytes32 _messageHash ) external payable {
70+ function claim (uint256 _fastMessageIndex , bytes32 _messageHash ) external payable override {
7071 require (msg .value >= claimDeposit, "Not enough claim deposit " );
71- require (claims[_messageHash].bridger == address (0 ), "Claimed already made " );
72+ require (relayed[_fastMessageIndex] == false , "Message already relayed. " );
73+ // only accept additional claims if the previous claims are successfully challenged
74+ // AND the message is not yet relayed
75+ require (claims[_fastMessageIndex].length == 0 || challenges[_fastMessageIndex][claims[_fastMessageIndex].length -1 ].honest, "There is a previous unresolved claim " );
7276
73- claims[_messageHash] = Claim ({
77+ claims[_fastMessageIndex]. push ( Claim ({
7478 bridger: msg .sender ,
79+ messageHash: _messageHash,
7580 claimedAt: block .timestamp ,
7681 claimDeposit: msg .value ,
77- honest: false ,
78- relayed: false
79- });
82+ honest: false
83+ }));
8084
81- emit ClaimReceived (_messageHash, block .timestamp );
85+ emit ClaimReceived (_fastMessageIndex, _messageHash, block .timestamp );
8286 }
8387
84- function verifyAndRelay (bytes32 _messageHash , bytes memory _encodedData ) external {
88+ function verifyAndRelay (uint _fastMessageIndex , bytes memory _encodedData ) external override {
89+
90+ Claim[] storage claimsForIndex = claims[_fastMessageIndex];
91+ require (claimsForIndex.length > 0 , "Claim does not exist " );
92+
8593
86- Claim storage claim = claims[_messageHash];
87- require (claim.bridger != address (0 ), "Claim does not exist " );
88- require (claim.claimedAt + challengeDuration < block .timestamp , "Challenge period not over " );
89- require (claim.relayed == false , "Message already relayed " );
94+ require (claimsForIndex[claimsForIndex.length -1 ].claimedAt + challengeDuration < block .timestamp , "Challenge period not over " );
95+ require (relayed[_fastMessageIndex] == false , "Message already relayed " );
9096
91- Challenge storage challenge = challenges[_messageHash];
92- require (challenge.challenger == address (0 ), "This claim is Challenged " );
97+ Challenge[] storage challengesForIndex = challenges[_fastMessageIndex];
9398
94- if (keccak256 (_encodedData) == _messageHash){
95- claim.honest = true ;
99+ require (challengesForIndex.length < claimsForIndex.length , "This claim is Challenged " );
100+
101+ if (keccak256 (_encodedData) == claimsForIndex[claimsForIndex.length -1 ].messageHash){
102+ claimsForIndex[claimsForIndex.length -1 ].honest = true ;
96103 // Decode the receiver address from the data encoded by the IFastBridgeSender
97104 (address receiver , bytes memory data ) = abi.decode (_encodedData, (address , bytes ));
98105 (bool success , ) = address (receiver).call (data);
99106 require (success, "Failed to call contract " );
100107
101- claim. relayed = true ;
108+ relayed[_fastMessageIndex] = true ;
102109 }
103110
104111 }
105112
106- function relayRule (bytes memory _encodedData ) external {
113+ function relayRule (bytes memory _encodedData ) external override {
107114 IBridge bridge = inbox.bridge ();
108115 require (msg .sender == address (bridge), "Not called by the Bridge " );
109116
110117 IOutbox outbox = IOutbox (inbox.bridge ().activeOutbox ());
111118 address l2Sender = outbox.l2ToL1Sender ();
112119 require (l2Sender == safebridge, "Can be relayed only by Safe Bridge " );
113120
114- bytes32 _messageHash = keccak256 (_encodedData);
115- Challenge storage challenge = challenges[_messageHash];
116- Claim storage claim = claims[_messageHash];
117- require (claim.relayed != true , "Claim already relayed " );
118-
119- if (claim.bridger != address (0 ) && challenge.challenger != address (0 )) {
120- challenge.honest = false ;
121- claim.honest = true ;
122- } else {
123- challenge.honest = true ;
124- claim.honest = false ;
125- }
121+ (uint256 _fastMessageIndex , bytes memory dataWithReceiver ) = abi.decode (_encodedData, (uint256 , bytes ));
122+ bytes32 messageHash = keccak256 (dataWithReceiver);
126123
127- // Decode the receiver address from the data encoded by the IFastBridgeSender
128- (address receiver , bytes memory data ) = abi.decode (_encodedData, (address , bytes ));
129- (bool success , ) = address (receiver).call (data);
130- require (success, "Failed to call contract " );
124+ require (relayed[_fastMessageIndex] != true , "Claim already relayed " );
131125
132- claim.relayed = true ;
126+ Claim[] storage claimsForIndex = claims[_fastMessageIndex];
127+ Challenge[] storage challengesForIndex = challenges[_fastMessageIndex];
128+
129+ if (claimsForIndex.length > 0 ){
130+ // has claims
131+ if (claimsForIndex[claimsForIndex.length -1 ].messageHash == messageHash){
132+ claimsForIndex[claimsForIndex.length -1 ].honest = true ;
133+ } else if (challengesForIndex.length > 0 ){
134+ // has challenges
135+ challengesForIndex[challengesForIndex.length - 1 ].honest = true ;
136+ }
137+ } else {
138+ // no claims, no challenges
139+ }
140+ // dispute ruled
141+ if (dataWithReceiver.length != 0 ){
142+ // Decode the receiver address from the data encoded by the IFastBridgeSender
143+ (address receiver , bytes memory data ) = abi.decode (dataWithReceiver, (address , bytes ));
144+ (bool success , ) = address (receiver).call (data);
145+ require (success, "Failed to call contract " );
146+
147+ relayed[_fastMessageIndex] = true ;
148+ }
149+
133150
134151 }
135152
136- function withdrawClaimDeposit (bytes32 _messageHash ) external {
137- Claim storage claim = claims[_messageHash];
138- require (claim.bridger != address (0 ), "Claim does not exist " );
139- require (claim.claimedAt + challengeDuration < block .timestamp , "Challenge period not over " );
140- require (claim.relayed == true , "Claim not relayed " );
141-
142- Challenge storage challenge = challenges[_messageHash];
143- uint256 amount = claim.claimDeposit;
144- if (challenge.honest == false ){
145- amount += challenge.challengeDeposit;
146- challenge.challengeDeposit = 0 ;
153+ function withdrawClaimDeposit (uint256 _fastMessageIndex ) external override {
154+ Claim[] storage claimsForIndex = claims[_fastMessageIndex];
155+ require (claimsForIndex.length > 0 , "Claim does not exist " );
156+
157+
158+ require (claimsForIndex[claimsForIndex.length -1 ].claimedAt + challengeDuration < block .timestamp , "Challenge period not over " );
159+ require (relayed[_fastMessageIndex] == true , "Claim not relayed " );
160+
161+ Challenge[] storage challengesForIndex = challenges[_fastMessageIndex];
162+
163+ uint256 amount = 0 ;
164+ if (claimsForIndex[claimsForIndex.length -1 ].honest == true ){
165+ amount += claimsForIndex[claimsForIndex.length -1 ].claimDeposit;
166+ if (challengesForIndex.length == claimsForIndex.length ){
167+ if (challengesForIndex[challengesForIndex.length - 1 ].honest == false ){
168+ amount += challengesForIndex[challengesForIndex.length - 1 ].challengeDeposit;
169+ challengesForIndex[challengesForIndex.length - 1 ].challengeDeposit = 0 ;
170+ }
171+ }
147172 }
148173
149- claim .claimDeposit = 0 ;
150- payable (claim .bridger).send (amount);
174+ claimsForIndex[claimsForIndex. length -1 ] .claimDeposit = 0 ;
175+ payable (claimsForIndex[claimsForIndex. length -1 ] .bridger).send (amount);
151176 }
152177
153- function challenge (bytes32 _messageHash ) external payable {
154- Claim memory claim = claims[_messageHash];
155- require (claim.bridger != address (0 ), "Claim does not exist " );
156- require (block .timestamp - claim.claimedAt < challengeDuration, "Challenge period over " );
178+ function challenge (uint256 _fastMessageIndex ) external payable {
179+ Claim[] memory claimsForIndex = claims[_fastMessageIndex];
180+ require (claimsForIndex.length > 0 , "Claim does not exist " );
181+ require (relayed[_fastMessageIndex] == false , "Message already relayed " );
182+ require (block .timestamp - claimsForIndex[claimsForIndex.length -1 ].claimedAt < challengeDuration, "Challenge period over " );
157183 require (msg .value >= challengeDeposit, "Not enough challenge deposit " );
158- require (challenges[_messageHash].challenger == address ( 0 ) , "Claim already challenged " );
184+ require (challenges[_fastMessageIndex]. length < claimsForIndex. length , "Claim already challenged " );
159185
160- challenges[_messageHash] = Challenge ({
186+ challenges[_fastMessageIndex]. push ( Challenge ({
161187 challenger: msg .sender ,
162188 challengedAt: block .timestamp ,
163189 challengeDeposit: msg .value ,
164190 honest: false
165- });
191+ })) ;
166192
167- emit ClaimChallenged (_messageHash , block .timestamp );
193+ emit ClaimChallenged (_fastMessageIndex,claimsForIndex. length -1 , claimsForIndex[claimsForIndex. length -1 ].messageHash , block .timestamp );
168194 }
169195
170- function withdrawChallengeDeposit (bytes32 _messageHash ) external {
171- Challenge storage challenge = challenges[_messageHash];
172- require (challenge.challenger != address (0 ), "Challenge does not exist " );
173- require (challenge.honest == true , "Challenge not honest " );
196+ function withdrawChallengeDeposit (uint256 _fastMessageIndex , uint256 challengeIndex ) external {
197+ Challenge[] storage challengesForIndex = challenges[_fastMessageIndex];
198+ require (challengesForIndex.length > 0 && challengeIndex < challengesForIndex.length , "Challenge does not exist " );
174199
175- Claim storage claim = claims[_messageHash];
176- require (block .timestamp > claim.claimedAt + challengeDuration, "Challenge period not over " );
177- require (claim.relayed == true , "Claim not relayed " );
200+ Claim[] storage claimsForIndex = claims[_fastMessageIndex];
178201
179- uint256 amount = challenge.challengeDeposit;
180- if (claim.honest == false ){
181- amount += claim.claimDeposit;
182- claim.claimDeposit = 0 ;
202+ uint256 amount = 0 ;
203+ if (challengesForIndex[challengeIndex].honest == true ){
204+ amount += challengesForIndex[challengeIndex].challengeDeposit;
205+ if (claimsForIndex[challengeIndex].honest == false ){
206+ amount += claimsForIndex[challengeIndex].claimDeposit;
207+ claimsForIndex[challengeIndex].claimDeposit = 0 ;
208+ }
183209 }
184210
185- challenge.challengeDeposit = 0 ;
186- payable (challenge.challenger).send (amount);
211+
212+ challengesForIndex[challengeIndex].challengeDeposit = 0 ;
213+ payable (challengesForIndex[challengeIndex].challenger).send (amount);
187214 }
188215 //**** View Functions ****//
189- function challengePeriod (bytes32 _messageHash ) public view returns (uint start , uint end ) {
190- start = claims[_messageHash].claimedAt;
191- end = start + challengeDuration;
216+ function challengePeriod (uint256 _fastMessageIndex ) public view returns (uint start , uint end ) {
217+ if (claims[_fastMessageIndex].length > 0 ){
218+ start = claims[_fastMessageIndex][claims[_fastMessageIndex].length -1 ].claimedAt;
219+ end = start + challengeDuration;
220+ }
221+
192222 return (start, end);
193223 }
224+
194225 //**** Governor functions ****//
195226
196227 function setClaimDeposit (uint256 _claimDeposit ) external onlyByGovernor {
197228 claimDeposit = _claimDeposit;
198229 }
230+ //TODO
231+ function viewClaimDeposit () external override view returns (uint256 amount ){
232+ return 0 ;
233+ }
199234
200235 function setChallengePeriodDuration (uint256 _challengeDuration ) external onlyByGovernor {
201236 challengeDuration = _challengeDuration;
0 commit comments