github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/internal/ethapi/api_fsn.go (about)

     1  package ethapi
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"math/big"
     9  	"sort"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/FusionFoundation/efsn/accounts"
    14  	"github.com/FusionFoundation/efsn/common"
    15  	"github.com/FusionFoundation/efsn/common/hexutil"
    16  	"github.com/FusionFoundation/efsn/consensus/datong"
    17  	"github.com/FusionFoundation/efsn/core/rawdb"
    18  	"github.com/FusionFoundation/efsn/core/state"
    19  	"github.com/FusionFoundation/efsn/core/types"
    20  	"github.com/FusionFoundation/efsn/log"
    21  	"github.com/FusionFoundation/efsn/rlp"
    22  	"github.com/FusionFoundation/efsn/rpc"
    23  )
    24  
    25  var lastBlockOfBuyTickets = int64(0)
    26  var buyTicketOnBlockMap map[common.Address]bool
    27  var buyTicketOnBlockMapMutex sync.Mutex
    28  
    29  //--------------------------------------------- PublicFusionAPI -------------------------------------
    30  
    31  // PublicFusionAPI ss
    32  type PublicFusionAPI struct {
    33  	b Backend
    34  }
    35  
    36  // NewPublicFusionAPI ss
    37  func NewPublicFusionAPI(b Backend) *PublicFusionAPI {
    38  	return &PublicFusionAPI{
    39  		b: b,
    40  	}
    41  }
    42  
    43  // IsAutoBuyTicket wacom
    44  func (s *PublicFusionAPI) IsAutoBuyTicket(ctx context.Context) bool {
    45  	return common.AutoBuyTicket
    46  }
    47  
    48  // GetBalance wacom
    49  func (s *PublicFusionAPI) GetBalance(ctx context.Context, assetID common.Hash, address common.Address, blockNr rpc.BlockNumber) (string, error) {
    50  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
    51  	if state == nil || err != nil {
    52  		return "0", err
    53  	}
    54  	b := state.GetBalance(assetID, address)
    55  	return b.String(), state.Error()
    56  }
    57  
    58  // GetAllBalances wacom
    59  func (s *PublicFusionAPI) GetAllBalances(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (map[common.Hash]string, error) {
    60  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
    61  	if state == nil || err != nil {
    62  		return make(map[common.Hash]string), err
    63  	}
    64  	b := state.GetAllBalances(address)
    65  	return b, state.Error()
    66  }
    67  
    68  // GetTimeLockBalance wacom
    69  func (s *PublicFusionAPI) GetTimeLockBalance(ctx context.Context, assetID common.Hash, address common.Address, blockNr rpc.BlockNumber) (*common.TimeLock, error) {
    70  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
    71  	if state == nil || err != nil {
    72  		return new(common.TimeLock), err
    73  	}
    74  	b := state.GetTimeLockBalance(assetID, address)
    75  	if state.Error() == nil {
    76  		b = b.ToDisplay()
    77  	}
    78  	return b, state.Error()
    79  }
    80  
    81  // GetTimeLockValueByInterval wacom
    82  func (s *PublicFusionAPI) GetTimeLockValueByInterval(ctx context.Context, assetID common.Hash, address common.Address, startTime, endTime uint64, blockNr rpc.BlockNumber) (string, error) {
    83  	state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
    84  	if state == nil || err != nil {
    85  		return "0", err
    86  	}
    87  	b := state.GetTimeLockBalance(assetID, address)
    88  	if state.Error() != nil {
    89  		return "0", state.Error()
    90  	}
    91  	if startTime < header.Time.Uint64() {
    92  		startTime = header.Time.Uint64()
    93  	}
    94  	if endTime == 0 {
    95  		endTime = common.TimeLockForever
    96  	}
    97  	return b.GetSpendableValue(startTime, endTime).String(), nil
    98  }
    99  
   100  // GetAllTimeLockBalances wacom
   101  func (s *PublicFusionAPI) GetAllTimeLockBalances(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (map[common.Hash]*common.TimeLock, error) {
   102  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
   103  	if state == nil || err != nil {
   104  		return make(map[common.Hash]*common.TimeLock), err
   105  	}
   106  	b := state.GetAllTimeLockBalances(address)
   107  	if state.Error() == nil {
   108  		for k, v := range b {
   109  			b[k] = v.ToDisplay()
   110  		}
   111  	}
   112  	return b, state.Error()
   113  }
   114  
   115  // GetRawTimeLockBalance wacom
   116  func (s *PublicFusionAPI) GetRawTimeLockBalance(ctx context.Context, assetID common.Hash, address common.Address, blockNr rpc.BlockNumber) (*common.TimeLock, error) {
   117  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
   118  	if state == nil || err != nil {
   119  		return new(common.TimeLock), err
   120  	}
   121  	b := state.GetTimeLockBalance(assetID, address)
   122  	return b, state.Error()
   123  }
   124  
   125  // GetAllRawTimeLockBalances wacom
   126  func (s *PublicFusionAPI) GetAllRawTimeLockBalances(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (map[common.Hash]*common.TimeLock, error) {
   127  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
   128  	if state == nil || err != nil {
   129  		return make(map[common.Hash]*common.TimeLock), err
   130  	}
   131  	b := state.GetAllTimeLockBalances(address)
   132  	return b, state.Error()
   133  }
   134  
   135  // GetNotation wacom
   136  func (s *PublicFusionAPI) GetNotation(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (uint64, error) {
   137  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
   138  	if state == nil || err != nil {
   139  		return 0, err
   140  	}
   141  	b := state.GetNotation(address)
   142  	return b, state.Error()
   143  }
   144  
   145  // GetAddressByNotation wacom
   146  func (s *PublicFusionAPI) GetAddressByNotation(ctx context.Context, notation uint64, blockNr rpc.BlockNumber) (common.Address, error) {
   147  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
   148  	if state == nil || err != nil {
   149  		return common.Address{}, err
   150  	}
   151  	address, err := state.GetAddressByNotation(notation)
   152  	if err != nil {
   153  		log.Error("GetAddressByNotation: error ", "err", err)
   154  		return common.Address{}, err
   155  	}
   156  	return address, nil
   157  }
   158  
   159  // AllNotation wacom
   160  func (s *PublicFusionAPI) AllNotation(ctx context.Context, blockNr rpc.BlockNumber) (map[common.Address]uint64, error) {
   161  	return nil, fmt.Errorf("AllNotations has been depreciated please use api.fusionnetwork.io")
   162  }
   163  
   164  // GetAsset wacom
   165  func (s *PublicFusionAPI) GetAsset(ctx context.Context, assetID common.Hash, blockNr rpc.BlockNumber) (*common.Asset, error) {
   166  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
   167  	if state == nil || err != nil {
   168  		return nil, err
   169  	}
   170  	if asset, err := state.GetAsset(assetID); err == nil {
   171  		return &asset, nil
   172  	}
   173  
   174  	// treat assetID as tx hash, deduct asset id from the tx
   175  	if id := s.getIDByTxHash(ctx, assetID, "AssetID"); id != (common.Hash{}) {
   176  		if asset, err := state.GetAsset(id); err == nil {
   177  			return &asset, nil
   178  		}
   179  	}
   180  	return nil, fmt.Errorf("Asset not found")
   181  }
   182  
   183  // AllAssets wacom
   184  func (s *PublicFusionAPI) AllAssets(ctx context.Context, blockNr rpc.BlockNumber) (map[common.Hash]common.Asset, error) {
   185  	return nil, fmt.Errorf("AllAssets has been depreciated, use api.fusionnetwork.io")
   186  }
   187  
   188  // AllAssetsByAddress wacom
   189  func (s *PublicFusionAPI) AllAssetsByAddress(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (map[common.Hash]common.Asset, error) {
   190  	return nil, fmt.Errorf("AllAssetsByAddress has been depreciated, use api.fusionnetwork.io")
   191  }
   192  
   193  // AssetExistForAddress wacom
   194  func (s *PublicFusionAPI) AssetExistForAddress(ctx context.Context, assetName string, address common.Address, blockNr rpc.BlockNumber) (common.Hash, error) {
   195  	return common.Hash{}, fmt.Errorf("AllAssetsByAddress has been depreciated, use api.fusionnetwork.io")
   196  }
   197  
   198  func (s *PublicFusionAPI) getAllTickets(ctx context.Context, blockNr rpc.BlockNumber) (common.TicketsDataSlice, error) {
   199  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
   200  	if state == nil || err != nil {
   201  		return nil, err
   202  	}
   203  	tickets, err := state.AllTickets()
   204  	if err == nil {
   205  		err = state.Error()
   206  	}
   207  	if err != nil {
   208  		log.Debug("AllTickets:apifsn.go unable to retrieve previous tickets")
   209  		return nil, fmt.Errorf("AllTickets:apifsn.go unable to retrieve previous tickets. error: %v", err)
   210  	}
   211  	return tickets, nil
   212  }
   213  
   214  // AllTickets wacom
   215  func (s *PublicFusionAPI) AllTickets(ctx context.Context, blockNr rpc.BlockNumber) (map[common.Hash]common.TicketDisplay, error) {
   216  	tickets, err := s.getAllTickets(ctx, blockNr)
   217  	if err != nil {
   218  		return nil, err
   219  	}
   220  	return tickets.ToMap(), nil
   221  }
   222  
   223  // TotalNumberOfTickets wacom
   224  func (s *PublicFusionAPI) TotalNumberOfTickets(ctx context.Context, blockNr rpc.BlockNumber) (int, error) {
   225  	tickets, err := s.getAllTickets(ctx, blockNr)
   226  	if err != nil {
   227  		return 0, err
   228  	}
   229  	return int(tickets.NumberOfTickets()), err
   230  }
   231  
   232  // TotalNumberOfTicketsByAddress wacom
   233  func (s *PublicFusionAPI) TotalNumberOfTicketsByAddress(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (int, error) {
   234  	tickets, err := s.getAllTickets(ctx, blockNr)
   235  	if err != nil {
   236  		return 0, err
   237  	}
   238  	return int(tickets.NumberOfTicketsByAddress(address)), err
   239  }
   240  
   241  // TicketPrice wacom
   242  func (s *PublicFusionAPI) TicketPrice(ctx context.Context, blockNr rpc.BlockNumber) (string, error) {
   243  	state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
   244  	if state == nil || err != nil {
   245  		return "", err
   246  	}
   247  	return common.TicketPrice(header.Number).String(), nil
   248  }
   249  
   250  // AllTicketsByAddress wacom
   251  func (s *PublicFusionAPI) AllTicketsByAddress(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (map[common.Hash]common.TicketDisplay, error) {
   252  	tickets, err := s.getAllTickets(ctx, blockNr)
   253  	if err != nil {
   254  		return nil, err
   255  	}
   256  	for _, v := range tickets {
   257  		if v.Owner == address {
   258  			return v.ToMap(), nil
   259  		}
   260  	}
   261  	return nil, nil
   262  }
   263  
   264  // TxAndReceipt wacom
   265  type TxAndReceipt struct {
   266  	FsnTxInput   interface{}            `json:"fsnTxInput,omitempty"`
   267  	Tx           *RPCTransaction        `json:"tx"`
   268  	Receipt      map[string]interface{} `json:"receipt"`
   269  	ReceiptFound bool                   `json:"receiptFound"`
   270  }
   271  
   272  // GetTransactionAndReceipt returns the transaction receipt for the given transaction hash.
   273  func (s *PublicFusionAPI) GetTransactionAndReceipt(ctx context.Context, hash common.Hash) (TxAndReceipt, error) {
   274  	// Try to return an already finalized transaction
   275  	var orgTx *RPCTransaction
   276  	tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash)
   277  	if tx != nil {
   278  		orgTx = newRPCTransaction(tx, blockHash, blockNumber, index)
   279  	} else if poolTx := s.b.GetPoolTransaction(hash); poolTx != nil {
   280  		// No finalized transaction, try to retrieve it from the pool
   281  		orgTx = newRPCPendingTransaction(poolTx)
   282  	} else {
   283  		return TxAndReceipt{}, fmt.Errorf("Tx not found")
   284  	}
   285  
   286  	var (
   287  		isFsnCall   = common.IsFsnCall(orgTx.To)
   288  		fsnLogTopic string
   289  		fsnLogData  interface{}
   290  		fsnTxInput  interface{}
   291  	)
   292  
   293  	if isFsnCall {
   294  		if decoded, err := datong.DecodeTxInput(orgTx.Input); err == nil {
   295  			fsnTxInput = decoded
   296  		}
   297  	}
   298  
   299  	txWithoutReceipt := TxAndReceipt{
   300  		Tx:           orgTx,
   301  		Receipt:      nil,
   302  		ReceiptFound: false,
   303  		FsnTxInput:   fsnTxInput,
   304  	}
   305  
   306  	if tx == nil {
   307  		return txWithoutReceipt, nil
   308  	}
   309  	receipts, err := s.b.GetReceipts(ctx, blockHash)
   310  	if err != nil || len(receipts) <= int(index) {
   311  		return txWithoutReceipt, nil
   312  	}
   313  	receipt := receipts[index]
   314  
   315  	var signer types.Signer = types.FrontierSigner{}
   316  	if tx.Protected() {
   317  		signer = types.NewEIP155Signer(tx.ChainId())
   318  	}
   319  	from, _ := types.Sender(signer, tx)
   320  
   321  	if isFsnCall && len(receipt.Logs) > 0 && len(receipt.Logs[0].Topics) > 0 {
   322  		log := receipt.Logs[0]
   323  		topic := log.Topics[0]
   324  		fsnCallFunc := common.FSNCallFunc(topic[common.HashLength-1])
   325  		fsnLogTopic = fsnCallFunc.Name()
   326  		if decodedLog, err := datong.DecodeLogData(log.Data); err == nil {
   327  			fsnLogData = decodedLog
   328  		}
   329  	}
   330  
   331  	fields := map[string]interface{}{
   332  		"blockHash":         blockHash,
   333  		"blockNumber":       hexutil.Uint64(blockNumber),
   334  		"transactionHash":   hash,
   335  		"transactionIndex":  hexutil.Uint64(index),
   336  		"from":              from,
   337  		"to":                tx.To(),
   338  		"gasUsed":           hexutil.Uint64(receipt.GasUsed),
   339  		"cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed),
   340  		"contractAddress":   nil,
   341  		"logs":              receipt.Logs,
   342  		"logsBloom":         receipt.Bloom,
   343  	}
   344  
   345  	if len(fsnLogTopic) != 0 {
   346  		fields["fsnLogTopic"] = fsnLogTopic
   347  		fields["fsnLogData"] = fsnLogData
   348  	}
   349  
   350  	// Assign receipt status or post state.
   351  	if len(receipt.PostState) > 0 {
   352  		fields["root"] = hexutil.Bytes(receipt.PostState)
   353  	} else {
   354  		fields["status"] = hexutil.Uint(receipt.Status)
   355  	}
   356  	if receipt.Logs == nil {
   357  		fields["logs"] = [][]*types.Log{}
   358  	}
   359  	// If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation
   360  	if receipt.ContractAddress != (common.Address{}) {
   361  		fields["contractAddress"] = receipt.ContractAddress
   362  	}
   363  	return TxAndReceipt{
   364  		Tx:           orgTx,
   365  		Receipt:      fields,
   366  		ReceiptFound: true,
   367  		FsnTxInput:   fsnTxInput,
   368  	}, nil
   369  }
   370  
   371  // AllInfoForAddress wacom
   372  type AllInfoForAddress struct {
   373  	Tickets   map[common.Hash]common.TicketDisplay `json:"tickets"`
   374  	Balances  map[common.Hash]string               `json:"balances"`
   375  	Timelocks map[common.Hash]*common.TimeLock     `json:"timeLockBalances"`
   376  	Notation  uint64                               `json:"notation"`
   377  }
   378  
   379  // AllInfoByAddress wacom
   380  func (s *PublicFusionAPI) AllInfoByAddress(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (AllInfoForAddress, error) {
   381  	allTickets, err := s.AllTicketsByAddress(ctx, address, blockNr)
   382  	if err != nil {
   383  		return AllInfoForAddress{}, err
   384  	}
   385  	allBalances, err := s.GetAllBalances(ctx, address, blockNr)
   386  	if err != nil {
   387  		return AllInfoForAddress{}, err
   388  	}
   389  	allTimeLockBalances, err := s.GetAllTimeLockBalances(ctx, address, blockNr)
   390  	if err != nil {
   391  		return AllInfoForAddress{}, err
   392  	}
   393  	notation, _ := s.GetNotation(ctx, address, blockNr)
   394  
   395  	return AllInfoForAddress{
   396  		Tickets:   allTickets,
   397  		Balances:  allBalances,
   398  		Timelocks: allTimeLockBalances,
   399  		Notation:  notation,
   400  	}, nil
   401  }
   402  
   403  func (s *PublicFusionAPI) getIDByTxHash(ctx context.Context, hash common.Hash, logKey string) common.Hash {
   404  	var id common.Hash
   405  	tx, blockHash, _, index := rawdb.ReadTransaction(s.b.ChainDb(), hash)
   406  	if tx == nil {
   407  		return id
   408  	}
   409  	// get from receipt's log
   410  	receipts, err := s.b.GetReceipts(ctx, blockHash)
   411  	if err == nil && len(receipts) > int(index) {
   412  		receipt := receipts[index]
   413  
   414  		for _, log := range receipt.Logs {
   415  			if log.Address != common.FSNCallAddress {
   416  				continue
   417  			}
   418  			maps := make(map[string]interface{})
   419  			err := json.Unmarshal(log.Data, &maps)
   420  			if err != nil {
   421  				continue
   422  			}
   423  
   424  			if _, hasError := maps["Error"]; hasError {
   425  				continue
   426  			}
   427  
   428  			idstr, idok := maps[logKey].(string)
   429  			if idok {
   430  				id = common.HexToHash(idstr)
   431  				return id
   432  			}
   433  
   434  		}
   435  	}
   436  	return id
   437  }
   438  
   439  // GetSwap wacom
   440  func (s *PublicFusionAPI) GetSwap(ctx context.Context, swapID common.Hash, blockNr rpc.BlockNumber) (*common.Swap, error) {
   441  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
   442  	if state == nil || err != nil {
   443  		return nil, err
   444  	}
   445  	if swap, err := state.GetSwap(swapID); err == nil {
   446  		return &swap, nil
   447  	}
   448  	// treat swapId as tx hash, deduct swap id from the tx
   449  	if id := s.getIDByTxHash(ctx, swapID, "SwapID"); id != (common.Hash{}) {
   450  		if swap, err := state.GetSwap(id); err == nil {
   451  			return &swap, nil
   452  		}
   453  	}
   454  	return nil, fmt.Errorf("Swap not found")
   455  }
   456  
   457  // GetMultiSwap wacom
   458  func (s *PublicFusionAPI) GetMultiSwap(ctx context.Context, swapID common.Hash, blockNr rpc.BlockNumber) (*common.MultiSwap, error) {
   459  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
   460  	if state == nil || err != nil {
   461  		return nil, err
   462  	}
   463  	if swap, err := state.GetMultiSwap(swapID); err == nil {
   464  		return &swap, nil
   465  	}
   466  	// treat swapId as tx hash, deduct swap id from the tx
   467  	if id := s.getIDByTxHash(ctx, swapID, "SwapID"); id != (common.Hash{}) {
   468  		if swap, err := state.GetMultiSwap(id); err == nil {
   469  			return &swap, nil
   470  		}
   471  	}
   472  	return nil, fmt.Errorf("MultiSwap not found")
   473  }
   474  
   475  // AllSwaps wacom
   476  func (s *PublicFusionAPI) AllSwaps(ctx context.Context, blockNr rpc.BlockNumber) (map[common.Hash]common.Swap, error) {
   477  	return nil, fmt.Errorf("AllSwaps has been depreciated please use api.fusionnetwork.io")
   478  }
   479  
   480  // AllSwapsByAddress wacom
   481  func (s *PublicFusionAPI) AllSwapsByAddress(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (map[common.Hash]common.Swap, error) {
   482  	return nil, fmt.Errorf("AllSwapsByAddress has been depreciated please use api.fusionnetwork.io")
   483  }
   484  
   485  type Summary struct {
   486  	TotalMiners  uint64 `json:"totalMiners"`
   487  	TotalTickets uint64 `json:"totalTickets"`
   488  }
   489  type Stake struct {
   490  	Owner   common.Address `json:"owner"`
   491  	Tickets uint64         `json:"tickets"`
   492  }
   493  type StakeSlice []Stake
   494  
   495  func (s StakeSlice) Len() int {
   496  	return len(s)
   497  }
   498  func (s StakeSlice) Swap(i, j int) {
   499  	s[i], s[j] = s[j], s[i]
   500  }
   501  func (s StakeSlice) Less(i, j int) bool {
   502  	return s[i].Tickets > s[j].Tickets
   503  }
   504  
   505  type StakeInfo struct {
   506  	StakeInfo StakeSlice `json:"stakeInfo"`
   507  	Summary   Summary    `json:"summary"`
   508  }
   509  
   510  // GetStakeInfo wacom
   511  func (s *PublicFusionAPI) GetStakeInfo(ctx context.Context, blockNr rpc.BlockNumber) (StakeInfo, error) {
   512  	stakeInfo := StakeInfo{
   513  		StakeInfo: make(StakeSlice, 0),
   514  	}
   515  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
   516  	if state == nil || err != nil {
   517  		return stakeInfo, fmt.Errorf("Only node using `archive' mode can get history states. error: %v", err)
   518  	}
   519  	tickets, err := state.AllTickets()
   520  	if err == nil {
   521  		err = state.Error()
   522  	}
   523  	if err != nil {
   524  		return stakeInfo, fmt.Errorf("Unable to retrieve all tickets. error: %v", err)
   525  	}
   526  	stakeInfo.Summary.TotalTickets, stakeInfo.Summary.TotalMiners = tickets.NumberOfTicketsAndOwners()
   527  	for _, v := range tickets {
   528  		stakeInfo.StakeInfo = append(stakeInfo.StakeInfo, Stake{v.Owner, uint64(len(v.Tickets))})
   529  	}
   530  	sort.Stable(stakeInfo.StakeInfo)
   531  	return stakeInfo, nil
   532  }
   533  
   534  // GetBlockAndReward wacom
   535  func (s *PublicFusionAPI) GetBlockReward(ctx context.Context, blockNr rpc.BlockNumber) (string, error) {
   536  	block, err := s.b.BlockByNumber(ctx, blockNr)
   537  	if err != nil {
   538  		return "", err
   539  	}
   540  	receipts, err := s.b.GetReceipts(ctx, block.Hash())
   541  	if err != nil {
   542  		return "", err
   543  	}
   544  	// block creation reward
   545  	reward := datong.CalcRewards(block.Number())
   546  	gasUses := make(map[common.Hash]uint64)
   547  	for _, receipt := range receipts {
   548  		gasUses[receipt.TxHash] = receipt.GasUsed
   549  	}
   550  	for _, tx := range block.Transactions() {
   551  		if gasUsed, ok := gasUses[tx.Hash()]; ok {
   552  			gasReward := new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(gasUsed))
   553  			if gasReward.Sign() > 0 {
   554  				// transaction gas reward
   555  				reward.Add(reward, gasReward)
   556  			}
   557  		}
   558  		if common.IsFsnCall(tx.To()) {
   559  			fsnCallParam := &common.FSNCallParam{}
   560  			rlp.DecodeBytes(tx.Data(), fsnCallParam)
   561  			feeReward := common.GetFsnCallFee(tx.To(), fsnCallParam.Func)
   562  			if feeReward.Sign() > 0 {
   563  				// transaction fee reward
   564  				reward.Add(reward, feeReward)
   565  			}
   566  		}
   567  	}
   568  	return reward.String(), nil
   569  }
   570  
   571  // GetLatestNotation wacom
   572  func (s *PublicFusionAPI) GetLatestNotation(ctx context.Context, blockNr rpc.BlockNumber) (uint64, error) {
   573  	state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
   574  	if state == nil || err != nil {
   575  		return 0, err
   576  	}
   577  	lastCount, err := state.GetNotationCount()
   578  	if err != nil {
   579  		return 0, err
   580  	}
   581  	latestNotation := state.CalcNotationDisplay(lastCount)
   582  	return latestNotation, state.Error()
   583  }
   584  
   585  type RetreatTicketInfo struct {
   586  	ID          common.Hash
   587  	Owner       common.Address
   588  	Height      uint64
   589  	StartTime   uint64
   590  	ExpireTime  uint64
   591  	Value       *big.Int
   592  	RetreatType string
   593  }
   594  
   595  // GetRetreatTickets wacom
   596  func (s *PublicFusionAPI) GetRetreatTickets(ctx context.Context, blockNr rpc.BlockNumber) ([]RetreatTicketInfo, error) {
   597  	result := make([]RetreatTicketInfo, 0)
   598  	header, err := s.b.HeaderByNumber(ctx, blockNr)
   599  	if err != nil || header == nil {
   600  		return result, fmt.Errorf("get block header failed, err=%v", err)
   601  	}
   602  	if header.Number.Sign() == 0 {
   603  		return result, nil
   604  	}
   605  
   606  	var tickets common.TicketsDataSlice
   607  	addRetreatTickets := func(ids []common.Hash, retreatType string) (err error) {
   608  		if len(ids) == 0 {
   609  			return nil
   610  		}
   611  		if tickets == nil {
   612  			prevNr := rpc.BlockNumber(header.Number.Int64() - 1)
   613  			tickets, err = s.getAllTickets(ctx, prevNr)
   614  			if err != nil {
   615  				return err
   616  			}
   617  		}
   618  		for _, tid := range ids {
   619  			tikcet, err := tickets.Get(tid)
   620  			if err != nil {
   621  				return err
   622  			}
   623  			retreat := RetreatTicketInfo{
   624  				ID:          tid,
   625  				Owner:       tikcet.Owner,
   626  				Height:      tikcet.Height,
   627  				StartTime:   tikcet.StartTime,
   628  				ExpireTime:  tikcet.ExpireTime,
   629  				Value:       tikcet.Value(),
   630  				RetreatType: retreatType,
   631  			}
   632  			result = append(result, retreat)
   633  		}
   634  		return nil
   635  	}
   636  
   637  	// add retreat tickets of miss mining
   638  	snap, _ := datong.NewSnapshotFromHeader(header)
   639  	if err := addRetreatTickets(snap.Retreat, "miss-mining"); err != nil {
   640  		return result, err
   641  	}
   642  
   643  	// add punish tickets of double blocking
   644  	block, err := s.b.BlockByNumber(ctx, blockNr)
   645  	if err != nil {
   646  		return result, err
   647  	}
   648  	receipts, err := s.b.GetReceipts(ctx, block.Hash())
   649  	if err != nil {
   650  		return result, err
   651  	}
   652  	var tids []common.Hash
   653  	for i, tx := range block.Transactions() {
   654  		if !common.IsFsnCall(tx.To()) {
   655  			continue
   656  		}
   657  		fsnCallParam := &common.FSNCallParam{}
   658  		rlp.DecodeBytes(tx.Data(), fsnCallParam)
   659  		if fsnCallParam.Func != common.ReportIllegalFunc {
   660  			continue
   661  		}
   662  		for _, l := range receipts[i].Logs {
   663  			punishTickets, _ := datong.DecodePunishTickets(l.Data)
   664  			tids = append(tids, punishTickets...)
   665  		}
   666  	}
   667  	if err := addRetreatTickets(tids, "double-blocking"); err != nil {
   668  		return result, err
   669  	}
   670  
   671  	return result, nil
   672  }
   673  
   674  //--------------------------------------------- PublicFusionAPI buile send tx args-------------------------------------
   675  func FSNCallArgsToSendTxArgs(args common.FSNBaseArgsInterface, funcType common.FSNCallFunc, funcData []byte) (*SendTxArgs, error) {
   676  	var param = common.FSNCallParam{Func: funcType, Data: funcData}
   677  	data, err := param.ToBytes()
   678  	if err != nil {
   679  		return nil, err
   680  	}
   681  	var argsData = hexutil.Bytes(data)
   682  	baseArgs := args.BaseArgs()
   683  	return &SendTxArgs{
   684  		From:     baseArgs.From,
   685  		To:       &common.FSNCallAddress,
   686  		Gas:      baseArgs.Gas,
   687  		GasPrice: baseArgs.GasPrice,
   688  		Value:    (*hexutil.Big)(big.NewInt(0)),
   689  		Nonce:    baseArgs.Nonce,
   690  		Data:     &argsData,
   691  		Input:    nil,
   692  	}, nil
   693  }
   694  
   695  func (s *PublicFusionAPI) BuildGenNotationSendTxArgs(ctx context.Context, args common.FusionBaseArgs) (*SendTxArgs, error) {
   696  	state, _, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
   697  	if state == nil || err != nil {
   698  		return nil, err
   699  	}
   700  	notation := state.GetNotation(args.From)
   701  	if notation != 0 {
   702  		return nil, fmt.Errorf("An address can have only one notation, you already have a mapped notation:%d", notation)
   703  	}
   704  
   705  	return FSNCallArgsToSendTxArgs(&args, common.GenNotationFunc, nil)
   706  }
   707  
   708  func (s *PublicFusionAPI) BuildGenAssetSendTxArgs(ctx context.Context, args common.GenAssetArgs) (*SendTxArgs, error) {
   709  	if err := args.ToParam().Check(common.BigMaxUint64); err != nil {
   710  		return nil, err
   711  	}
   712  
   713  	funcData, err := args.ToData()
   714  	if err != nil {
   715  		return nil, err
   716  	}
   717  	return FSNCallArgsToSendTxArgs(&args, common.GenAssetFunc, funcData)
   718  }
   719  
   720  func CheckAndSetToAddress(args *common.SendAssetArgs, state *state.StateDB) error {
   721  	if args.ToUSAN != 0 {
   722  		address, err := state.GetAddressByNotation(args.ToUSAN)
   723  		if err != nil {
   724  			return err
   725  		}
   726  		if args.To == (common.Address{}) {
   727  			args.To = address
   728  		} else if args.To != address {
   729  			return fmt.Errorf("'to' and 'toUSAN' conflicts")
   730  		}
   731  	}
   732  	if args.To == (common.Address{}) {
   733  		return fmt.Errorf("receiver address must be set and not zero address")
   734  	}
   735  	return nil
   736  }
   737  
   738  func (s *PublicFusionAPI) BuildSendAssetSendTxArgs(ctx context.Context, args common.SendAssetArgs) (*SendTxArgs, error) {
   739  	state, _, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
   740  	if state == nil || err != nil {
   741  		return nil, err
   742  	}
   743  	if err = CheckAndSetToAddress(&args, state); err != nil {
   744  		return nil, err
   745  	}
   746  	if err := args.ToParam().Check(common.BigMaxUint64); err != nil {
   747  		return nil, err
   748  	}
   749  
   750  	if state.GetBalance(args.AssetID, args.From).Cmp(args.Value.ToInt()) < 0 {
   751  		return nil, fmt.Errorf("not enough asset")
   752  	}
   753  
   754  	funcData, err := args.ToData()
   755  	if err != nil {
   756  		return nil, err
   757  	}
   758  	return FSNCallArgsToSendTxArgs(&args, common.SendAssetFunc, funcData)
   759  }
   760  
   761  func (s *PublicFusionAPI) BuildAssetToTimeLockSendTxArgs(ctx context.Context, args common.TimeLockArgs) (*SendTxArgs, error) {
   762  	state, header, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
   763  	if state == nil || err != nil {
   764  		return nil, err
   765  	}
   766  	if err = CheckAndSetToAddress(&args.SendAssetArgs, state); err != nil {
   767  		return nil, err
   768  	}
   769  	args.Init(common.AssetToTimeLock)
   770  	if err := args.ToParam().Check(common.BigMaxUint64, header.Time.Uint64()); err != nil {
   771  		return nil, err
   772  	}
   773  	needValue := common.NewTimeLock(&common.TimeLockItem{
   774  		StartTime: common.MaxUint64(uint64(*args.StartTime), header.Time.Uint64()),
   775  		EndTime:   uint64(*args.EndTime),
   776  		Value:     args.Value.ToInt(),
   777  	})
   778  	if err := needValue.IsValid(); err != nil {
   779  		return nil, fmt.Errorf("BuildAssetToTimeLockTx err:%v", err.Error())
   780  	}
   781  	if state.GetBalance(args.AssetID, args.From).Cmp(args.Value.ToInt()) < 0 {
   782  		return nil, fmt.Errorf("not enough asset")
   783  	}
   784  
   785  	funcData, err := args.ToData()
   786  	if err != nil {
   787  		return nil, err
   788  	}
   789  	return FSNCallArgsToSendTxArgs(&args, common.TimeLockFunc, funcData)
   790  }
   791  
   792  func (s *PublicFusionAPI) BuildTimeLockToTimeLockSendTxArgs(ctx context.Context, args common.TimeLockArgs) (*SendTxArgs, error) {
   793  	state, header, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
   794  	if state == nil || err != nil {
   795  		return nil, err
   796  	}
   797  	if err = CheckAndSetToAddress(&args.SendAssetArgs, state); err != nil {
   798  		return nil, err
   799  	}
   800  	args.Init(common.TimeLockToTimeLock)
   801  	if err := args.ToParam().Check(common.BigMaxUint64, header.Time.Uint64()); err != nil {
   802  		return nil, err
   803  	}
   804  	needValue := common.NewTimeLock(&common.TimeLockItem{
   805  		StartTime: common.MaxUint64(uint64(*args.StartTime), header.Time.Uint64()),
   806  		EndTime:   uint64(*args.EndTime),
   807  		Value:     args.Value.ToInt(),
   808  	})
   809  	if err := needValue.IsValid(); err != nil {
   810  		return nil, fmt.Errorf("BuildTimeLockToTimeLockTx err:%v", err.Error())
   811  	}
   812  
   813  	if state.GetTimeLockBalance(args.AssetID, args.From).Cmp(needValue) < 0 {
   814  		return nil, fmt.Errorf("not enough time lock balance")
   815  	}
   816  
   817  	funcData, err := args.ToData()
   818  	if err != nil {
   819  		return nil, err
   820  	}
   821  	return FSNCallArgsToSendTxArgs(&args, common.TimeLockFunc, funcData)
   822  }
   823  
   824  func (s *PublicFusionAPI) BuildTimeLockToAssetSendTxArgs(ctx context.Context, args common.TimeLockArgs) (*SendTxArgs, error) {
   825  	state, header, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
   826  	if state == nil || err != nil {
   827  		return nil, err
   828  	}
   829  	if err = CheckAndSetToAddress(&args.SendAssetArgs, state); err != nil {
   830  		return nil, err
   831  	}
   832  	args.Init(common.TimeLockToAsset)
   833  	*(*uint64)(args.StartTime) = header.Time.Uint64()
   834  	*(*uint64)(args.EndTime) = common.TimeLockForever
   835  	if err := args.ToParam().Check(common.BigMaxUint64, header.Time.Uint64()); err != nil {
   836  		return nil, err
   837  	}
   838  	needValue := common.NewTimeLock(&common.TimeLockItem{
   839  		StartTime: uint64(*args.StartTime),
   840  		EndTime:   uint64(*args.EndTime),
   841  		Value:     args.Value.ToInt(),
   842  	})
   843  	if err := needValue.IsValid(); err != nil {
   844  		return nil, fmt.Errorf("BuildTimeLockToAssetTx err:%v", err.Error())
   845  	}
   846  	if state.GetTimeLockBalance(args.AssetID, args.From).Cmp(needValue) < 0 {
   847  		return nil, fmt.Errorf("not enough time lock balance")
   848  	}
   849  
   850  	funcData, err := args.ToData()
   851  	if err != nil {
   852  		return nil, err
   853  	}
   854  	return FSNCallArgsToSendTxArgs(&args, common.TimeLockFunc, funcData)
   855  }
   856  
   857  func (s *PublicFusionAPI) BuildSendTimeLockSendTxArgs(ctx context.Context, args common.TimeLockArgs) (*SendTxArgs, error) {
   858  	state, header, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
   859  	if state == nil || err != nil {
   860  		return nil, err
   861  	}
   862  	if err = CheckAndSetToAddress(&args.SendAssetArgs, state); err != nil {
   863  		return nil, err
   864  	}
   865  	args.Init(common.SmartTransfer)
   866  	if err := args.ToParam().Check(common.BigMaxUint64, header.Time.Uint64()); err != nil {
   867  		return nil, err
   868  	}
   869  	needValue := common.NewTimeLock(&common.TimeLockItem{
   870  		StartTime: common.MaxUint64(uint64(*args.StartTime), header.Time.Uint64()),
   871  		EndTime:   uint64(*args.EndTime),
   872  		Value:     args.Value.ToInt(),
   873  	})
   874  	if err := needValue.IsValid(); err != nil {
   875  		return nil, fmt.Errorf("BuildSendTimeLockSendTxArgs err:%v", err.Error())
   876  	}
   877  
   878  	funcData, err := args.ToData()
   879  	if err != nil {
   880  		return nil, err
   881  	}
   882  	return FSNCallArgsToSendTxArgs(&args, common.TimeLockFunc, funcData)
   883  }
   884  
   885  func (s *PublicFusionAPI) BuildBuyTicketSendTxArgs(ctx context.Context, args common.BuyTicketArgs) (*SendTxArgs, error) {
   886  	state, header, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
   887  	if state == nil || err != nil {
   888  		return nil, err
   889  	}
   890  
   891  	if doesTicketPurchaseExistsForBlock(header.Number.Int64(), args.From) {
   892  		return nil, fmt.Errorf("Purchase of BuyTicket for this block already submitted")
   893  	}
   894  
   895  	parentTime := header.Time.Uint64()
   896  	args.Init(parentTime)
   897  	if err := args.ToParam().Check(common.BigMaxUint64, parentTime); err != nil {
   898  		return nil, err
   899  	}
   900  
   901  	start := uint64(*args.Start)
   902  	end := uint64(*args.End)
   903  	value := common.TicketPrice(header.Number)
   904  	needValue := common.NewTimeLock(&common.TimeLockItem{
   905  		StartTime: common.MaxUint64(start, header.Time.Uint64()),
   906  		EndTime:   end,
   907  		Value:     value,
   908  	})
   909  	if err := needValue.IsValid(); err != nil {
   910  		return nil, fmt.Errorf("BuildBuyTicketTx err:%v", err.Error())
   911  	}
   912  
   913  	if state.GetTimeLockBalance(common.SystemAssetID, args.From).Cmp(needValue) < 0 {
   914  		if state.GetBalance(common.SystemAssetID, args.From).Cmp(value) < 0 {
   915  			return nil, fmt.Errorf("not enough time lock or asset balance")
   916  		}
   917  	}
   918  
   919  	funcData, err := args.ToData()
   920  	if err != nil {
   921  		return nil, err
   922  	}
   923  	return FSNCallArgsToSendTxArgs(&args, common.BuyTicketFunc, funcData)
   924  }
   925  
   926  func (s *PublicFusionAPI) BuildAssetValueChangeSendTxArgs(ctx context.Context, args common.AssetValueChangeExArgs) (*SendTxArgs, error) {
   927  	state, _, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
   928  	if state == nil || err != nil {
   929  		return nil, err
   930  	}
   931  
   932  	if err := args.ToParam().Check(common.BigMaxUint64); err != nil {
   933  		return nil, err
   934  	}
   935  
   936  	asset, assetError := state.GetAsset(args.AssetID)
   937  	if assetError != nil {
   938  		return nil, fmt.Errorf("asset not found")
   939  	}
   940  
   941  	if !asset.CanChange {
   942  		return nil, fmt.Errorf("asset can't inc or dec")
   943  	}
   944  
   945  	if asset.Owner != args.From {
   946  		return nil, fmt.Errorf("can only be changed by onwer")
   947  	}
   948  
   949  	if asset.Owner != args.To && !args.IsInc {
   950  		return nil, fmt.Errorf("decrement can only happen to asset's own account")
   951  	}
   952  
   953  	currentBalance := state.GetBalance(args.AssetID, args.To)
   954  	val := args.Value.ToInt()
   955  	if !args.IsInc {
   956  		if currentBalance.Cmp(val) < 0 {
   957  			return nil, fmt.Errorf("not enough asset")
   958  		}
   959  	}
   960  
   961  	funcData, err := args.ToData()
   962  	if err != nil {
   963  		return nil, err
   964  	}
   965  	return FSNCallArgsToSendTxArgs(&args, common.AssetValueChangeFunc, funcData)
   966  }
   967  
   968  func (s *PublicFusionAPI) BuildMakeSwapSendTxArgs(ctx context.Context, args common.MakeSwapArgs) (*SendTxArgs, error) {
   969  	state, header, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
   970  	if state == nil || err != nil {
   971  		return nil, err
   972  	}
   973  
   974  	args.Init(header.Time)
   975  	now := uint64(time.Now().Unix())
   976  	if err := args.ToParam().Check(common.BigMaxUint64, now); err != nil {
   977  		return nil, err
   978  	}
   979  
   980  	total := new(big.Int).Mul(args.MinFromAmount.ToInt(), args.SwapSize)
   981  	start := uint64(*args.FromStartTime)
   982  	end := uint64(*args.FromEndTime)
   983  
   984  	if args.FromAssetID == common.OwnerUSANAssetID {
   985  		notation := state.GetNotation(args.From)
   986  		if notation == 0 {
   987  			return nil, fmt.Errorf("from address does not have a notation")
   988  		}
   989  	} else if start == common.TimeLockNow && end == common.TimeLockForever {
   990  		if state.GetBalance(args.FromAssetID, args.From).Cmp(total) < 0 {
   991  			return nil, fmt.Errorf("not enough from asset")
   992  		}
   993  	} else {
   994  		needValue := common.NewTimeLock(&common.TimeLockItem{
   995  			StartTime: common.MaxUint64(start, header.Time.Uint64()),
   996  			EndTime:   end,
   997  			Value:     total,
   998  		})
   999  		if err := needValue.IsValid(); err != nil {
  1000  			return nil, fmt.Errorf("BuildMakeSwapTx from err:%v", err.Error())
  1001  		}
  1002  		if state.GetTimeLockBalance(args.FromAssetID, args.From).Cmp(needValue) < 0 {
  1003  			if state.GetBalance(args.FromAssetID, args.From).Cmp(total) < 0 {
  1004  				return nil, fmt.Errorf("not enough time lock or asset balance")
  1005  			}
  1006  		}
  1007  	}
  1008  
  1009  	funcData, err := args.ToData()
  1010  	if err != nil {
  1011  		return nil, err
  1012  	}
  1013  	return FSNCallArgsToSendTxArgs(&args, common.MakeSwapFuncExt, funcData)
  1014  }
  1015  
  1016  func (s *PublicFusionAPI) BuildRecallSwapSendTxArgs(ctx context.Context, args common.RecallSwapArgs) (*SendTxArgs, error) {
  1017  	state, _, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
  1018  	if state == nil || err != nil {
  1019  		return nil, err
  1020  	}
  1021  
  1022  	var swap common.Swap
  1023  	swap, err = state.GetSwap(args.SwapID)
  1024  	if err != nil {
  1025  		return nil, err
  1026  	}
  1027  
  1028  	if err := args.ToParam().Check(common.BigMaxUint64, &swap); err != nil {
  1029  		return nil, err
  1030  	}
  1031  
  1032  	if swap.Owner != args.From {
  1033  		return nil, fmt.Errorf("Must be swap onwer can recall")
  1034  	}
  1035  
  1036  	funcData, err := args.ToData()
  1037  	if err != nil {
  1038  		return nil, err
  1039  	}
  1040  	return FSNCallArgsToSendTxArgs(&args, common.RecallSwapFunc, funcData)
  1041  }
  1042  
  1043  func (s *PublicFusionAPI) BuildTakeSwapSendTxArgs(ctx context.Context, args common.TakeSwapArgs) (*SendTxArgs, error) {
  1044  	state, _, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
  1045  	if state == nil || err != nil {
  1046  		return nil, err
  1047  	}
  1048  	var swap common.Swap
  1049  	swap, err = state.GetSwap(args.SwapID)
  1050  	if err != nil {
  1051  		return nil, err
  1052  	}
  1053  
  1054  	now := uint64(time.Now().Unix())
  1055  	if err := args.ToParam().Check(common.BigMaxUint64, &swap, now); err != nil {
  1056  		return nil, err
  1057  	}
  1058  
  1059  	total := new(big.Int).Mul(swap.MinToAmount, args.Size)
  1060  	start := swap.ToStartTime
  1061  	end := swap.ToEndTime
  1062  
  1063  	if start == common.TimeLockNow && end == common.TimeLockForever {
  1064  		if state.GetBalance(swap.ToAssetID, args.From).Cmp(total) < 0 {
  1065  			return nil, fmt.Errorf("not enough from asset")
  1066  		}
  1067  	} else {
  1068  		needValue := common.NewTimeLock(&common.TimeLockItem{
  1069  			StartTime: start,
  1070  			EndTime:   end,
  1071  			Value:     total,
  1072  		})
  1073  		if err := needValue.IsValid(); err != nil {
  1074  			return nil, fmt.Errorf("BuildTakeSwapTx to err:%v", err.Error())
  1075  		}
  1076  		if state.GetTimeLockBalance(swap.ToAssetID, args.From).Cmp(needValue) < 0 {
  1077  			if state.GetBalance(swap.ToAssetID, args.From).Cmp(total) < 0 {
  1078  				return nil, fmt.Errorf("not enough time lock or asset balance")
  1079  			}
  1080  		}
  1081  	}
  1082  
  1083  	funcData, err := args.ToData()
  1084  	if err != nil {
  1085  		return nil, err
  1086  	}
  1087  	return FSNCallArgsToSendTxArgs(&args, common.TakeSwapFuncExt, funcData)
  1088  }
  1089  
  1090  func (s *PublicFusionAPI) BuildMakeMultiSwapSendTxArgs(ctx context.Context, args common.MakeMultiSwapArgs) (*SendTxArgs, error) {
  1091  	state, header, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
  1092  	if state == nil || err != nil {
  1093  		return nil, err
  1094  	}
  1095  
  1096  	args.Init(header.Time)
  1097  	now := uint64(time.Now().Unix())
  1098  	if err := args.ToParam().Check(common.BigMaxUint64, now); err != nil {
  1099  		return nil, err
  1100  	}
  1101  
  1102  	ln := len(args.MinFromAmount)
  1103  	for i := 0; i < ln; i++ {
  1104  		total := new(big.Int).Mul(args.MinFromAmount[i].ToInt(), args.SwapSize)
  1105  		start := uint64(*args.FromStartTime[i])
  1106  		end := uint64(*args.FromEndTime[i])
  1107  
  1108  		if args.FromAssetID[i] == common.OwnerUSANAssetID {
  1109  			return nil, fmt.Errorf("USANs cannot be multi-swapped")
  1110  		} else if start == common.TimeLockNow && end == common.TimeLockForever {
  1111  			if state.GetBalance(args.FromAssetID[i], args.From).Cmp(total) < 0 {
  1112  				return nil, fmt.Errorf("not enough from asset")
  1113  			}
  1114  		} else {
  1115  			needValue := common.NewTimeLock(&common.TimeLockItem{
  1116  				StartTime: common.MaxUint64(start, header.Time.Uint64()),
  1117  				EndTime:   end,
  1118  				Value:     total,
  1119  			})
  1120  			if err := needValue.IsValid(); err != nil {
  1121  				return nil, fmt.Errorf("BuildMakeSwapTx from err:%v", err.Error())
  1122  			}
  1123  			if state.GetTimeLockBalance(args.FromAssetID[i], args.From).Cmp(needValue) < 0 {
  1124  				if state.GetBalance(args.FromAssetID[i], args.From).Cmp(total) < 0 {
  1125  					return nil, fmt.Errorf("not enough time lock or asset balance")
  1126  				}
  1127  			}
  1128  		}
  1129  	}
  1130  
  1131  	funcData, err := args.ToData()
  1132  	if err != nil {
  1133  		return nil, err
  1134  	}
  1135  	return FSNCallArgsToSendTxArgs(&args, common.MakeMultiSwapFunc, funcData)
  1136  }
  1137  
  1138  func (s *PublicFusionAPI) BuildRecallMultiSwapSendTxArgs(ctx context.Context, args common.RecallMultiSwapArgs) (*SendTxArgs, error) {
  1139  	state, _, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
  1140  	if state == nil || err != nil {
  1141  		return nil, err
  1142  	}
  1143  
  1144  	var swap common.MultiSwap
  1145  	swap, err = state.GetMultiSwap(args.SwapID)
  1146  	if err != nil {
  1147  		return nil, err
  1148  	}
  1149  
  1150  	if err := args.ToParam().Check(common.BigMaxUint64, &swap); err != nil {
  1151  		return nil, err
  1152  	}
  1153  
  1154  	if swap.Owner != args.From {
  1155  		return nil, fmt.Errorf("Must be swap onwer can recall")
  1156  	}
  1157  
  1158  	funcData, err := args.ToData()
  1159  	if err != nil {
  1160  		return nil, err
  1161  	}
  1162  	return FSNCallArgsToSendTxArgs(&args, common.RecallMultiSwapFunc, funcData)
  1163  }
  1164  
  1165  func (s *PublicFusionAPI) BuildTakeMultiSwapSendTxArgs(ctx context.Context, args common.TakeMultiSwapArgs) (*SendTxArgs, error) {
  1166  	state, _, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
  1167  	if state == nil || err != nil {
  1168  		return nil, err
  1169  	}
  1170  	var swap common.MultiSwap
  1171  	swap, err = state.GetMultiSwap(args.SwapID)
  1172  	if err != nil {
  1173  		return nil, err
  1174  	}
  1175  
  1176  	now := uint64(time.Now().Unix())
  1177  	if err := args.ToParam().Check(common.BigMaxUint64, &swap, now); err != nil {
  1178  		return nil, err
  1179  	}
  1180  
  1181  	ln := len(swap.MinToAmount)
  1182  	for i := 0; i < ln; i++ {
  1183  		total := new(big.Int).Mul(swap.MinToAmount[i], args.Size)
  1184  		start := swap.ToStartTime[i]
  1185  		end := swap.ToEndTime[i]
  1186  
  1187  		if start == common.TimeLockNow && end == common.TimeLockForever {
  1188  			if state.GetBalance(swap.ToAssetID[i], args.From).Cmp(total) < 0 {
  1189  				return nil, fmt.Errorf("not enough from asset")
  1190  			}
  1191  		} else {
  1192  			needValue := common.NewTimeLock(&common.TimeLockItem{
  1193  				StartTime: start,
  1194  				EndTime:   end,
  1195  				Value:     total,
  1196  			})
  1197  			if err := needValue.IsValid(); err != nil {
  1198  				return nil, fmt.Errorf("BuildTakeSwapTx to err:%v", err.Error())
  1199  			}
  1200  			if state.GetTimeLockBalance(swap.ToAssetID[i], args.From).Cmp(needValue) < 0 {
  1201  				if state.GetBalance(swap.ToAssetID[i], args.From).Cmp(total) < 0 {
  1202  					return nil, fmt.Errorf("not enough time lock or asset balance")
  1203  				}
  1204  			}
  1205  		}
  1206  	}
  1207  
  1208  	funcData, err := args.ToData()
  1209  	if err != nil {
  1210  		return nil, err
  1211  	}
  1212  	return FSNCallArgsToSendTxArgs(&args, common.TakeMultiSwapFunc, funcData)
  1213  }
  1214  
  1215  //--------------------------------------------- PrivateFusionAPI -------------------------------------
  1216  
  1217  // PrivateFusionAPI ss
  1218  type PrivateFusionAPI struct {
  1219  	PublicFusionAPI
  1220  	nonceLock *AddrLocker
  1221  	papi      *PrivateAccountAPI
  1222  }
  1223  
  1224  // NewPrivateFusionAPI ss
  1225  func NewPrivateFusionAPI(b Backend, nonceLock *AddrLocker, papi *PrivateAccountAPI) *PrivateFusionAPI {
  1226  	return &PrivateFusionAPI{
  1227  		PublicFusionAPI: *NewPublicFusionAPI(b),
  1228  		nonceLock:       nonceLock,
  1229  		papi:            papi,
  1230  	}
  1231  }
  1232  
  1233  // GenNotation ss
  1234  func (s *PrivateFusionAPI) GenNotation(ctx context.Context, args common.FusionBaseArgs, passwd string) (common.Hash, error) {
  1235  	sendArgs, err := s.BuildGenNotationSendTxArgs(ctx, args)
  1236  	if err != nil {
  1237  		return common.Hash{}, err
  1238  	}
  1239  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1240  }
  1241  
  1242  // GenAsset ss
  1243  func (s *PrivateFusionAPI) GenAsset(ctx context.Context, args common.GenAssetArgs, passwd string) (common.Hash, error) {
  1244  	sendArgs, err := s.BuildGenAssetSendTxArgs(ctx, args)
  1245  	if err != nil {
  1246  		return common.Hash{}, err
  1247  	}
  1248  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1249  }
  1250  
  1251  // SendAsset ss
  1252  func (s *PrivateFusionAPI) SendAsset(ctx context.Context, args common.SendAssetArgs, passwd string) (common.Hash, error) {
  1253  	sendArgs, err := s.BuildSendAssetSendTxArgs(ctx, args)
  1254  	if err != nil {
  1255  		return common.Hash{}, err
  1256  	}
  1257  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1258  }
  1259  
  1260  // AssetToTimeLock ss
  1261  func (s *PrivateFusionAPI) AssetToTimeLock(ctx context.Context, args common.TimeLockArgs, passwd string) (common.Hash, error) {
  1262  	sendArgs, err := s.BuildAssetToTimeLockSendTxArgs(ctx, args)
  1263  	if err != nil {
  1264  		return common.Hash{}, err
  1265  	}
  1266  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1267  }
  1268  
  1269  // TimeLockToTimeLock ss
  1270  func (s *PrivateFusionAPI) TimeLockToTimeLock(ctx context.Context, args common.TimeLockArgs, passwd string) (common.Hash, error) {
  1271  	sendArgs, err := s.BuildTimeLockToTimeLockSendTxArgs(ctx, args)
  1272  	if err != nil {
  1273  		return common.Hash{}, err
  1274  	}
  1275  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1276  }
  1277  
  1278  // TimeLockToAsset ss
  1279  func (s *PrivateFusionAPI) TimeLockToAsset(ctx context.Context, args common.TimeLockArgs, passwd string) (common.Hash, error) {
  1280  	sendArgs, err := s.BuildTimeLockToAssetSendTxArgs(ctx, args)
  1281  	if err != nil {
  1282  		return common.Hash{}, err
  1283  	}
  1284  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1285  }
  1286  
  1287  // SendTimeLock ss
  1288  func (s *PrivateFusionAPI) SendTimeLock(ctx context.Context, args common.TimeLockArgs, passwd string) (common.Hash, error) {
  1289  	sendArgs, err := s.BuildSendTimeLockSendTxArgs(ctx, args)
  1290  	if err != nil {
  1291  		return common.Hash{}, err
  1292  	}
  1293  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1294  }
  1295  
  1296  /** on our public gateways too many buyTickets are past through
  1297  this cache of purchase on block will stop multiple purchase
  1298  attempt on a block (which state_transistion also flags).
  1299  the goals is to limit the number of buytickets being processed
  1300  if it is know that they will fail anyway
  1301  */
  1302  func doesTicketPurchaseExistsForBlock(blockNbr int64, from common.Address) bool {
  1303  	buyTicketOnBlockMapMutex.Lock()
  1304  	defer buyTicketOnBlockMapMutex.Unlock()
  1305  	if lastBlockOfBuyTickets == 0 || lastBlockOfBuyTickets != blockNbr {
  1306  		lastBlockOfBuyTickets = blockNbr
  1307  		buyTicketOnBlockMap = make(map[common.Address]bool)
  1308  	}
  1309  	_, found := buyTicketOnBlockMap[from]
  1310  	return found
  1311  }
  1312  
  1313  // only record on purchase ticket successfully
  1314  func addTicketPurchaseForBlock(from common.Address) {
  1315  	buyTicketOnBlockMapMutex.Lock()
  1316  	defer buyTicketOnBlockMapMutex.Unlock()
  1317  	buyTicketOnBlockMap[from] = true
  1318  }
  1319  
  1320  // BuyTicket ss
  1321  func (s *PrivateFusionAPI) BuyTicket(ctx context.Context, args common.BuyTicketArgs, passwd string) (common.Hash, error) {
  1322  	sendArgs, err := s.BuildBuyTicketSendTxArgs(ctx, args)
  1323  	if err != nil {
  1324  		return common.Hash{}, err
  1325  	}
  1326  	hash, err := s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1327  	if err != nil {
  1328  		return common.Hash{}, err
  1329  	}
  1330  	addTicketPurchaseForBlock(args.From)
  1331  	return hash, err
  1332  }
  1333  
  1334  // IncAsset ss
  1335  func (s *PrivateFusionAPI) IncAsset(ctx context.Context, args common.AssetValueChangeExArgs, passwd string) (common.Hash, error) {
  1336  	args.IsInc = true
  1337  	sendArgs, err := s.BuildAssetValueChangeSendTxArgs(ctx, args)
  1338  	if err != nil {
  1339  		return common.Hash{}, err
  1340  	}
  1341  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1342  }
  1343  
  1344  // DecAsset ss
  1345  func (s *PrivateFusionAPI) DecAsset(ctx context.Context, args common.AssetValueChangeExArgs, passwd string) (common.Hash, error) {
  1346  	args.IsInc = false
  1347  	sendArgs, err := s.BuildAssetValueChangeSendTxArgs(ctx, args)
  1348  	if err != nil {
  1349  		return common.Hash{}, err
  1350  	}
  1351  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1352  }
  1353  
  1354  // MakeSwap ss
  1355  func (s *PrivateFusionAPI) MakeSwap(ctx context.Context, args common.MakeSwapArgs, passwd string) (common.Hash, error) {
  1356  	sendArgs, err := s.BuildMakeSwapSendTxArgs(ctx, args)
  1357  	if err != nil {
  1358  		return common.Hash{}, err
  1359  	}
  1360  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1361  }
  1362  
  1363  // RecallSwap ss
  1364  func (s *PrivateFusionAPI) RecallSwap(ctx context.Context, args common.RecallSwapArgs, passwd string) (common.Hash, error) {
  1365  	sendArgs, err := s.BuildRecallSwapSendTxArgs(ctx, args)
  1366  	if err != nil {
  1367  		return common.Hash{}, err
  1368  	}
  1369  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1370  }
  1371  
  1372  // TakeSwap ss
  1373  func (s *PrivateFusionAPI) TakeSwap(ctx context.Context, args common.TakeSwapArgs, passwd string) (common.Hash, error) {
  1374  	sendArgs, err := s.BuildTakeSwapSendTxArgs(ctx, args)
  1375  	if err != nil {
  1376  		return common.Hash{}, err
  1377  	}
  1378  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1379  }
  1380  
  1381  // MakeMultiSwap ss
  1382  func (s *PrivateFusionAPI) MakeMultiSwap(ctx context.Context, args common.MakeMultiSwapArgs, passwd string) (common.Hash, error) {
  1383  	sendArgs, err := s.BuildMakeMultiSwapSendTxArgs(ctx, args)
  1384  	if err != nil {
  1385  		return common.Hash{}, err
  1386  	}
  1387  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1388  }
  1389  
  1390  // RecallMultiSwap ss
  1391  func (s *PrivateFusionAPI) RecallMultiSwap(ctx context.Context, args common.RecallMultiSwapArgs, passwd string) (common.Hash, error) {
  1392  	sendArgs, err := s.BuildRecallMultiSwapSendTxArgs(ctx, args)
  1393  	if err != nil {
  1394  		return common.Hash{}, err
  1395  	}
  1396  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1397  }
  1398  
  1399  // TakeMultiSwap ss
  1400  func (s *PrivateFusionAPI) TakeMultiSwap(ctx context.Context, args common.TakeMultiSwapArgs, passwd string) (common.Hash, error) {
  1401  	sendArgs, err := s.BuildTakeMultiSwapSendTxArgs(ctx, args)
  1402  	if err != nil {
  1403  		return common.Hash{}, err
  1404  	}
  1405  	return s.papi.SendTransaction(ctx, *sendArgs, passwd)
  1406  }
  1407  
  1408  //--------------------------------------------- FusionTransactionAPI -------------------------------------
  1409  
  1410  // FusionTransactionAPI ss
  1411  type FusionTransactionAPI struct {
  1412  	b         Backend
  1413  	pubapi    *PublicFusionAPI
  1414  	nonceLock *AddrLocker
  1415  	txapi     *PublicTransactionPoolAPI
  1416  }
  1417  
  1418  var fusionTransactionAPI *FusionTransactionAPI
  1419  
  1420  // NewFusionTransactionAPI ss
  1421  func NewFusionTransactionAPI(b Backend, nonceLock *AddrLocker, txapi *PublicTransactionPoolAPI) *FusionTransactionAPI {
  1422  	fusionTransactionAPI = &FusionTransactionAPI{
  1423  		b:         b,
  1424  		pubapi:    NewPublicFusionAPI(b),
  1425  		nonceLock: nonceLock,
  1426  		txapi:     txapi,
  1427  	}
  1428  	return fusionTransactionAPI
  1429  }
  1430  
  1431  // auto buy ticket
  1432  func AutoBuyTicket(enable bool) {
  1433  	if enable {
  1434  		_, err := fusionTransactionAPI.b.Coinbase()
  1435  		if err != nil {
  1436  			log.Warn("AutoBuyTicket not enabled as no coinbase account exist")
  1437  			enable = false
  1438  		}
  1439  	}
  1440  	common.AutoBuyTicket = enable
  1441  
  1442  	for {
  1443  		<-common.AutoBuyTicketChan
  1444  	COMSUMEALL:
  1445  		for {
  1446  			select {
  1447  			case <-common.AutoBuyTicketChan:
  1448  			default:
  1449  				break COMSUMEALL
  1450  			}
  1451  		}
  1452  
  1453  		// prevent auto buy ticket in syncing
  1454  		if !fusionTransactionAPI.b.IsMining() {
  1455  			common.DebugInfo("ignore AutoBuyTicket as isMining is false")
  1456  			continue
  1457  		}
  1458  
  1459  		coinbase, err := fusionTransactionAPI.b.Coinbase()
  1460  		if err == nil {
  1461  			fbase := common.FusionBaseArgs{From: coinbase}
  1462  			args := common.BuyTicketArgs{FusionBaseArgs: fbase}
  1463  			fusionTransactionAPI.BuyTicket(context.TODO(), args)
  1464  		}
  1465  	}
  1466  }
  1467  
  1468  // report illegal
  1469  func ReportIllegal() {
  1470  	for {
  1471  		select {
  1472  		case content := <-common.ReportIllegalChan:
  1473  			coinbase, err := fusionTransactionAPI.b.Coinbase()
  1474  			if err == nil {
  1475  				args := common.FusionBaseArgs{From: coinbase}
  1476  				fusionTransactionAPI.ReportIllegal(context.TODO(), args, content)
  1477  			}
  1478  		}
  1479  	}
  1480  }
  1481  
  1482  func (s *FusionTransactionAPI) ReportIllegal(ctx context.Context, args common.FusionBaseArgs, content []byte) (common.Hash, error) {
  1483  	oldtx := s.b.GetPoolTransactionByPredicate(func(tx *types.Transaction) bool {
  1484  		param := common.FSNCallParam{}
  1485  		rlp.DecodeBytes(tx.Data(), &param)
  1486  		return param.Func == common.ReportIllegalFunc && bytes.Equal(param.Data, content)
  1487  	})
  1488  	if oldtx != nil {
  1489  		return common.Hash{}, fmt.Errorf("ReportIllegal: already reported in txpool")
  1490  	}
  1491  	sendArgs, err := FSNCallArgsToSendTxArgs(&args, common.ReportIllegalFunc, content)
  1492  	if err != nil {
  1493  		return common.Hash{}, err
  1494  	}
  1495  	tx, err := s.buildTransaction(ctx, *sendArgs)
  1496  	if err != nil {
  1497  		return common.Hash{}, err
  1498  	}
  1499  	return s.sendTransaction(ctx, args.From, tx)
  1500  }
  1501  
  1502  func (s *FusionTransactionAPI) buildTransaction(ctx context.Context, args SendTxArgs) (*types.Transaction, error) {
  1503  	if args.Nonce == nil {
  1504  		s.nonceLock.LockAddr(args.From)
  1505  		defer s.nonceLock.UnlockAddr(args.From)
  1506  	}
  1507  	if err := args.setDefaults(ctx, s.b); err != nil {
  1508  		return nil, err
  1509  	}
  1510  	tx := args.toTransaction()
  1511  	return tx, nil
  1512  }
  1513  
  1514  func (s *FusionTransactionAPI) sendTransaction(ctx context.Context, from common.Address, tx *types.Transaction) (common.Hash, error) {
  1515  	account := accounts.Account{Address: from}
  1516  	wallet, err := s.b.AccountManager().Find(account)
  1517  	if err != nil {
  1518  		return common.Hash{}, err
  1519  	}
  1520  	var chainID *big.Int
  1521  	if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
  1522  		chainID = config.ChainID
  1523  	}
  1524  	signed, err := wallet.SignTx(account, tx, chainID)
  1525  	if err != nil {
  1526  		return common.Hash{}, err
  1527  	}
  1528  	return s.SendRawTransaction(ctx, signed)
  1529  }
  1530  
  1531  // SendRawTransaction wacom
  1532  func (s *FusionTransactionAPI) SendRawTransaction(ctx context.Context, tx *types.Transaction) (common.Hash, error) {
  1533  	encodedTx, err := rlp.EncodeToBytes(tx)
  1534  	if err != nil {
  1535  		return common.Hash{}, err
  1536  	}
  1537  	return s.txapi.SendRawTransaction(ctx, encodedTx)
  1538  }
  1539  
  1540  // BuildGenNotationTx ss
  1541  func (s *FusionTransactionAPI) BuildGenNotationTx(ctx context.Context, args common.FusionBaseArgs) (*types.Transaction, error) {
  1542  	sendArgs, err := s.pubapi.BuildGenNotationSendTxArgs(ctx, args)
  1543  	if err != nil {
  1544  		return nil, err
  1545  	}
  1546  	return s.buildTransaction(ctx, *sendArgs)
  1547  }
  1548  
  1549  // GenNotation ss
  1550  func (s *FusionTransactionAPI) GenNotation(ctx context.Context, args common.FusionBaseArgs) (common.Hash, error) {
  1551  	tx, err := s.BuildGenNotationTx(ctx, args)
  1552  	if err != nil {
  1553  		return common.Hash{}, err
  1554  	}
  1555  	return s.sendTransaction(ctx, args.From, tx)
  1556  }
  1557  
  1558  // BuildGenAssetTx ss
  1559  func (s *FusionTransactionAPI) BuildGenAssetTx(ctx context.Context, args common.GenAssetArgs) (*types.Transaction, error) {
  1560  	sendArgs, err := s.pubapi.BuildGenAssetSendTxArgs(ctx, args)
  1561  	if err != nil {
  1562  		return nil, err
  1563  	}
  1564  	return s.buildTransaction(ctx, *sendArgs)
  1565  }
  1566  
  1567  // GenAsset ss
  1568  func (s *FusionTransactionAPI) GenAsset(ctx context.Context, args common.GenAssetArgs) (common.Hash, error) {
  1569  	tx, err := s.BuildGenAssetTx(ctx, args)
  1570  	if err != nil {
  1571  		return common.Hash{}, err
  1572  	}
  1573  	return s.sendTransaction(ctx, args.From, tx)
  1574  }
  1575  
  1576  // BuildSendAssetTx ss
  1577  func (s *FusionTransactionAPI) BuildSendAssetTx(ctx context.Context, args common.SendAssetArgs) (*types.Transaction, error) {
  1578  	sendArgs, err := s.pubapi.BuildSendAssetSendTxArgs(ctx, args)
  1579  	if err != nil {
  1580  		return nil, err
  1581  	}
  1582  	return s.buildTransaction(ctx, *sendArgs)
  1583  }
  1584  
  1585  // SendAsset ss
  1586  func (s *FusionTransactionAPI) SendAsset(ctx context.Context, args common.SendAssetArgs) (common.Hash, error) {
  1587  	tx, err := s.BuildSendAssetTx(ctx, args)
  1588  	if err != nil {
  1589  		return common.Hash{}, err
  1590  	}
  1591  	return s.sendTransaction(ctx, args.From, tx)
  1592  }
  1593  
  1594  // BuildAssetToTimeLockTx ss
  1595  func (s *FusionTransactionAPI) BuildAssetToTimeLockTx(ctx context.Context, args common.TimeLockArgs) (*types.Transaction, error) {
  1596  	sendArgs, err := s.pubapi.BuildAssetToTimeLockSendTxArgs(ctx, args)
  1597  	if err != nil {
  1598  		return nil, err
  1599  	}
  1600  	return s.buildTransaction(ctx, *sendArgs)
  1601  }
  1602  
  1603  // AssetToTimeLock ss
  1604  func (s *FusionTransactionAPI) AssetToTimeLock(ctx context.Context, args common.TimeLockArgs) (common.Hash, error) {
  1605  	tx, err := s.BuildAssetToTimeLockTx(ctx, args)
  1606  	if err != nil {
  1607  		return common.Hash{}, err
  1608  	}
  1609  	return s.sendTransaction(ctx, args.From, tx)
  1610  }
  1611  
  1612  // BuildTimeLockToTimeLockTx ss
  1613  func (s *FusionTransactionAPI) BuildTimeLockToTimeLockTx(ctx context.Context, args common.TimeLockArgs) (*types.Transaction, error) {
  1614  	sendArgs, err := s.pubapi.BuildTimeLockToTimeLockSendTxArgs(ctx, args)
  1615  	if err != nil {
  1616  		return nil, err
  1617  	}
  1618  	return s.buildTransaction(ctx, *sendArgs)
  1619  }
  1620  
  1621  // TimeLockToTimeLock ss
  1622  func (s *FusionTransactionAPI) TimeLockToTimeLock(ctx context.Context, args common.TimeLockArgs) (common.Hash, error) {
  1623  	tx, err := s.BuildTimeLockToTimeLockTx(ctx, args)
  1624  	if err != nil {
  1625  		return common.Hash{}, err
  1626  	}
  1627  	return s.sendTransaction(ctx, args.From, tx)
  1628  }
  1629  
  1630  // BuildTimeLockToAssetTx ss
  1631  func (s *FusionTransactionAPI) BuildTimeLockToAssetTx(ctx context.Context, args common.TimeLockArgs) (*types.Transaction, error) {
  1632  	sendArgs, err := s.pubapi.BuildTimeLockToAssetSendTxArgs(ctx, args)
  1633  	if err != nil {
  1634  		return nil, err
  1635  	}
  1636  	return s.buildTransaction(ctx, *sendArgs)
  1637  }
  1638  
  1639  // TimeLockToAsset ss
  1640  func (s *FusionTransactionAPI) TimeLockToAsset(ctx context.Context, args common.TimeLockArgs) (common.Hash, error) {
  1641  	tx, err := s.BuildTimeLockToAssetTx(ctx, args)
  1642  	if err != nil {
  1643  		return common.Hash{}, err
  1644  	}
  1645  	return s.sendTransaction(ctx, args.From, tx)
  1646  }
  1647  
  1648  // BuildSendTimeLockTx ss
  1649  func (s *FusionTransactionAPI) BuildSendTimeLockTx(ctx context.Context, args common.TimeLockArgs) (*types.Transaction, error) {
  1650  	sendArgs, err := s.pubapi.BuildSendTimeLockSendTxArgs(ctx, args)
  1651  	if err != nil {
  1652  		return nil, err
  1653  	}
  1654  	return s.buildTransaction(ctx, *sendArgs)
  1655  }
  1656  
  1657  // SendTimeLock ss
  1658  func (s *FusionTransactionAPI) SendTimeLock(ctx context.Context, args common.TimeLockArgs) (common.Hash, error) {
  1659  	tx, err := s.BuildSendTimeLockTx(ctx, args)
  1660  	if err != nil {
  1661  		return common.Hash{}, err
  1662  	}
  1663  	return s.sendTransaction(ctx, args.From, tx)
  1664  }
  1665  
  1666  // BuildBuyTicketTx ss
  1667  func (s *FusionTransactionAPI) BuildBuyTicketTx(ctx context.Context, args common.BuyTicketArgs) (*types.Transaction, error) {
  1668  	sendArgs, err := s.pubapi.BuildBuyTicketSendTxArgs(ctx, args)
  1669  	if err != nil {
  1670  		return nil, err
  1671  	}
  1672  	return s.buildTransaction(ctx, *sendArgs)
  1673  }
  1674  
  1675  // BuyTicket ss
  1676  func (s *FusionTransactionAPI) BuyTicket(ctx context.Context, args common.BuyTicketArgs) (common.Hash, error) {
  1677  	tx, err := s.BuildBuyTicketTx(ctx, args)
  1678  	if err != nil {
  1679  		return common.Hash{}, err
  1680  	}
  1681  	hash, err := s.sendTransaction(ctx, args.From, tx)
  1682  	if err != nil {
  1683  		return common.Hash{}, err
  1684  	}
  1685  	addTicketPurchaseForBlock(args.From)
  1686  	return hash, err
  1687  }
  1688  
  1689  // BuildIncAssetTx ss
  1690  func (s *FusionTransactionAPI) BuildIncAssetTx(ctx context.Context, args common.AssetValueChangeExArgs) (*types.Transaction, error) {
  1691  	args.IsInc = true
  1692  	sendArgs, err := s.pubapi.BuildAssetValueChangeSendTxArgs(ctx, args)
  1693  	if err != nil {
  1694  		return nil, err
  1695  	}
  1696  	return s.buildTransaction(ctx, *sendArgs)
  1697  }
  1698  
  1699  // IncAsset ss
  1700  func (s *FusionTransactionAPI) IncAsset(ctx context.Context, args common.AssetValueChangeExArgs) (common.Hash, error) {
  1701  	tx, err := s.BuildIncAssetTx(ctx, args)
  1702  	if err != nil {
  1703  		return common.Hash{}, err
  1704  	}
  1705  	return s.sendTransaction(ctx, args.From, tx)
  1706  }
  1707  
  1708  // BuildDecAssetTx ss
  1709  func (s *FusionTransactionAPI) BuildDecAssetTx(ctx context.Context, args common.AssetValueChangeExArgs) (*types.Transaction, error) {
  1710  	args.IsInc = false
  1711  	sendArgs, err := s.pubapi.BuildAssetValueChangeSendTxArgs(ctx, args)
  1712  	if err != nil {
  1713  		return nil, err
  1714  	}
  1715  	return s.buildTransaction(ctx, *sendArgs)
  1716  }
  1717  
  1718  // DecAsset ss
  1719  func (s *FusionTransactionAPI) DecAsset(ctx context.Context, args common.AssetValueChangeExArgs) (common.Hash, error) {
  1720  	tx, err := s.BuildDecAssetTx(ctx, args)
  1721  	if err != nil {
  1722  		return common.Hash{}, err
  1723  	}
  1724  	return s.sendTransaction(ctx, args.From, tx)
  1725  }
  1726  
  1727  // BuildMakeSwapTx ss
  1728  func (s *FusionTransactionAPI) BuildMakeSwapTx(ctx context.Context, args common.MakeSwapArgs) (*types.Transaction, error) {
  1729  	sendArgs, err := s.pubapi.BuildMakeSwapSendTxArgs(ctx, args)
  1730  	if err != nil {
  1731  		return nil, err
  1732  	}
  1733  	return s.buildTransaction(ctx, *sendArgs)
  1734  }
  1735  
  1736  // MakeSwap ss
  1737  func (s *FusionTransactionAPI) MakeSwap(ctx context.Context, args common.MakeSwapArgs) (common.Hash, error) {
  1738  	tx, err := s.BuildMakeSwapTx(ctx, args)
  1739  	if err != nil {
  1740  		return common.Hash{}, err
  1741  	}
  1742  	return s.sendTransaction(ctx, args.From, tx)
  1743  }
  1744  
  1745  // BuildRecallSwapTx ss
  1746  func (s *FusionTransactionAPI) BuildRecallSwapTx(ctx context.Context, args common.RecallSwapArgs) (*types.Transaction, error) {
  1747  	sendArgs, err := s.pubapi.BuildRecallSwapSendTxArgs(ctx, args)
  1748  	if err != nil {
  1749  		return nil, err
  1750  	}
  1751  	return s.buildTransaction(ctx, *sendArgs)
  1752  }
  1753  
  1754  // RecallSwap ss
  1755  func (s *FusionTransactionAPI) RecallSwap(ctx context.Context, args common.RecallSwapArgs) (common.Hash, error) {
  1756  	tx, err := s.BuildRecallSwapTx(ctx, args)
  1757  	if err != nil {
  1758  		return common.Hash{}, err
  1759  	}
  1760  	return s.sendTransaction(ctx, args.From, tx)
  1761  }
  1762  
  1763  // BuildTakeSwapTx ss
  1764  func (s *FusionTransactionAPI) BuildTakeSwapTx(ctx context.Context, args common.TakeSwapArgs) (*types.Transaction, error) {
  1765  	sendArgs, err := s.pubapi.BuildTakeSwapSendTxArgs(ctx, args)
  1766  	if err != nil {
  1767  		return nil, err
  1768  	}
  1769  	return s.buildTransaction(ctx, *sendArgs)
  1770  }
  1771  
  1772  // TakeSwap ss
  1773  func (s *FusionTransactionAPI) TakeSwap(ctx context.Context, args common.TakeSwapArgs) (common.Hash, error) {
  1774  	tx, err := s.BuildTakeSwapTx(ctx, args)
  1775  	if err != nil {
  1776  		return common.Hash{}, err
  1777  	}
  1778  	return s.sendTransaction(ctx, args.From, tx)
  1779  }
  1780  
  1781  // MakeMultiSwap wacom
  1782  func (s *FusionTransactionAPI) MakeMultiSwap(ctx context.Context, args common.MakeMultiSwapArgs) (common.Hash, error) {
  1783  	tx, err := s.BuildMakeMultiSwapTx(ctx, args)
  1784  	if err != nil {
  1785  		return common.Hash{}, err
  1786  	}
  1787  	return s.sendTransaction(ctx, args.From, tx)
  1788  }
  1789  
  1790  // BuildMakeMultiSwapTx ss
  1791  func (s *FusionTransactionAPI) BuildMakeMultiSwapTx(ctx context.Context, args common.MakeMultiSwapArgs) (*types.Transaction, error) {
  1792  	sendArgs, err := s.pubapi.BuildMakeMultiSwapSendTxArgs(ctx, args)
  1793  	if err != nil {
  1794  		return nil, err
  1795  	}
  1796  	return s.buildTransaction(ctx, *sendArgs)
  1797  }
  1798  
  1799  // RecallMultiSwap wacom
  1800  func (s *FusionTransactionAPI) RecallMultiSwap(ctx context.Context, args common.RecallMultiSwapArgs) (common.Hash, error) {
  1801  	tx, err := s.BuildRecallMultiSwapTx(ctx, args)
  1802  	if err != nil {
  1803  		return common.Hash{}, err
  1804  	}
  1805  	return s.sendTransaction(ctx, args.From, tx)
  1806  }
  1807  
  1808  // BuildRecallMultiSwapTx ss
  1809  func (s *FusionTransactionAPI) BuildRecallMultiSwapTx(ctx context.Context, args common.RecallMultiSwapArgs) (*types.Transaction, error) {
  1810  	sendArgs, err := s.pubapi.BuildRecallMultiSwapSendTxArgs(ctx, args)
  1811  	if err != nil {
  1812  		return nil, err
  1813  	}
  1814  	return s.buildTransaction(ctx, *sendArgs)
  1815  }
  1816  
  1817  // TakeMultiSwap wacom
  1818  func (s *FusionTransactionAPI) TakeMultiSwap(ctx context.Context, args common.TakeMultiSwapArgs) (common.Hash, error) {
  1819  	tx, err := s.BuildTakeMultiSwapTx(ctx, args)
  1820  	if err != nil {
  1821  		return common.Hash{}, err
  1822  	}
  1823  	return s.sendTransaction(ctx, args.From, tx)
  1824  }
  1825  
  1826  // BuildTakeSwapTx ss
  1827  func (s *FusionTransactionAPI) BuildTakeMultiSwapTx(ctx context.Context, args common.TakeMultiSwapArgs) (*types.Transaction, error) {
  1828  	sendArgs, err := s.pubapi.BuildTakeMultiSwapSendTxArgs(ctx, args)
  1829  	if err != nil {
  1830  		return nil, err
  1831  	}
  1832  	return s.buildTransaction(ctx, *sendArgs)
  1833  }