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