github.com/status-im/status-go@v1.1.0/services/communitytokens/token_instances.go (about)

     1  package communitytokens
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math/big"
     7  	"strings"
     8  
     9  	"github.com/ethereum/go-ethereum/accounts/abi"
    10  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    11  	"github.com/ethereum/go-ethereum/core/types"
    12  	"github.com/status-im/status-go/contracts/community-tokens/assets"
    13  	"github.com/status-im/status-go/contracts/community-tokens/collectibles"
    14  	"github.com/status-im/status-go/contracts/community-tokens/mastertoken"
    15  	"github.com/status-im/status-go/contracts/community-tokens/ownertoken"
    16  	"github.com/status-im/status-go/protocol/communities/token"
    17  	"github.com/status-im/status-go/protocol/protobuf"
    18  	"github.com/status-im/status-go/services/wallet/bigint"
    19  )
    20  
    21  type TokenInstance interface {
    22  	RemoteBurn(*bind.TransactOpts, []*big.Int) (*types.Transaction, error)
    23  	Mint(*bind.TransactOpts, []string, *bigint.BigInt) (*types.Transaction, error)
    24  	SetMaxSupply(*bind.TransactOpts, *big.Int) (*types.Transaction, error)
    25  	PackMethod(ctx context.Context, methodName string, args ...interface{}) ([]byte, error)
    26  }
    27  
    28  // Owner Token
    29  type OwnerTokenInstance struct {
    30  	TokenInstance
    31  	instance *ownertoken.OwnerToken
    32  }
    33  
    34  func (t OwnerTokenInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) {
    35  	return nil, fmt.Errorf("remote destruction for owner token not implemented")
    36  }
    37  
    38  func (t OwnerTokenInstance) Mint(transactOpts *bind.TransactOpts, walletAddresses []string, amount *bigint.BigInt) (*types.Transaction, error) {
    39  	return nil, fmt.Errorf("minting for owner token not implemented")
    40  }
    41  
    42  func (t OwnerTokenInstance) SetMaxSupply(transactOpts *bind.TransactOpts, maxSupply *big.Int) (*types.Transaction, error) {
    43  	return nil, fmt.Errorf("setting max supply for owner token not implemented")
    44  }
    45  
    46  func (t OwnerTokenInstance) PackMethod(ctx context.Context, methodName string, args ...interface{}) ([]byte, error) {
    47  	ownerTokenABI, err := abi.JSON(strings.NewReader(ownertoken.OwnerTokenABI))
    48  	if err != nil {
    49  		return []byte{}, err
    50  	}
    51  	return ownerTokenABI.Pack(methodName, args...)
    52  }
    53  
    54  // Master Token
    55  type MasterTokenInstance struct {
    56  	TokenInstance
    57  	instance *mastertoken.MasterToken
    58  }
    59  
    60  func (t MasterTokenInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) {
    61  	return t.instance.RemoteBurn(transactOpts, tokenIds)
    62  }
    63  
    64  func (t MasterTokenInstance) Mint(transactOpts *bind.TransactOpts, walletAddresses []string, amount *bigint.BigInt) (*types.Transaction, error) {
    65  	usersAddresses := prepareMintCollectiblesData(walletAddresses, amount)
    66  	return t.instance.MintTo(transactOpts, usersAddresses)
    67  }
    68  
    69  func (t MasterTokenInstance) SetMaxSupply(transactOpts *bind.TransactOpts, maxSupply *big.Int) (*types.Transaction, error) {
    70  	return t.instance.SetMaxSupply(transactOpts, maxSupply)
    71  }
    72  
    73  func (t MasterTokenInstance) PackMethod(ctx context.Context, methodName string, args ...interface{}) ([]byte, error) {
    74  	masterTokenABI, err := abi.JSON(strings.NewReader(mastertoken.MasterTokenABI))
    75  	if err != nil {
    76  		return []byte{}, err
    77  	}
    78  	return masterTokenABI.Pack(methodName, args...)
    79  }
    80  
    81  // Collectible
    82  type CollectibleInstance struct {
    83  	TokenInstance
    84  	instance *collectibles.Collectibles
    85  }
    86  
    87  func (t CollectibleInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) {
    88  	return t.instance.RemoteBurn(transactOpts, tokenIds)
    89  }
    90  
    91  func (t CollectibleInstance) Mint(transactOpts *bind.TransactOpts, walletAddresses []string, amount *bigint.BigInt) (*types.Transaction, error) {
    92  	usersAddresses := prepareMintCollectiblesData(walletAddresses, amount)
    93  	return t.instance.MintTo(transactOpts, usersAddresses)
    94  }
    95  
    96  func (t CollectibleInstance) SetMaxSupply(transactOpts *bind.TransactOpts, maxSupply *big.Int) (*types.Transaction, error) {
    97  	return t.instance.SetMaxSupply(transactOpts, maxSupply)
    98  }
    99  
   100  func (t CollectibleInstance) PackMethod(ctx context.Context, methodName string, args ...interface{}) ([]byte, error) {
   101  	collectiblesABI, err := abi.JSON(strings.NewReader(collectibles.CollectiblesABI))
   102  	if err != nil {
   103  		return []byte{}, err
   104  	}
   105  	return collectiblesABI.Pack(methodName, args...)
   106  }
   107  
   108  // Asset
   109  type AssetInstance struct {
   110  	TokenInstance
   111  	instance *assets.Assets
   112  }
   113  
   114  func (t AssetInstance) RemoteBurn(transactOpts *bind.TransactOpts, tokenIds []*big.Int) (*types.Transaction, error) {
   115  	return nil, fmt.Errorf("remote destruction for assets not implemented")
   116  }
   117  
   118  // The amount should be in smallest denomination of the asset (like wei) with decimal = 18, eg.
   119  // if we want to mint 2.34 of the token, then amount should be 234{16 zeros}.
   120  func (t AssetInstance) Mint(transactOpts *bind.TransactOpts, walletAddresses []string, amount *bigint.BigInt) (*types.Transaction, error) {
   121  	usersAddresses, amountsList := prepareMintAssetsData(walletAddresses, amount)
   122  	return t.instance.MintTo(transactOpts, usersAddresses, amountsList)
   123  }
   124  
   125  func (t AssetInstance) SetMaxSupply(transactOpts *bind.TransactOpts, maxSupply *big.Int) (*types.Transaction, error) {
   126  	return t.instance.SetMaxSupply(transactOpts, maxSupply)
   127  }
   128  
   129  func (t AssetInstance) PackMethod(ctx context.Context, methodName string, args ...interface{}) ([]byte, error) {
   130  	assetsABI, err := abi.JSON(strings.NewReader(assets.AssetsABI))
   131  	if err != nil {
   132  		return []byte{}, err
   133  	}
   134  	return assetsABI.Pack(methodName, args...)
   135  }
   136  
   137  // creator
   138  
   139  func NewTokenInstance(s *Service, chainID uint64, contractAddress string) (TokenInstance, error) {
   140  	tokenType, err := s.db.GetTokenType(chainID, contractAddress)
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  	privLevel, err := s.db.GetTokenPrivilegesLevel(chainID, contractAddress)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	switch {
   149  	case privLevel == token.OwnerLevel:
   150  		contractInst, err := s.NewOwnerTokenInstance(chainID, contractAddress)
   151  		if err != nil {
   152  			return nil, err
   153  		}
   154  		return &OwnerTokenInstance{instance: contractInst}, nil
   155  	case privLevel == token.MasterLevel:
   156  		contractInst, err := s.NewMasterTokenInstance(chainID, contractAddress)
   157  		if err != nil {
   158  			return nil, err
   159  		}
   160  		return &MasterTokenInstance{instance: contractInst}, nil
   161  	case tokenType == protobuf.CommunityTokenType_ERC721:
   162  		contractInst, err := s.manager.NewCollectiblesInstance(chainID, contractAddress)
   163  		if err != nil {
   164  			return nil, err
   165  		}
   166  		return &CollectibleInstance{instance: contractInst}, nil
   167  	case tokenType == protobuf.CommunityTokenType_ERC20:
   168  		contractInst, err := s.manager.NewAssetsInstance(chainID, contractAddress)
   169  		if err != nil {
   170  			return nil, err
   171  		}
   172  		return &AssetInstance{instance: contractInst}, nil
   173  	}
   174  
   175  	return nil, fmt.Errorf("unknown type of contract: chain=%v, address=%v", chainID, contractAddress)
   176  }