@@ -7,6 +7,7 @@ import {CollateralManagementContract} from "../../src/CollateralManagement.sol";
77import {FlyoverDiscovery} from "../../src/FlyoverDiscovery.sol " ;
88import {PauseRegistry} from "../../src/PauseRegistry.sol " ;
99import {BridgeMock} from "../../src/test-contracts/BridgeMock.sol " ;
10+ import {WalletMock} from "../../src/test-contracts/WalletMock.sol " ;
1011import {ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol " ;
1112import {Quotes} from "../../src/libraries/Quotes.sol " ;
1213import {Flyover} from "../../src/libraries/Flyover.sol " ;
@@ -184,4 +185,107 @@ abstract contract PegInTestBase is Test {
184185 Flyover.ProviderType.Both
185186 );
186187 }
188+
189+ /// @notice Shared helper for constructing a standard PegIn quote fixture
190+ function _buildPegInQuoteFixture (
191+ uint256 value ,
192+ address lp ,
193+ address payable refundAddress ,
194+ address destinationContract ,
195+ uint256 nonce
196+ ) internal view returns (Quotes.PegInQuote memory ) {
197+ bytes memory testBtcAddress = new bytes (21 );
198+
199+ return
200+ Quotes.PegInQuote ({
201+ chainId: block .chainid ,
202+ callFee: 100000000000000 ,
203+ penaltyFee: 10000000000000 ,
204+ value: value,
205+ gasFee: 100 ,
206+ fedBtcAddress: bytes20 (testBtcAddress),
207+ lbcAddress: address (pegInContract),
208+ liquidityProviderRskAddress: lp,
209+ contractAddress: destinationContract,
210+ rskRefundAddress: refundAddress,
211+ nonce: int64 (uint64 (nonce)),
212+ gasLimit: 21000 ,
213+ agreementTimestamp: uint32 (block .timestamp ),
214+ timeForDeposit: 3600 ,
215+ callTime: 7200 ,
216+ depositConfirmations: 10 ,
217+ callOnRegister: false ,
218+ btcRefundAddress: testBtcAddress,
219+ liquidityProviderBtcAddress: testBtcAddress,
220+ data: new bytes (0 )
221+ });
222+ }
223+
224+ /// @notice Shared helper for signing PegIn quotes
225+ function _signPegInQuoteWithKey (
226+ uint256 privateKey ,
227+ Quotes.PegInQuote memory quote
228+ ) internal view returns (bytes memory ) {
229+ bytes32 eip712Hash = pegInContract.hashPegInQuoteEIP712 (quote);
230+ (uint8 v , bytes32 r , bytes32 s ) = vm.sign (privateKey, eip712Hash);
231+ return abi.encodePacked (r, s, v);
232+ }
233+
234+ /// @notice Shared helper for creating BTC block headers with LE timestamp
235+ function _btcHeaderFromTimestamp (
236+ uint32 timestamp
237+ ) internal pure returns (bytes memory ) {
238+ bytes memory header = new bytes (80 );
239+ header[68 ] = bytes1 (uint8 (timestamp));
240+ header[69 ] = bytes1 (uint8 (timestamp >> 8 ));
241+ header[70 ] = bytes1 (uint8 (timestamp >> 16 ));
242+ header[71 ] = bytes1 (uint8 (timestamp >> 24 ));
243+ return header;
244+ }
245+
246+ /// @notice Seeds one non-LP internal balance by forcing refund transfer failure on registerPegIn
247+ function _seedNonLpRefundLiabilityFixture (
248+ address lp ,
249+ uint256 lpPrivateKey ,
250+ uint256 value ,
251+ uint256 height ,
252+ bytes memory rawTx ,
253+ bytes memory pmt
254+ ) internal returns (address creditor , uint256 creditedAmount ) {
255+ WalletMock refundWallet = new WalletMock ();
256+ refundWallet.setRejectFunds (true );
257+ creditor = address (refundWallet);
258+
259+ Quotes.PegInQuote memory quote = _buildPegInQuoteFixture (
260+ value,
261+ lp,
262+ payable (creditor),
263+ address (0xBEEF ),
264+ uint256 (uint64 (block .timestamp ))
265+ );
266+ bytes32 quoteHash = pegInContract.hashPegInQuote (quote);
267+ bytes memory signature = _signPegInQuoteWithKey (lpPrivateKey, quote);
268+ uint256 peginAmount = quote.value + quote.callFee + quote.gasFee;
269+
270+ vm.deal (address (this ), peginAmount);
271+ bridgeMock.setPegin {value: peginAmount}(quoteHash);
272+ bridgeMock.setHeader (
273+ height,
274+ _btcHeaderFromTimestamp (uint32 (block .timestamp ) + 300 )
275+ );
276+ bridgeMock.setHeader (
277+ height + uint256 (quote.depositConfirmations) - 1 ,
278+ _btcHeaderFromTimestamp (uint32 (block .timestamp ) + 600 )
279+ );
280+
281+ vm.prank (lp);
282+ pegInContract.registerPegIn (quote, signature, rawTx, pmt, height);
283+
284+ creditedAmount = pegInContract.getBalance (creditor);
285+ assertGt (
286+ creditedAmount,
287+ 0 ,
288+ "Expected non-LP refund creditor balance to be seeded "
289+ );
290+ }
187291}
0 commit comments