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(), ¶m) 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 }