Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion api/handlers/signing.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import (
"fmt"
"math/big"
"net/http"
"strconv"

"github.com/ethereum/go-ethereum/common"
"github.com/gorilla/mux"
evmMessage "github.com/sprintertech/sprinter-signing/chains/evm/message"
"github.com/sprintertech/sprinter-signing/chains/evm/signature"
lighterMessage "github.com/sprintertech/sprinter-signing/chains/lighter/message"
"github.com/sygmaprotocol/sygma-core/relayer/message"
)
Expand Down Expand Up @@ -234,7 +236,7 @@ func (h *StatusHandler) HandleRequest(w http.ResponseWriter, r *http.Request) {

ctx := r.Context()
sigChn := make(chan []byte, 1)
h.cache.Subscribe(ctx, fmt.Sprintf("%d-%s", chainId, depositId), sigChn)
h.cache.Subscribe(ctx, subscribeKey(r, chainId.Uint64(), depositId), sigChn)
for {
select {
case <-r.Context().Done():
Expand All @@ -249,6 +251,21 @@ func (h *StatusHandler) HandleRequest(w http.ResponseWriter, r *http.Request) {
}
}

// subscribeKey uses the composite key when the caller supplies the digest fields, else the legacy key.
func subscribeKey(r *http.Request, chainID uint64, depositID string) string {
q := r.URL.Query()
deadline, errD := strconv.ParseUint(q.Get("deadline"), 10, 64)
caller := q.Get("caller")
borrowAmount, okB := new(big.Int).SetString(q.Get("borrowAmount"), 10)
liquidityPool := q.Get("liquidityPool")
repaymentChainID, errR := strconv.ParseUint(q.Get("repaymentChainId"), 10, 64)
if errD != nil || caller == "" || !okB || liquidityPool == "" || errR != nil {
return fmt.Sprintf("%d-%s", chainID, depositID)
}
return signature.BorrowSessionID(chainID, depositID, deadline, common.HexToAddress(caller),
borrowAmount, common.HexToAddress(liquidityPool), repaymentChainID)
}

func (h *StatusHandler) setheaders(w http.ResponseWriter) {
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
Expand Down
37 changes: 34 additions & 3 deletions api/handlers/signing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"testing"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/gorilla/mux"
"github.com/sprintertech/sprinter-signing/api/handlers"
mock_handlers "github.com/sprintertech/sprinter-signing/api/handlers/mock"
Expand Down Expand Up @@ -472,17 +473,21 @@ func (s *StatusHandlerTestSuite) Test_HandleRequest_ChainNotSupported() {
}

func (s *StatusHandlerTestSuite) Test_HandleRequest_ValidSignature() {
req := httptest.NewRequest(http.MethodGet, "/v1/chains/1/signatures/id", nil)
caller := "0x1111111111111111111111111111111111111111"
pool := "0x3333333333333333333333333333333333333333"
query := "?deadline=1000&caller=" + caller + "&borrowAmount=500&liquidityPool=" + pool + "&repaymentChainId=10"
req := httptest.NewRequest(http.MethodGet, "/v1/chains/1/signatures/id"+query, nil)
req = mux.SetURLVars(req, map[string]string{
"chainId": "1",
"depositId": "id",
})

recorder := httptest.NewRecorder()

expectedKey := "1-id-1000-" + common.HexToAddress(caller).Hex() + "-500-" + common.HexToAddress(pool).Hex() + "-10"
expectedSignature := []byte{0x01, 0x02, 0x03}
s.mockSignatureCacher.EXPECT().
Subscribe(gomock.Any(), "1-id", gomock.Any()).
Subscribe(gomock.Any(), expectedKey, gomock.Any()).
Do(func(ctx context.Context, id string, sigChannel chan []byte) {
go func() {
sigChannel <- expectedSignature
Expand All @@ -491,7 +496,7 @@ func (s *StatusHandlerTestSuite) Test_HandleRequest_ValidSignature() {

go s.handler.HandleRequest(recorder, req)

time.Sleep(100 * time.Millisecond) // Give some time for the goroutine to execute
time.Sleep(50 * time.Millisecond)

s.Equal(http.StatusOK, recorder.Code)
s.Equal("text/event-stream", recorder.Header().Get("Content-Type"))
Expand All @@ -500,3 +505,29 @@ func (s *StatusHandlerTestSuite) Test_HandleRequest_ValidSignature() {
s.Equal("*", recorder.Header().Get("Access-Control-Allow-Origin"))
s.Equal("data: "+hex.EncodeToString(expectedSignature)+"\n\n", recorder.Body.String())
}

func (s *StatusHandlerTestSuite) Test_HandleRequest_LegacyKeyWithoutParams() {
req := httptest.NewRequest(http.MethodGet, "/v1/chains/1/signatures/id", nil)
req = mux.SetURLVars(req, map[string]string{
"chainId": "1",
"depositId": "id",
})

recorder := httptest.NewRecorder()

expectedSignature := []byte{0x01, 0x02, 0x03}
s.mockSignatureCacher.EXPECT().
Subscribe(gomock.Any(), "1-id", gomock.Any()).
Do(func(ctx context.Context, id string, sigChannel chan []byte) {
go func() {
sigChannel <- expectedSignature
}()
})

go s.handler.HandleRequest(recorder, req)

time.Sleep(100 * time.Millisecond) // Give some time for the goroutine to execute

s.Equal(http.StatusOK, recorder.Code)
s.Equal("data: "+hex.EncodeToString(expectedSignature)+"\n\n", recorder.Body.String())
}
4 changes: 3 additions & 1 deletion chains/evm/message/across.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,9 @@ func (h *AcrossMessageHandler) HandleMessage(m *message.Message) (*proposal.Prop
return nil, err
}

sessionID := fmt.Sprintf("%d-%s", sourceChainID, data.DepositId)
sessionID := signature.BorrowSessionID(
sourceChainID, data.DepositId.String(), data.Deadline, data.Caller,
data.BorrowAmount, data.LiquidityPool, data.RepaymentChainID)
signing, err := signing.NewSigning(
new(big.Int).SetBytes(unlockHash),
sessionID,
Expand Down
18 changes: 18 additions & 0 deletions chains/evm/signature/session.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package signature

import (
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/common"
)

// BorrowSessionID keys the signing session and cache by the digest fields not already fixed by the deposit.
func BorrowSessionID(
chainID uint64, depositID string, deadline uint64, caller common.Address,
borrowAmount *big.Int, liquidityPool common.Address, repaymentChainID uint64,
) string {
return fmt.Sprintf("%d-%s-%d-%s-%s-%s-%d",
chainID, depositID, deadline, caller.Hex(),
borrowAmount.String(), liquidityPool.Hex(), repaymentChainID)
}
48 changes: 48 additions & 0 deletions chains/evm/signature/session_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package signature_test

import (
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/sprintertech/sprinter-signing/chains/evm/signature"
)

func TestBorrowSessionID(t *testing.T) {
caller := common.HexToAddress("0x1111111111111111111111111111111111111111")
other := common.HexToAddress("0x2222222222222222222222222222222222222222")
pool := common.HexToAddress("0x3333333333333333333333333333333333333333")
otherPool := common.HexToAddress("0x4444444444444444444444444444444444444444")
id := func(chainID uint64, deposit string, deadline uint64, c common.Address,
amount *big.Int, lp common.Address, repay uint64) string {
return signature.BorrowSessionID(chainID, deposit, deadline, c, amount, lp, repay)
}
base := id(1, "42", 1000, caller, big.NewInt(500), pool, 10)

tests := []struct {
name string
got string
equal bool
}{
{"identical inputs match", id(1, "42", 1000, caller, big.NewInt(500), pool, 10), true},
{"different chain differs", id(2, "42", 1000, caller, big.NewInt(500), pool, 10), false},
{"different deposit differs", id(1, "43", 1000, caller, big.NewInt(500), pool, 10), false},
{"different deadline differs", id(1, "42", 1001, caller, big.NewInt(500), pool, 10), false},
{"different caller differs", id(1, "42", 1000, other, big.NewInt(500), pool, 10), false},
{"different borrow amount differs", id(1, "42", 1000, caller, big.NewInt(501), pool, 10), false},
{"different liquidity pool differs", id(1, "42", 1000, caller, big.NewInt(500), otherPool, 10), false},
{"different repayment chain differs", id(1, "42", 1000, caller, big.NewInt(500), pool, 11), false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if (tt.got == base) != tt.equal {
t.Fatalf("equal=%v, base=%q got=%q", tt.equal, base, tt.got)
}
})
}

want := "1-42-1000-" + caller.Hex() + "-500-" + pool.Hex() + "-10"
if base != want {
t.Fatalf("format: want %q got %q", want, base)
}
}
Loading