|
| 1 | +package aggkit |
| 2 | + |
| 3 | +import ( |
| 4 | + "errors" |
| 5 | + "fmt" |
| 6 | + "net/http" |
| 7 | + "strings" |
| 8 | + "time" |
| 9 | + |
| 10 | + "github.com/0xPolygon/polygon-cli/cmd/ulxly/bridge_service" |
| 11 | + "github.com/0xPolygon/polygon-cli/cmd/ulxly/bridge_service/httpjson" |
| 12 | + "github.com/ethereum/go-ethereum/common" |
| 13 | + "github.com/rs/zerolog/log" |
| 14 | +) |
| 15 | + |
| 16 | +const urlPath = "bridge/v1" |
| 17 | + |
| 18 | +type BridgeService struct { |
| 19 | + bridge_service.BridgeServiceBase |
| 20 | + httpClient *http.Client |
| 21 | +} |
| 22 | + |
| 23 | +// NewBridgeService creates an instance of the BridgeService. |
| 24 | +func NewBridgeService(url string, insecure bool) (*BridgeService, error) { |
| 25 | + return &BridgeService{ |
| 26 | + BridgeServiceBase: bridge_service.NewBridgeServiceBase(url), |
| 27 | + httpClient: httpjson.NewHTTPClient(insecure), |
| 28 | + }, nil |
| 29 | +} |
| 30 | + |
| 31 | +func (s *BridgeService) GetDeposit(depositNetwork, depositCount uint32) (*bridge_service.Deposit, error) { |
| 32 | + bridgeEndpoint := fmt.Sprintf("%s/%s/bridges?network_id=%d&deposit_count=%d", s.BridgeServiceBase.Url(), urlPath, depositNetwork, depositCount) |
| 33 | + bridgeResp, bridgeRespError, statusCode, err := httpjson.HTTPGetWithError[getBridgesResponse, errorResponse](s.httpClient, bridgeEndpoint) |
| 34 | + if err != nil { |
| 35 | + return nil, err |
| 36 | + } |
| 37 | + |
| 38 | + if statusCode != http.StatusOK { |
| 39 | + errMsg := "unable to retrieve bridge deposit" |
| 40 | + log.Warn().Int("code", statusCode).Str("message", bridgeRespError.Error).Msg(errMsg) |
| 41 | + return nil, bridge_service.ErrNotFound |
| 42 | + } |
| 43 | + |
| 44 | + if len(bridgeResp.Bridges) == 0 { |
| 45 | + return nil, bridge_service.ErrNotFound |
| 46 | + } |
| 47 | + |
| 48 | + deposit, err := bridgeResp.Bridges[0].ToDeposit(depositNetwork) |
| 49 | + if err != nil { |
| 50 | + return nil, err |
| 51 | + } |
| 52 | + |
| 53 | + return deposit, nil |
| 54 | +} |
| 55 | + |
| 56 | +func (s *BridgeService) GetDeposits(destinationAddress string, offset, limit int) ([]bridge_service.Deposit, int, error) { |
| 57 | + return nil, 0, fmt.Errorf("GetDeposits is not supported by aggkit bridge service yet") |
| 58 | +} |
| 59 | + |
| 60 | +func (s *BridgeService) GetProof(depositNetwork, depositCount uint32, ger *common.Hash) (*bridge_service.Proof, error) { |
| 61 | + var l1InfoTreeIndex uint32 |
| 62 | + |
| 63 | + if ger != nil { |
| 64 | + return nil, errors.New("getting proof by ger is not supported yet by Aggkit bridge service") |
| 65 | + } |
| 66 | + |
| 67 | + timeout := time.After(time.Minute) |
| 68 | +out: |
| 69 | + for { |
| 70 | + idx, err := s.getL1InfoTreeIndex(depositNetwork, depositCount) |
| 71 | + if err != nil && !errors.Is(err, bridge_service.ErrNotFound) { |
| 72 | + return nil, err |
| 73 | + } else if err == nil { |
| 74 | + l1InfoTreeIndex = *idx |
| 75 | + break out |
| 76 | + } |
| 77 | + select { |
| 78 | + case <-timeout: |
| 79 | + return nil, fmt.Errorf("timeout waiting for l1 info tree index") |
| 80 | + default: |
| 81 | + time.Sleep(time.Second) |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + endpoint := fmt.Sprintf("%s/%s/claim-proof?network_id=%d&leaf_index=%d&deposit_count=%d", s.BridgeServiceBase.Url(), urlPath, depositNetwork, l1InfoTreeIndex, depositCount) |
| 86 | + resp, respError, statusCode, err := httpjson.HTTPGetWithError[getClaimProofResponse, errorResponse](s.httpClient, endpoint) |
| 87 | + if err != nil { |
| 88 | + return nil, err |
| 89 | + } |
| 90 | + |
| 91 | + if statusCode != http.StatusOK { |
| 92 | + if statusCode == http.StatusNotFound { |
| 93 | + return nil, bridge_service.ErrNotFound |
| 94 | + } |
| 95 | + errMsg := "unable to retrieve proof" |
| 96 | + log.Warn().Int("code", statusCode).Str("message", respError.Error).Msg(errMsg) |
| 97 | + return nil, fmt.Errorf("unable to get proof: %s", respError.Error) |
| 98 | + } |
| 99 | + |
| 100 | + proof := resp.ToProof() |
| 101 | + return proof, nil |
| 102 | +} |
| 103 | + |
| 104 | +func (s *BridgeService) getL1InfoTreeIndex(depositNetwork, depositCount uint32) (*uint32, error) { |
| 105 | + l1InfoTreeIndexEndpoint := fmt.Sprintf("%s/%s/l1-info-tree-index?network_id=%d&deposit_count=%d", s.BridgeServiceBase.Url(), urlPath, depositNetwork, depositCount) |
| 106 | + l1InfoTreeIndex, l1InfoTreeIndexRespError, statusCode, err := httpjson.HTTPGetWithError[uint32, errorResponse](s.httpClient, l1InfoTreeIndexEndpoint) |
| 107 | + if err != nil { |
| 108 | + return nil, err |
| 109 | + } |
| 110 | + |
| 111 | + if statusCode != http.StatusOK { |
| 112 | + if statusCode == http.StatusNotFound { |
| 113 | + return nil, bridge_service.ErrNotFound |
| 114 | + } |
| 115 | + if statusCode == http.StatusInternalServerError { |
| 116 | + if strings.HasSuffix(l1InfoTreeIndexRespError.Error, "error: this bridge has not been included on the L1 Info Tree yet") || |
| 117 | + strings.HasSuffix(l1InfoTreeIndexRespError.Error, "error: not found") { |
| 118 | + return nil, bridge_service.ErrNotFound |
| 119 | + } |
| 120 | + } |
| 121 | + errMsg := "unable to retrieve l1 info tree index" |
| 122 | + log.Warn().Int("code", statusCode).Str("message", l1InfoTreeIndexRespError.Error).Msg(errMsg) |
| 123 | + return nil, fmt.Errorf("%s: %s", errMsg, l1InfoTreeIndexRespError.Error) |
| 124 | + } |
| 125 | + |
| 126 | + return &l1InfoTreeIndex, nil |
| 127 | +} |
0 commit comments