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  }