github.com/mavryk-network/mvgo@v1.19.9/contract/fa12.go (about) 1 // Copyright (c) 2020-2022 Blockwatch Data Inc. 2 // Author: alex@blockwatch.cc 3 4 package contract 5 6 import ( 7 "context" 8 "encoding/json" 9 "fmt" 10 11 "github.com/mavryk-network/mvgo/codec" 12 "github.com/mavryk-network/mvgo/mavryk" 13 "github.com/mavryk-network/mvgo/micheline" 14 "github.com/mavryk-network/mvgo/rpc" 15 ) 16 17 // Represents a generic FA1 (tzip5) or FA1.2 (tzip7) token 18 type FA1Token struct { 19 Address mavryk.Address 20 contract *Contract 21 } 22 23 func NewFA1Token(addr mavryk.Address, cli *rpc.Client) *FA1Token { 24 return &FA1Token{Address: addr, contract: NewContract(addr, cli)} 25 } 26 27 func (t FA1Token) Contract() *Contract { 28 return t.contract 29 } 30 31 func (t FA1Token) Equal(v FA1Token) bool { 32 return t.Address.Equal(v.Address) 33 } 34 35 func (t FA1Token) ResolveMetadata(ctx context.Context) (*TokenMetadata, error) { 36 return ResolveTokenMetadata(ctx, t.contract, mavryk.NewZ(0)) 37 } 38 39 func (t FA1Token) GetBalance(ctx context.Context, owner mavryk.Address) (mavryk.Z, error) { 40 var balance mavryk.Z 41 prim, err := t.contract.RunCallback(ctx, "getBalance", micheline.NewBytes(owner.EncodePadded())) 42 if err == nil { 43 balance.SetBig(prim.Int) 44 } 45 return balance, err 46 } 47 48 func (t FA1Token) GetTotalSupply(ctx context.Context) (mavryk.Z, error) { 49 var supply mavryk.Z 50 prim, err := t.contract.RunCallback(ctx, "getTotalSupply", micheline.NewPrim(micheline.D_UNIT)) 51 if err == nil { 52 supply.SetBig(prim.Int) 53 } 54 return supply, err 55 } 56 57 func (t FA1Token) GetAllowance(ctx context.Context, owner, spender mavryk.Address) (mavryk.Z, error) { 58 var allowance mavryk.Z 59 prim, err := t.contract.RunCallback(ctx, "getAllowance", 60 micheline.NewPair( 61 micheline.NewBytes(owner.EncodePadded()), 62 micheline.NewBytes(spender.EncodePadded()), 63 ), 64 ) 65 if err == nil { 66 allowance.SetBig(prim.Int) 67 } 68 return allowance, err 69 } 70 71 func (t FA1Token) Approve(spender mavryk.Address, amount mavryk.Z) CallArguments { 72 return NewFA1ApprovalArgs(). 73 Approve(spender, amount). 74 WithSource(spender). 75 WithDestination(t.Address) 76 } 77 78 func (t FA1Token) Revoke(spender mavryk.Address) CallArguments { 79 return NewFA1ApprovalArgs(). 80 Revoke(spender). 81 WithSource(spender). 82 WithDestination(t.Address) 83 } 84 85 func (t FA1Token) Transfer(from, to mavryk.Address, amount mavryk.Z) CallArguments { 86 return NewFA1TransferArgs().WithTransfer(from, to, amount). 87 WithSource(from). 88 WithDestination(t.Address) 89 } 90 91 type FA1Approval struct { 92 Spender mavryk.Address `json:"spender"` 93 Value mavryk.Z `json:"value"` 94 } 95 96 type FA1ApprovalArgs struct { 97 TxArgs 98 Approval FA1Approval `json:"approve"` 99 } 100 101 var _ CallArguments = (*FA1ApprovalArgs)(nil) 102 103 func NewFA1ApprovalArgs() *FA1ApprovalArgs { 104 return &FA1ApprovalArgs{} 105 } 106 107 func (a *FA1ApprovalArgs) WithSource(addr mavryk.Address) CallArguments { 108 a.Source = addr.Clone() 109 return a 110 } 111 112 func (a *FA1ApprovalArgs) WithDestination(addr mavryk.Address) CallArguments { 113 a.Destination = addr.Clone() 114 return a 115 } 116 117 func (p *FA1ApprovalArgs) Approve(spender mavryk.Address, amount mavryk.Z) *FA1ApprovalArgs { 118 p.Approval.Spender = spender.Clone() 119 p.Approval.Value = amount.Clone() 120 return p 121 } 122 123 func (p *FA1ApprovalArgs) Revoke(spender mavryk.Address) *FA1ApprovalArgs { 124 p.Approval.Spender = spender.Clone() 125 p.Approval.Value = mavryk.NewZ(0) 126 return p 127 } 128 129 func (a FA1ApprovalArgs) Parameters() *micheline.Parameters { 130 return &micheline.Parameters{ 131 Entrypoint: "approve", 132 Value: micheline.NewPair( 133 micheline.NewBytes(a.Approval.Spender.EncodePadded()), 134 micheline.NewNat(a.Approval.Value.Big()), 135 ), 136 } 137 } 138 139 func (p FA1ApprovalArgs) Encode() *codec.Transaction { 140 return &codec.Transaction{ 141 Manager: codec.Manager{ 142 Source: p.Source, 143 }, 144 Destination: p.Destination, 145 Parameters: p.Parameters(), 146 } 147 } 148 149 type FA1Transfer struct { 150 From mavryk.Address `json:"from"` 151 To mavryk.Address `json:"to"` 152 Amount mavryk.Z `json:"value"` 153 } 154 155 // compatible with micheline.Value.Unmarshal() 156 func (t *FA1Transfer) UnmarshalJSON(data []byte) error { 157 var xfer struct { 158 Transfer struct { 159 From mavryk.Address `json:"from"` 160 To mavryk.Address `json:"to"` 161 Amount mavryk.Z `json:"value"` 162 } `json:"transfer"` 163 } 164 if err := json.Unmarshal(data, &xfer); err != nil { 165 return err 166 } 167 t.From = xfer.Transfer.From 168 t.To = xfer.Transfer.To 169 t.Amount = xfer.Transfer.Amount 170 return nil 171 } 172 173 type FA1TransferArgs struct { 174 TxArgs 175 Transfer FA1Transfer 176 } 177 178 var _ CallArguments = (*FA1TransferArgs)(nil) 179 180 func NewFA1TransferArgs() *FA1TransferArgs { 181 return &FA1TransferArgs{} 182 } 183 184 func (a *FA1TransferArgs) WithSource(addr mavryk.Address) CallArguments { 185 a.Source = addr.Clone() 186 return a 187 } 188 189 func (a *FA1TransferArgs) WithDestination(addr mavryk.Address) CallArguments { 190 a.Destination = addr.Clone() 191 return a 192 } 193 194 func (p *FA1TransferArgs) WithTransfer(from, to mavryk.Address, amount mavryk.Z) *FA1TransferArgs { 195 p.Transfer.From = from.Clone() 196 p.Transfer.To = to.Clone() 197 p.Transfer.Amount = amount.Clone() 198 return p 199 } 200 201 func (t FA1TransferArgs) Parameters() *micheline.Parameters { 202 return &micheline.Parameters{ 203 Entrypoint: "transfer", 204 Value: micheline.NewPair( 205 micheline.NewBytes(t.Transfer.From.EncodePadded()), 206 micheline.NewPair( 207 micheline.NewBytes(t.Transfer.To.EncodePadded()), 208 micheline.NewNat(t.Transfer.Amount.Big()), 209 ), 210 ), 211 } 212 } 213 214 func (p FA1TransferArgs) Encode() *codec.Transaction { 215 return &codec.Transaction{ 216 Manager: codec.Manager{ 217 Source: p.Source, 218 }, 219 Destination: p.Destination, 220 Parameters: p.Parameters(), 221 } 222 } 223 224 type FA1TransferReceipt struct { 225 tx *rpc.Transaction 226 } 227 228 func NewFA1TransferReceipt(tx *rpc.Transaction) (*FA1TransferReceipt, error) { 229 if tx.Parameters == nil { 230 return nil, fmt.Errorf("missing transaction parameters") 231 } 232 if tx.Parameters.Entrypoint != "transfer" { 233 return nil, fmt.Errorf("invalid transfer entrypoint name %q", tx.Parameters.Entrypoint) 234 } 235 return &FA1TransferReceipt{tx: tx}, nil 236 } 237 238 func (r FA1TransferReceipt) IsSuccess() bool { 239 return r.tx.Result().Status.IsSuccess() 240 } 241 242 func (r FA1TransferReceipt) Request() FA1Transfer { 243 typ := micheline.ITzip7.TypeOf("transfer") 244 val := micheline.NewValue(typ, r.tx.Parameters.Value) 245 xfer := FA1Transfer{} 246 _ = val.Unmarshal(&xfer) 247 return xfer 248 } 249 250 func (r FA1TransferReceipt) Result() *rpc.Transaction { 251 return r.tx 252 } 253 254 func (r FA1TransferReceipt) Costs() mavryk.Costs { 255 return r.tx.Costs() 256 } 257 258 func (r FA1TransferReceipt) BalanceUpdates() []TokenBalance { 259 // TODO: read from ledger bigmap update 260 return nil 261 }