Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
e9ab2181
Commit
e9ab2181
authored
Jun 07, 2023
by
Will Cory
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: hook up api to dao
parent
fd0a77f7
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
84 additions
and
176 deletions
+84
-176
api.go
indexer/api/api.go
+40
-107
api_test.go
indexer/api/api_test.go
+44
-69
No files found.
indexer/api/api.go
View file @
e9ab2181
...
@@ -2,79 +2,12 @@ package api
...
@@ -2,79 +2,12 @@ package api
import
(
import
(
"encoding/json"
"encoding/json"
"net/http"
"github.com/ethereum-optimism/optimism/indexer/database"
"strconv"
"github.com/ethereum/go-ethereum/common"
"time"
"github.com/go-chi/chi"
"github.com/go-chi/chi"
"net/http"
)
)
// TODO in this pr most of these types should be coming from the ORM instead
// DepositsDAO represents the Database Access Object for deposits
type
DepositDAO
interface
{
GetDeposits
(
limit
int
,
cursor
string
,
sortDirection
string
)
([]
Deposit
,
string
,
bool
,
error
)
}
// WithdrawalDAO represents the Database Access Object for deposits
type
WithdrawalDAO
interface
{
GetWithdrawals
(
limit
int
,
cursor
string
,
sortDirection
string
,
sortBy
string
)
([]
Withdrawal
,
string
,
bool
,
error
)
}
// Deposit data structure
type
Deposit
struct
{
Guid
string
`json:"guid"`
Amount
string
`json:"amount"`
BlockNumber
int
`json:"blockNumber"`
BlockTimestamp
time
.
Time
`json:"blockTimestamp"`
From
string
`json:"from"`
To
string
`json:"to"`
TransactionHash
string
`json:"transactionHash"`
L1Token
TokenListItem
`json:"l1Token"`
L2Token
TokenListItem
`json:"l2Token"`
}
// Withdrawal data structure
type
Withdrawal
struct
{
Guid
string
`json:"guid"`
Amount
string
`json:"amount"`
BlockNumber
int
`json:"blockNumber"`
BlockTimestamp
time
.
Time
`json:"blockTimestamp"`
From
string
`json:"from"`
To
string
`json:"to"`
TransactionHash
string
`json:"transactionHash"`
WithdrawalState
string
`json:"withdrawalState"`
Proof
*
ProofClaim
`json:"proof"`
Claim
*
ProofClaim
`json:"claim"`
L1Token
TokenListItem
`json:"l1Token"`
L2Token
TokenListItem
`json:"l2Token"`
}
// TokenListItem data structure
type
TokenListItem
struct
{
ChainId
int
`json:"chainId"`
Address
string
`json:"address"`
Name
string
`json:"name"`
Symbol
string
`json:"symbol"`
Decimals
int
`json:"decimals"`
LogoURI
string
`json:"logoURI"`
Extensions
Extensions
`json:"extensions"`
}
// Extensions data structure
type
Extensions
struct
{
OptimismBridgeAddress
string
`json:"optimismBridgeAddress"`
BridgeType
string
`json:"bridgeType"`
}
// ProofClaim data structure
type
ProofClaim
struct
{
TransactionHash
string
`json:"transactionHash"`
BlockTimestamp
time
.
Time
`json:"blockTimestamp"`
BlockNumber
int
`json:"blockNumber"`
}
// PaginationResponse for paginated responses
type
PaginationResponse
struct
{
type
PaginationResponse
struct
{
// TODO type this better
// TODO type this better
Data
interface
{}
`json:"data"`
Data
interface
{}
`json:"data"`
...
@@ -83,59 +16,59 @@ type PaginationResponse struct {
...
@@ -83,59 +16,59 @@ type PaginationResponse struct {
}
}
func
(
a
*
Api
)
DepositsHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
(
a
*
Api
)
DepositsHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
bv
:=
a
.
bridgeView
address
:=
common
.
HexToAddress
(
chi
.
URLParam
(
r
,
"address"
))
limit
:=
getIntFromQuery
(
r
,
"limit"
,
10
)
// limit := getIntFromQuery(r, "limit", 10)
cursor
:=
r
.
URL
.
Query
()
.
Get
(
"cursor"
)
// cursor := r.URL.Query().Get("cursor")
sortDirection
:=
r
.
URL
.
Query
()
.
Get
(
"sortDirection"
)
// sortDirection := r.URL.Query().Get("sortDirection")
deposits
,
err
:=
bv
.
DepositsByAddress
(
address
)
deposits
,
nextCursor
,
hasNextPage
,
err
:=
a
.
DepositDAO
.
GetDeposits
(
limit
,
cursor
,
sortDirection
)
if
err
!=
nil
{
if
err
!=
nil
{
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusInternalServerError
)
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusInternalServerError
)
return
return
}
}
// This is not the shape of the response we want!!!
// will add in the individual features in future prs 1 by 1
response
:=
PaginationResponse
{
response
:=
PaginationResponse
{
Data
:
deposits
,
Data
:
deposits
,
Cursor
:
nextCursor
,
//
Cursor: nextCursor,
HasNextPage
:
hasNextPag
e
,
HasNextPage
:
fals
e
,
}
}
jsonResponse
(
w
,
response
,
http
.
StatusOK
)
jsonResponse
(
w
,
response
,
http
.
StatusOK
)
}
}
func
(
a
*
Api
)
WithdrawalsHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
(
a
*
Api
)
WithdrawalsHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
limit
:=
getIntFromQuery
(
r
,
"limit"
,
10
)
bv
:=
a
.
bridgeView
cursor
:=
r
.
URL
.
Query
()
.
Get
(
"cursor"
)
sortDirection
:=
r
.
URL
.
Query
()
.
Get
(
"sortDirection"
)
address
:=
common
.
HexToAddress
(
chi
.
URLParam
(
r
,
"address"
))
sortBy
:=
r
.
URL
.
Query
()
.
Get
(
"sortBy"
)
// limit := getIntFromQuery(r, "limit", 10)
// cursor := r.URL.Query().Get("cursor")
// sortDirection := r.URL.Query().Get("sortDirection")
withdrawals
,
err
:=
bv
.
WithdrawalsByAddress
(
address
)
withdrawals
,
nextCursor
,
hasNextPage
,
err
:=
a
.
WithdrawalDAO
.
GetWithdrawals
(
limit
,
cursor
,
sortDirection
,
sortBy
)
if
err
!=
nil
{
if
err
!=
nil
{
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusInternalServerError
)
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusInternalServerError
)
return
return
}
}
// This is not the shape of the response we want!!!
// will add in the individual features in future prs 1 by 1
response
:=
PaginationResponse
{
response
:=
PaginationResponse
{
Data
:
withdrawals
,
Data
:
withdrawals
,
Cursor
:
nextCursor
,
//
Cursor: nextCursor,
HasNextPage
:
hasNextPag
e
,
HasNextPage
:
fals
e
,
}
}
jsonResponse
(
w
,
response
,
http
.
StatusOK
)
jsonResponse
(
w
,
response
,
http
.
StatusOK
)
}
}
func
getIntFromQuery
(
r
*
http
.
Request
,
key
string
,
defaultValue
int
)
int
{
valueStr
:=
r
.
URL
.
Query
()
.
Get
(
key
)
if
valueStr
==
""
{
return
defaultValue
}
value
,
err
:=
strconv
.
Atoi
(
valueStr
)
if
err
!=
nil
{
return
defaultValue
}
return
value
}
func
jsonResponse
(
w
http
.
ResponseWriter
,
data
interface
{},
statusCode
int
)
{
func
jsonResponse
(
w
http
.
ResponseWriter
,
data
interface
{},
statusCode
int
)
{
w
.
Header
()
.
Set
(
"Content-Type"
,
"application/json"
)
w
.
Header
()
.
Set
(
"Content-Type"
,
"application/json"
)
w
.
WriteHeader
(
statusCode
)
w
.
WriteHeader
(
statusCode
)
...
@@ -143,22 +76,22 @@ func jsonResponse(w http.ResponseWriter, data interface{}, statusCode int) {
...
@@ -143,22 +76,22 @@ func jsonResponse(w http.ResponseWriter, data interface{}, statusCode int) {
}
}
type
Api
struct
{
type
Api
struct
{
Router
*
chi
.
Mux
Router
*
chi
.
Mux
DepositDAO
DepositDAO
bridgeView
database
.
BridgeView
WithdrawalDAO
WithdrawalDAO
}
}
func
NewApi
(
depositDAO
DepositDAO
,
withdrawalDAO
WithdrawalDAO
)
*
Api
{
func
NewApi
(
bv
database
.
BridgeView
)
*
Api
{
r
:=
chi
.
NewRouter
()
r
:=
chi
.
NewRouter
()
api
:=
&
Api
{
api
:=
&
Api
{
Router
:
r
,
Router
:
r
,
DepositDAO
:
depositDAO
,
bridgeView
:
bv
,
WithdrawalDAO
:
withdrawalDAO
,
}
}
// these regex are .+ because I wasn't sure what they should be
r
.
Get
(
"/api/v0/deposits"
,
api
.
DepositsHandler
)
// don't want a regex for addresses because would prefer to validate the address
r
.
Get
(
"/api/v0/withdrawals"
,
api
.
WithdrawalsHandler
)
// with go-ethereum and throw a friendly error message
r
.
Get
(
"/api/v0/deposits/{address:.+}"
,
api
.
DepositsHandler
)
r
.
Get
(
"/api/v0/withdrawals/{address:.+}"
,
api
.
WithdrawalsHandler
)
return
api
return
api
...
...
indexer/api/api_test.go
View file @
e9ab2181
package
api
package
api
import
(
import
(
"encoding/json"
"net/http"
"net/http"
"net/http/httptest"
"net/http/httptest"
"testing"
"testing"
"time"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
)
type
MockDB
struct
{
// MockBridgeView mocks the BridgeView interface
mock
.
Mock
type
MockBridgeView
struct
{}
}
func
(
db
*
MockDB
)
GetDeposits
(
limit
int
,
cursor
string
,
sortDirection
string
)
([]
Deposit
,
string
,
bool
,
error
)
{
args
:=
db
.
Called
(
limit
,
cursor
,
sortDirection
)
return
args
.
Get
(
0
)
.
([]
Deposit
),
args
.
String
(
1
),
args
.
Bool
(
2
),
args
.
Error
(
3
)
}
func
(
db
*
MockDB
)
GetWithdrawals
(
limit
int
,
cursor
string
,
sortDirection
string
,
sortBy
string
)
([]
Withdrawal
,
string
,
bool
,
error
)
{
args
:=
db
.
Called
(
limit
,
cursor
,
sortDirection
,
sortBy
)
return
args
.
Get
(
0
)
.
([]
Withdrawal
),
args
.
String
(
1
),
args
.
Bool
(
2
),
args
.
Error
(
3
)
}
func
TestApi
(
t
*
testing
.
T
)
{
mockDB
:=
new
(
MockDB
)
mockDeposits
:=
[]
Deposit
{
// DepositsByAddress mocks returning deposits by an address
func
(
mbv
*
MockBridgeView
)
DepositsByAddress
(
address
common
.
Address
)
([]
*
database
.
DepositWithTransactionHash
,
error
)
{
return
[]
*
database
.
DepositWithTransactionHash
{
{
{
Guid
:
"test-guid"
,
Deposit
:
database
.
Deposit
{
Amount
:
"1000
"
,
GUID
:
"mockGUID1
"
,
BlockNumber
:
123
,
InitiatedL1EventGUID
:
"mockEventGUID1"
,
BlockTimestamp
:
time
.
Unix
(
123456
,
0
)
,
Tx
:
database
.
Transaction
{}
,
From
:
"0x1"
,
TokenPair
:
database
.
TokenPair
{}
,
To
:
"0x2"
,
}
,
TransactionHash
:
"0x3"
,
L1TransactionHash
:
common
.
HexToHash
(
"0x123"
)
,
},
},
}
},
nil
}
mockWithdrawals
:=
[]
Withdrawal
{
// WithdrawalsByAddress mocks returning withdrawals by an address
func
(
mbv
*
MockBridgeView
)
WithdrawalsByAddress
(
address
common
.
Address
)
([]
*
database
.
WithdrawalWithTransactionHashes
,
error
)
{
return
[]
*
database
.
WithdrawalWithTransactionHashes
{
{
{
Guid
:
"test-guid"
,
Withdrawal
:
database
.
Withdrawal
{
Amount
:
"1000"
,
GUID
:
"mockGUID2"
,
BlockNumber
:
123
,
InitiatedL2EventGUID
:
"mockEventGUID2"
,
BlockTimestamp
:
time
.
Unix
(
123456
,
0
),
WithdrawalHash
:
common
.
HexToHash
(
"0x456"
),
From
:
"0x1"
,
Tx
:
database
.
Transaction
{},
To
:
"0x2"
,
TokenPair
:
database
.
TokenPair
{},
TransactionHash
:
"0x3"
,
},
L2TransactionHash
:
common
.
HexToHash
(
"0x789"
),
},
},
}
},
nil
}
mockDB
.
On
(
"GetDeposits"
,
10
,
""
,
""
)
.
Return
(
mockDeposits
,
"nextCursor"
,
false
,
nil
)
mockDB
.
On
(
"GetWithdrawals"
,
10
,
""
,
""
,
""
)
.
Return
(
mockWithdrawals
,
"nextCursor"
,
false
,
nil
)
testApi
:=
NewApi
(
mockDB
,
mockDB
)
req
,
_
:=
http
.
NewRequest
(
"GET"
,
"/api/v0/deposits"
,
nil
)
rr
:=
httptest
.
NewRecorder
()
testApi
.
Router
.
ServeHTTP
(
rr
,
req
)
assert
.
Equal
(
t
,
http
.
StatusOK
,
rr
.
Code
,
"status code should be 200"
)
// TODO make this type exist
var
depositsResponse
DepositsResponse
err
:=
json
.
Unmarshal
(
rr
.
Body
.
Bytes
(),
&
depositsResponse
)
assert
.
NoError
(
t
,
err
)
assert
.
Equal
(
t
,
mockDeposits
,
depositsResponse
.
Data
)
func
TestDepositsHandler
(
t
*
testing
.
T
)
{
api
:=
NewApi
(
&
MockBridgeView
{})
request
,
err
:=
http
.
NewRequest
(
"GET"
,
"/api/v0/deposits/0x123"
,
nil
)
assert
.
Nil
(
t
,
err
)
req
,
_
=
http
.
NewRequest
(
"GET"
,
"/api/v0/withdrawals"
,
nil
)
responseRecorder
:=
httptest
.
NewRecorder
()
rr
=
httptest
.
NewRecorder
()
api
.
Router
.
ServeHTTP
(
responseRecorder
,
request
)
testApi
.
Router
.
ServeHTTP
(
rr
,
req
)
assert
.
Equal
(
t
,
http
.
StatusOK
,
rr
.
Code
,
"status code should be 200"
)
assert
.
Equal
(
t
,
http
.
StatusOK
,
responseRecorder
.
Code
)
}
// TODO make this type exist
func
TestWithdrawalsHandler
(
t
*
testing
.
T
)
{
var
withdrawalsResponse
WithdrawalsResponse
api
:=
NewApi
(
&
MockBridgeView
{})
err
=
json
request
,
err
:=
http
.
NewRequest
(
"GET"
,
"/api/v0/withdrawals/0x123"
,
nil
)
err
=
json
.
Unmarshal
(
rr
.
Body
.
Bytes
(),
&
withdrawalsResponse
)
assert
.
Nil
(
t
,
err
)
assert
.
NoError
(
t
,
err
)
// Assert response data
responseRecorder
:=
httptest
.
NewRecorder
()
a
ssert
.
Equal
(
t
,
mockWithdrawals
,
withdrawalsResponse
.
Data
)
a
pi
.
Router
.
ServeHTTP
(
responseRecorder
,
request
)
// Finally, assert that the methods were called with the expected parameters
assert
.
Equal
(
t
,
http
.
StatusOK
,
responseRecorder
.
Code
)
mockDB
.
AssertCalled
(
t
,
"GetDeposits"
,
10
,
""
,
""
)
mockDB
.
AssertCalled
(
t
,
"GetWithdrawals"
,
10
,
""
,
""
,
""
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment