22pragma solidity >= 0.8.17 ;
33
44import "../StakingI.sol " as staking;
5+ import "./DelegationManager.sol " ;
56
67/// @title StakingCaller
78/// @author Evmos Core Team
89/// @dev This contract is used to test external contract calls to the staking precompile.
9- contract StakingCaller {
10+ contract StakingCaller is DelegationManager {
1011 /// counter is used to test the state persistence bug, when EVM and Cosmos state were both
1112 /// changed in the same function.
1213 uint256 public counter;
1314 string [] private delegateMethod = [staking.MSG_DELEGATE];
1415
15- /// The delegation mapping is used to associate the EOA address that
16- /// actually made the delegate request with its corresponding delegation information.
17- mapping (address => mapping (string => uint256 )) public delegation;
18-
19- /// The unbonding entry struct represents an unbonding operation that is in progress.
20- /// It contains information about the validator and the amount of tokens that are being unbonded.
21- struct UnbondingEntry {
22- /// @dev The validator address is the address of the validator that is being unbonded.
23- string validator;
24- /// @dev The amount of tokens that are being unbonded.
25- uint256 amount;
26- /// @dev The creation height is the height at which the unbonding operation was created.
27- uint256 creationHeight;
28- /// @dev The completion time is the time at which the unbonding operation will complete.
29- int64 completionTime;
30- }
31-
32- /// The unbonding queue is used to store the unbonding operations that are in progress.
33- mapping (address => UnbondingEntry[]) public unbondingQueue;
34-
3516 /// @dev This function calls the staking precompile's create validator method
3617 /// using the msg.sender as the validator's operator address.
3718 /// @param _descr The initial description
@@ -91,15 +72,14 @@ contract StakingCaller {
9172 function testDelegate (
9273 string memory _validatorAddr
9374 ) public payable {
94- _dequeueUnbondingEntry ();
95-
75+ _dequeueUnbondingDelegation ();
9676 bool success = staking.STAKING_CONTRACT.delegate (
9777 address (this ),
9878 _validatorAddr,
9979 msg .value
10080 );
10181 require (success, "delegate failed " );
102- delegation[ msg .sender ][ _validatorAddr] += msg .value ;
82+ _increaseAmount ( msg .sender , _validatorAddr, msg .value ) ;
10383 }
10484
10585 /// @dev This function calls the staking precompile's undelegate method.
@@ -109,20 +89,11 @@ contract StakingCaller {
10989 string memory _validatorAddr ,
11090 uint256 _amount
11191 ) public {
112- _dequeueUnbondingEntry ();
113-
114- require (delegation[msg .sender ][_validatorAddr] >= _amount, "Insufficient delegation " );
115-
92+ _checkDelegation (_validatorAddr, _amount);
93+ _dequeueUnbondingDelegation ();
11694 int64 completionTime = staking.STAKING_CONTRACT.undelegate (address (this ), _validatorAddr, _amount);
11795 require (completionTime > 0 , "Failed to undelegate " );
118-
119- uint256 creationHeight = block .number ;
120- unbondingQueue[msg .sender ].push (UnbondingEntry ({
121- validator: _validatorAddr,
122- amount: _amount,
123- creationHeight: creationHeight,
124- completionTime: completionTime
125- }));
96+ _undelegate (_validatorAddr, _amount, completionTime);
12697 }
12798
12899 /// @dev This function calls the staking precompile's redelegate method.
@@ -133,16 +104,17 @@ contract StakingCaller {
133104 string memory _validatorSrcAddr ,
134105 string memory _validatorDstAddr ,
135106 uint256 _amount
136- ) public {
107+ ) public {
108+ _checkDelegation (_validatorSrcAddr, _amount);
137109 int64 completionTime = staking.STAKING_CONTRACT.redelegate (
138110 address (this ),
139111 _validatorSrcAddr,
140112 _validatorDstAddr,
141113 _amount
142114 );
143115 require (completionTime > 0 , "Failed to redelegate " );
144- delegation[ msg .sender ][ _validatorSrcAddr] -= _amount;
145- delegation[ msg .sender ][ _validatorDstAddr] += _amount;
116+ _decreaseAmount ( msg .sender , _validatorSrcAddr, _amount) ;
117+ _increaseAmount ( msg .sender , _validatorDstAddr, _amount) ;
146118 }
147119
148120 /// @dev This function calls the staking precompile's cancel unbonding delegation method.
@@ -154,16 +126,15 @@ contract StakingCaller {
154126 uint256 _amount ,
155127 uint256 _creationHeight
156128 ) public {
157- _dequeueUnbondingEntry ();
158-
129+ _dequeueUnbondingDelegation ();
130+ _checkUnbondingDelegation ( msg . sender , _validatorAddr);
159131 bool success = staking.STAKING_CONTRACT.cancelUnbondingDelegation (
160132 address (this ),
161133 _validatorAddr,
162134 _amount,
163135 _creationHeight
164136 );
165137 require (success, "Failed to cancel unbonding " );
166-
167138 _cancelUnbonding (_creationHeight, _amount);
168139 }
169140
@@ -280,8 +251,7 @@ contract StakingCaller {
280251 uint256 _amount ,
281252 string memory _calltype
282253 ) public {
283- _dequeueUnbondingEntry ();
284-
254+ _dequeueUnbondingDelegation ();
285255 address calledContractAddress = staking.STAKING_PRECOMPILE_ADDRESS;
286256 bytes memory payload = abi.encodeWithSignature (
287257 "undelegate(address,string,uint256) " ,
@@ -331,14 +301,7 @@ contract StakingCaller {
331301 } else {
332302 revert ("invalid calltype " );
333303 }
334-
335- uint256 creationHeight = block .number ;
336- unbondingQueue[msg .sender ].push (UnbondingEntry ({
337- validator: _validatorAddr,
338- amount: _amount,
339- creationHeight: creationHeight,
340- completionTime: completionTime
341- }));
304+ _undelegate (_validatorAddr, _amount, completionTime);
342305 }
343306
344307 /// @dev This function is used to test the behaviour when executing queries using special function calling opcodes,
@@ -452,15 +415,14 @@ contract StakingCaller {
452415 function testDelegateIncrementCounter (
453416 string memory _validatorAddr
454417 ) public payable {
455- _dequeueUnbondingEntry ();
456-
418+ _dequeueUnbondingDelegation ();
457419 bool success = staking.STAKING_CONTRACT.delegate (
458420 address (this ),
459421 _validatorAddr,
460422 msg .value
461423 );
462424 require (success, "delegate failed " );
463- delegation[ msg .sender ][ _validatorAddr] += msg .value ;
425+ _increaseAmount ( msg .sender , _validatorAddr, msg .value ) ;
464426 counter += 1 ;
465427 }
466428
@@ -469,15 +431,14 @@ contract StakingCaller {
469431 function testDelegateAndFailCustomLogic (
470432 string memory _validatorAddr
471433 ) public payable {
472- _dequeueUnbondingEntry ();
473-
434+ _dequeueUnbondingDelegation ();
474435 bool success = staking.STAKING_CONTRACT.delegate (
475436 address (this ),
476437 _validatorAddr,
477438 msg .value
478439 );
479440 require (success, "delegate failed " );
480- delegation[ msg .sender ][ _validatorAddr] += msg .value ;
441+ _increaseAmount ( msg .sender , _validatorAddr, msg .value ) ;
481442
482443 // This should fail since the balance is already spent in the previous call
483444 payable (msg .sender ).transfer (msg .value );
@@ -496,8 +457,7 @@ contract StakingCaller {
496457 string memory _validatorAddr ,
497458 uint256 _amount
498459 ) public payable {
499- _dequeueUnbondingEntry ();
500-
460+ _dequeueUnbondingDelegation ();
501461 (bool success , ) = _contract.call (
502462 abi.encodeWithSignature (
503463 "transfer(address,uint256) " ,
@@ -506,53 +466,8 @@ contract StakingCaller {
506466 )
507467 );
508468 require (success, "transfer failed " );
509-
510469 success = staking.STAKING_CONTRACT.delegate (address (this ), _validatorAddr, msg .value );
511470 require (success, "delegate failed " );
512- delegation[msg .sender ][_validatorAddr] += msg .value ;
513- }
514-
515- /// @dev This function is used to dequeue unbonding entries that have expired.
516- ///
517- /// @notice StakingCaller acts as the delegator and manages delegation/unbonding state per EoA.
518- /// Reflecting x/staking unbondingQueue changes in real-time would require event listening.
519- /// To simplify unbonding entry processing, this function is called during delegate/undelegate calls.
520- /// Although updating unbondingQueue state isn't tested in the staking precompile integration tests,
521- /// it is included for the completeness of the contract.
522- function _dequeueUnbondingEntry () private {
523-
524- for (uint256 i = 0 ; i < unbondingQueue[msg .sender ].length ; i++ ) {
525- UnbondingEntry storage entry = unbondingQueue[msg .sender ][i];
526- if (uint256 (int256 (entry.completionTime)) <= block .timestamp ) {
527- delete unbondingQueue[msg .sender ][i];
528- delegation[msg .sender ][entry.validator] -= entry.amount;
529- }
530- }
531- }
532-
533- /// @dev This function is used to cancel unbonding entries that have been cancelled.
534- /// @param _creationHeight The creation height of the unbonding entry to cancel.
535- /// @param _amount The amount to cancel.
536- function _cancelUnbonding (uint256 _creationHeight , uint256 _amount ) private {
537- UnbondingEntry[] storage entries = unbondingQueue[msg .sender ];
538-
539- for (uint256 i = 0 ; i < entries.length ; i++ ) {
540- UnbondingEntry storage entry = entries[i];
541-
542- if (entry.creationHeight != _creationHeight) {
543- continue ;
544- }
545-
546- require (entry.amount >= _amount, "amount exceeds unbonding entry amount " );
547- entry.amount -= _amount;
548-
549- // If the amount is now 0, remove the entry
550- if (entry.amount == 0 ) {
551- delete entries[i];
552- }
553-
554- // Only cancel one entry per call
555- break ;
556- }
471+ _increaseAmount (msg .sender , _validatorAddr, msg .value );
557472 }
558473}
0 commit comments