@@ -183,11 +183,40 @@ func (m *MockBankKeeper) BurnCoins(ctx context.Context, moduleName string, amt s
183183 return nil
184184}
185185
186- // MockStakingKeeper is a mock implementation of the StakingKeeper interface
187- type MockStakingKeeper struct {}
186+ // delegationKey uniquely identifies a delegation by delegator+validator.
187+ type delegationKey struct {
188+ Delegator string
189+ Validator string
190+ }
191+
192+ // MockStakingKeeper is a stateful mock of the StakingKeeper interface.
193+ // It tracks validators, delegations, and unbonding delegations so that
194+ // reactor infuse/defuse/migrate/cancel tests can exercise the full handler path.
195+ type MockStakingKeeper struct {
196+ validators map [string ]stakingtypes.Validator
197+ delegations map [delegationKey ]stakingtypes.Delegation
198+ unbondings map [delegationKey ]stakingtypes.UnbondingDelegation
199+ nextUnbondID uint64
200+ }
188201
189202func NewMockStakingKeeper () * MockStakingKeeper {
190- return & MockStakingKeeper {}
203+ return & MockStakingKeeper {
204+ validators : make (map [string ]stakingtypes.Validator ),
205+ delegations : make (map [delegationKey ]stakingtypes.Delegation ),
206+ unbondings : make (map [delegationKey ]stakingtypes.UnbondingDelegation ),
207+ nextUnbondID : 1 ,
208+ }
209+ }
210+
211+ // AddValidator registers a bonded validator with 1:1 token-to-share ratio.
212+ func (m * MockStakingKeeper ) AddValidator (operatorAddr sdk.ValAddress , tokens math.Int ) {
213+ val := stakingtypes.Validator {
214+ OperatorAddress : operatorAddr .String (),
215+ Status : stakingtypes .Bonded ,
216+ Tokens : tokens ,
217+ DelegatorShares : math .LegacyNewDecFromInt (tokens ),
218+ }
219+ m .validators [operatorAddr .String ()] = val
191220}
192221
193222func (m * MockStakingKeeper ) ConsensusAddressCodec () address.Codec {
@@ -199,70 +228,212 @@ func (m *MockStakingKeeper) ValidatorByConsAddr(ctx context.Context, consAddr sd
199228}
200229
201230func (m * MockStakingKeeper ) GetValidator (ctx context.Context , addr sdk.ValAddress ) (stakingtypes.Validator , error ) {
202- return stakingtypes.Validator {}, nil
231+ val , ok := m .validators [addr .String ()]
232+ if ! ok {
233+ return stakingtypes.Validator {}, stakingtypes .ErrNoValidatorFound
234+ }
235+ return val , nil
203236}
204237
205238func (m * MockStakingKeeper ) GetAllValidators (ctx context.Context ) ([]stakingtypes.Validator , error ) {
206- return nil , nil
239+ vals := make ([]stakingtypes.Validator , 0 , len (m .validators ))
240+ for _ , v := range m .validators {
241+ vals = append (vals , v )
242+ }
243+ return vals , nil
207244}
208245
209246func (m * MockStakingKeeper ) GetValidators (ctx context.Context , maxRetrieve uint32 ) ([]stakingtypes.Validator , error ) {
210- return nil , nil
247+ return m . GetAllValidators ( ctx )
211248}
212249
213250func (m * MockStakingKeeper ) GetValidatorDelegations (ctx context.Context , valAddr sdk.ValAddress ) ([]stakingtypes.Delegation , error ) {
214- return nil , nil
251+ var result []stakingtypes.Delegation
252+ for k , d := range m .delegations {
253+ if k .Validator == valAddr .String () {
254+ result = append (result , d )
255+ }
256+ }
257+ return result , nil
215258}
216259
217260func (m * MockStakingKeeper ) GetDelegation (ctx context.Context , delAddr sdk.AccAddress , valAddr sdk.ValAddress ) (stakingtypes.Delegation , error ) {
218- return stakingtypes.Delegation {}, nil
261+ dk := delegationKey {Delegator : delAddr .String (), Validator : valAddr .String ()}
262+ del , ok := m .delegations [dk ]
263+ if ! ok {
264+ return stakingtypes.Delegation {}, stakingtypes .ErrNoDelegation
265+ }
266+ return del , nil
219267}
220268
221269func (m * MockStakingKeeper ) GetUnbondingDelegation (ctx context.Context , delAddr sdk.AccAddress , valAddr sdk.ValAddress ) (stakingtypes.UnbondingDelegation , error ) {
222- return stakingtypes.UnbondingDelegation {}, nil
270+ dk := delegationKey {Delegator : delAddr .String (), Validator : valAddr .String ()}
271+ ubd , ok := m .unbondings [dk ]
272+ if ! ok {
273+ return stakingtypes.UnbondingDelegation {}, stakingtypes .ErrNoUnbondingDelegation
274+ }
275+ return ubd , nil
223276}
224277
225278func (m * MockStakingKeeper ) GetUnbondingDelegationByUnbondingID (ctx context.Context , id uint64 ) (stakingtypes.UnbondingDelegation , error ) {
226- return stakingtypes.UnbondingDelegation {}, nil
279+ for _ , ubd := range m .unbondings {
280+ for _ , entry := range ubd .Entries {
281+ if entry .UnbondingId == id {
282+ return ubd , nil
283+ }
284+ }
285+ }
286+ return stakingtypes.UnbondingDelegation {}, stakingtypes .ErrNoUnbondingDelegation
227287}
228288
229289func (m * MockStakingKeeper ) GetDelegatorDelegations (ctx context.Context , delegator sdk.AccAddress , maxRetrieve uint16 ) ([]stakingtypes.Delegation , error ) {
230- return nil , nil
290+ var result []stakingtypes.Delegation
291+ for k , d := range m .delegations {
292+ if k .Delegator == delegator .String () {
293+ result = append (result , d )
294+ if uint16 (len (result )) >= maxRetrieve {
295+ break
296+ }
297+ }
298+ }
299+ return result , nil
231300}
232301
233302func (m * MockStakingKeeper ) SetDelegation (ctx context.Context , delegation stakingtypes.Delegation ) error {
303+ dk := delegationKey {Delegator : delegation .DelegatorAddress , Validator : delegation .ValidatorAddress }
304+ m .delegations [dk ] = delegation
234305 return nil
235306}
236307
237308func (m * MockStakingKeeper ) RemoveDelegation (ctx context.Context , delegation stakingtypes.Delegation ) error {
309+ dk := delegationKey {Delegator : delegation .DelegatorAddress , Validator : delegation .ValidatorAddress }
310+ delete (m .delegations , dk )
238311 return nil
239312}
240313
314+ // ValidateUnbondAmount returns the shares corresponding to amt using a 1:1 ratio.
315+ // Returns an error if no delegation exists or the amount exceeds delegated shares.
241316func (m * MockStakingKeeper ) ValidateUnbondAmount (ctx context.Context , delAddr sdk.AccAddress , valAddr sdk.ValAddress , amt math.Int ) (math.LegacyDec , error ) {
242- return math .LegacyZeroDec (), nil
317+ dk := delegationKey {Delegator : delAddr .String (), Validator : valAddr .String ()}
318+ del , ok := m .delegations [dk ]
319+ if ! ok {
320+ return math .LegacyZeroDec (), stakingtypes .ErrNoDelegation
321+ }
322+ shares := math .LegacyNewDecFromInt (amt )
323+ if shares .GT (del .Shares ) {
324+ return math .LegacyZeroDec (), stakingtypes .ErrNotEnoughDelegationShares
325+ }
326+ return shares , nil
243327}
244328
245329func (m * MockStakingKeeper ) BeginRedelegation (ctx context.Context , delAddr sdk.AccAddress , valSrcAddr , valDstAddr sdk.ValAddress , sharesAmount math.LegacyDec ) (time.Time , error ) {
246- return time .Now (), nil
330+ srcKey := delegationKey {Delegator : delAddr .String (), Validator : valSrcAddr .String ()}
331+ srcDel , ok := m .delegations [srcKey ]
332+ if ! ok {
333+ return time.Time {}, stakingtypes .ErrNoDelegation
334+ }
335+ if sharesAmount .GT (srcDel .Shares ) {
336+ return time.Time {}, stakingtypes .ErrNotEnoughDelegationShares
337+ }
338+ srcDel .Shares = srcDel .Shares .Sub (sharesAmount )
339+ if srcDel .Shares .IsZero () {
340+ delete (m .delegations , srcKey )
341+ } else {
342+ m .delegations [srcKey ] = srcDel
343+ }
344+ dstKey := delegationKey {Delegator : delAddr .String (), Validator : valDstAddr .String ()}
345+ dstDel , exists := m .delegations [dstKey ]
346+ if ! exists {
347+ dstDel = stakingtypes.Delegation {
348+ DelegatorAddress : delAddr .String (),
349+ ValidatorAddress : valDstAddr .String (),
350+ Shares : math .LegacyZeroDec (),
351+ }
352+ }
353+ dstDel .Shares = dstDel .Shares .Add (sharesAmount )
354+ m .delegations [dstKey ] = dstDel
355+ return time .Now ().Add (21 * 24 * time .Hour ), nil
247356}
248357
249358func (m * MockStakingKeeper ) BondDenom (ctx context.Context ) (string , error ) {
250359 return "stake" , nil
251360}
252361
362+ // Delegate creates or adds to a delegation using a 1:1 token-to-share ratio.
253363func (m * MockStakingKeeper ) Delegate (ctx context.Context , delAddr sdk.AccAddress , bondAmt math.Int , tokenSrc stakingtypes.BondStatus , validator stakingtypes.Validator , subtractAccount bool ) (math.LegacyDec , error ) {
254- return math .LegacyZeroDec (), nil
364+ dk := delegationKey {Delegator : delAddr .String (), Validator : validator .OperatorAddress }
365+ del , exists := m .delegations [dk ]
366+ if ! exists {
367+ del = stakingtypes.Delegation {
368+ DelegatorAddress : delAddr .String (),
369+ ValidatorAddress : validator .OperatorAddress ,
370+ Shares : math .LegacyZeroDec (),
371+ }
372+ }
373+ newShares := math .LegacyNewDecFromInt (bondAmt )
374+ del .Shares = del .Shares .Add (newShares )
375+ m .delegations [dk ] = del
376+
377+ if val , ok := m .validators [validator .OperatorAddress ]; ok {
378+ val .Tokens = val .Tokens .Add (bondAmt )
379+ val .DelegatorShares = val .DelegatorShares .Add (newShares )
380+ m .validators [validator .OperatorAddress ] = val
381+ }
382+ return newShares , nil
255383}
256384
385+ // Undelegate removes shares from a delegation and creates an unbonding entry.
257386func (m * MockStakingKeeper ) Undelegate (ctx context.Context , delAddr sdk.AccAddress , valAddr sdk.ValAddress , sharesAmount math.LegacyDec ) (time.Time , math.Int , error ) {
258- return time .Now (), math .ZeroInt (), nil
387+ dk := delegationKey {Delegator : delAddr .String (), Validator : valAddr .String ()}
388+ del , ok := m .delegations [dk ]
389+ if ! ok {
390+ return time.Time {}, math .ZeroInt (), stakingtypes .ErrNoDelegation
391+ }
392+ if sharesAmount .GT (del .Shares ) {
393+ return time.Time {}, math .ZeroInt (), stakingtypes .ErrNotEnoughDelegationShares
394+ }
395+ del .Shares = del .Shares .Sub (sharesAmount )
396+ if del .Shares .IsZero () {
397+ delete (m .delegations , dk )
398+ } else {
399+ m .delegations [dk ] = del
400+ }
401+
402+ returnAmount := sharesAmount .TruncateInt ()
403+ sdkCtx := sdk .UnwrapSDKContext (ctx )
404+ completionTime := sdkCtx .BlockTime ().Add (21 * 24 * time .Hour )
405+
406+ ubd , exists := m .unbondings [dk ]
407+ if ! exists {
408+ ubd = stakingtypes.UnbondingDelegation {
409+ DelegatorAddress : delAddr .String (),
410+ ValidatorAddress : valAddr .String (),
411+ }
412+ }
413+ id := m .nextUnbondID
414+ m .nextUnbondID ++
415+ ubd .Entries = append (ubd .Entries , stakingtypes.UnbondingDelegationEntry {
416+ CreationHeight : sdkCtx .BlockHeight (),
417+ CompletionTime : completionTime ,
418+ InitialBalance : returnAmount ,
419+ Balance : returnAmount ,
420+ UnbondingId : id ,
421+ UnbondingOnHoldRefCount : 0 ,
422+ })
423+ m .unbondings [dk ] = ubd
424+
425+ return completionTime , returnAmount , nil
259426}
260427
261428func (m * MockStakingKeeper ) RemoveUnbondingDelegation (ctx context.Context , ubd stakingtypes.UnbondingDelegation ) error {
429+ dk := delegationKey {Delegator : ubd .DelegatorAddress , Validator : ubd .ValidatorAddress }
430+ delete (m .unbondings , dk )
262431 return nil
263432}
264433
265434func (m * MockStakingKeeper ) SetUnbondingDelegation (ctx context.Context , ubd stakingtypes.UnbondingDelegation ) error {
435+ dk := delegationKey {Delegator : ubd .DelegatorAddress , Validator : ubd .ValidatorAddress }
436+ m .unbondings [dk ] = ubd
266437 return nil
267438}
268439
0 commit comments