github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/gnovm/stdlibs/std/banker.gno (about)

     1  package std
     2  
     3  import "strconv"
     4  
     5  // Realm functions can call std.GetBanker(options) to get
     6  // a banker instance. Banker objects cannot be persisted,
     7  // but can be passed onto other functions to be transacted
     8  // on. A banker instance can be passed onto other realm
     9  // functions; this allows other realms to spend coins on
    10  // behalf of the first realm.
    11  //
    12  // Banker panics on errors instead of returning errors.
    13  // This also helps simplify the interface and prevent
    14  // hidden bugs (e.g. ignoring errors)
    15  //
    16  // NOTE: this Gno interface is satisfied by a native go
    17  // type, and those can't return non-primitive objects
    18  // (without confusion).
    19  type Banker interface {
    20  	GetCoins(addr Address) (dst Coins)
    21  	SendCoins(from, to Address, amt Coins)
    22  	TotalCoin(denom string) int64
    23  	IssueCoin(addr Address, denom string, amount int64)
    24  	RemoveCoin(addr Address, denom string, amount int64)
    25  }
    26  
    27  // BankerType represents the "permission level" requested for a banker,
    28  // retrievable through [GetBanker].
    29  type BankerType uint8
    30  
    31  // Available types of banker.
    32  const (
    33  	// Can only read state.
    34  	BankerTypeReadonly BankerType = iota
    35  	// Can only send from tx send.
    36  	BankerTypeOrigSend
    37  	// Can send from all realm coins.
    38  	BankerTypeRealmSend
    39  	// Can issue and remove realm coins.
    40  	BankerTypeRealmIssue
    41  
    42  	maxBanker
    43  )
    44  
    45  func (b BankerType) String() string {
    46  	switch b {
    47  	case BankerTypeReadonly:
    48  		return "BankerTypeReadonly"
    49  	case BankerTypeOrigSend:
    50  		return "BankerTypeOrigSend"
    51  	case BankerTypeRealmSend:
    52  		return "BankerTypeRealmSend"
    53  	case BankerTypeRealmIssue:
    54  		return "BankerTypeRealmIssue"
    55  	default:
    56  		panic("invalid BankerType: " + strconv.Itoa(int(b)))
    57  	}
    58  }
    59  
    60  //----------------------------------------
    61  // adapter for native banker
    62  
    63  // GetBanker returns a new Banker, with its capabilities matching the given
    64  // [BankerType].
    65  func GetBanker(bt BankerType) Banker {
    66  	if bt >= maxBanker {
    67  		panic("invalid banker type")
    68  	}
    69  	return banker{bt}
    70  }
    71  
    72  // These are native bindings to the banker's functions.
    73  func bankerGetCoins(bt uint8, addr string) (denoms []string, amounts []int64)
    74  func bankerSendCoins(bt uint8, from, to string, denoms []string, amounts []int64)
    75  func bankerTotalCoin(bt uint8, denom string) int64
    76  func bankerIssueCoin(bt uint8, addr string, denom string, amount int64)
    77  func bankerRemoveCoin(bt uint8, addr string, denom string, amount int64)
    78  
    79  type banker struct {
    80  	bt BankerType
    81  }
    82  
    83  func (b banker) GetCoins(addr Address) (dst Coins) {
    84  	denoms, amounts := bankerGetCoins(uint8(b.bt), string(addr))
    85  	dst = make(Coins, len(denoms))
    86  	for i := range dst {
    87  		dst[i] = Coin{denoms[i], amounts[i]}
    88  	}
    89  	return dst
    90  }
    91  
    92  func (b banker) SendCoins(from, to Address, amt Coins) {
    93  	if b.bt == BankerTypeReadonly {
    94  		panic("BankerTypeReadonly cannot send coins")
    95  	}
    96  	denoms, amounts := amt.expandNative()
    97  	bankerSendCoins(uint8(b.bt), string(from), string(to), denoms, amounts)
    98  }
    99  
   100  func (b banker) TotalCoin(denom string) int64 {
   101  	return bankerTotalCoin(uint8(b.bt), denom)
   102  }
   103  
   104  func (b banker) IssueCoin(addr Address, denom string, amount int64) {
   105  	if b.bt != BankerTypeRealmIssue {
   106  		panic(b.bt.String() + " cannot issue coins")
   107  	}
   108  	bankerIssueCoin(uint8(b.bt), string(addr), denom, amount)
   109  }
   110  
   111  func (b banker) RemoveCoin(addr Address, denom string, amount int64) {
   112  	if b.bt != BankerTypeRealmIssue {
   113  		panic(b.bt.String() + " cannot remove coins")
   114  	}
   115  	bankerRemoveCoin(uint8(b.bt), string(addr), denom, amount)
   116  }