github.com/Finschia/finschia-sdk@v0.48.1/x/token/keeper/send.go (about) 1 package keeper 2 3 import ( 4 sdk "github.com/Finschia/finschia-sdk/types" 5 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 6 "github.com/Finschia/finschia-sdk/x/token" 7 ) 8 9 func (k Keeper) Send(ctx sdk.Context, contractID string, from, to sdk.AccAddress, amount sdk.Int) error { 10 if !amount.IsPositive() { 11 panic(sdkerrors.ErrInvalidRequest.Wrap("amount must be positive")) 12 } 13 14 if err := k.subtractToken(ctx, contractID, from, amount); err != nil { 15 return err 16 } 17 k.addToken(ctx, contractID, to, amount) 18 19 return nil 20 } 21 22 func (k Keeper) AuthorizeOperator(ctx sdk.Context, contractID string, holder, operator sdk.AccAddress) error { 23 if _, err := k.GetClass(ctx, contractID); err != nil { 24 panic(err) 25 } 26 27 if _, err := k.GetAuthorization(ctx, contractID, holder, operator); err == nil { 28 return token.ErrTokenAlreadyApproved.Wrap("Already authorized") 29 } 30 31 k.setAuthorization(ctx, contractID, holder, operator) 32 33 return nil 34 } 35 36 func (k Keeper) RevokeOperator(ctx sdk.Context, contractID string, holder, operator sdk.AccAddress) error { 37 if _, err := k.GetAuthorization(ctx, contractID, holder, operator); err != nil { 38 return err 39 } 40 41 k.deleteAuthorization(ctx, contractID, holder, operator) 42 return nil 43 } 44 45 func (k Keeper) GetAuthorization(ctx sdk.Context, contractID string, holder, operator sdk.AccAddress) (*token.Authorization, error) { 46 store := ctx.KVStore(k.storeKey) 47 if store.Has(authorizationKey(contractID, operator, holder)) { 48 return &token.Authorization{ 49 Holder: holder.String(), 50 Operator: operator.String(), 51 }, nil 52 } 53 return nil, token.ErrTokenNotApproved.Wrapf("no authorization to %s by %s", operator, holder) 54 } 55 56 func (k Keeper) setAuthorization(ctx sdk.Context, contractID string, holder, operator sdk.AccAddress) { 57 store := ctx.KVStore(k.storeKey) 58 key := authorizationKey(contractID, operator, holder) 59 store.Set(key, []byte{}) 60 } 61 62 func (k Keeper) deleteAuthorization(ctx sdk.Context, contractID string, holder, operator sdk.AccAddress) { 63 store := ctx.KVStore(k.storeKey) 64 key := authorizationKey(contractID, operator, holder) 65 store.Delete(key) 66 } 67 68 func (k Keeper) subtractToken(ctx sdk.Context, contractID string, addr sdk.AccAddress, amount sdk.Int) error { 69 balance := k.GetBalance(ctx, contractID, addr) 70 newBalance := balance.Sub(amount) 71 if newBalance.IsNegative() { 72 // Daphne emits ErrInsufficientFunds here, which is against to the spec. 73 return token.ErrInsufficientBalance.Wrapf("%s is smaller than %s", balance, amount) 74 } 75 76 k.setBalance(ctx, contractID, addr, newBalance) 77 78 return nil 79 } 80 81 func (k Keeper) addToken(ctx sdk.Context, contractID string, addr sdk.AccAddress, amount sdk.Int) { 82 balance := k.GetBalance(ctx, contractID, addr) 83 newBalance := balance.Add(amount) 84 85 k.setBalance(ctx, contractID, addr, newBalance) 86 } 87 88 func (k Keeper) GetBalance(ctx sdk.Context, contractID string, addr sdk.AccAddress) sdk.Int { 89 store := ctx.KVStore(k.storeKey) 90 amount := sdk.ZeroInt() 91 bz := store.Get(balanceKey(contractID, addr)) 92 if bz != nil { 93 if err := amount.Unmarshal(bz); err != nil { 94 panic(err) 95 } 96 } 97 return amount 98 } 99 100 // setBalance sets balance. 101 // The caller must validate `balance`. 102 func (k Keeper) setBalance(ctx sdk.Context, contractID string, addr sdk.AccAddress, balance sdk.Int) { 103 store := ctx.KVStore(k.storeKey) 104 key := balanceKey(contractID, addr) 105 if balance.IsZero() { 106 store.Delete(key) 107 } else { 108 bz, err := balance.Marshal() 109 if err != nil { 110 panic(err) 111 } 112 store.Set(key, bz) 113 } 114 }