Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e7c74c7
Implement compact digest generation
mpetrun5 Jul 17, 2025
ae38038
Add lifi api tests
mpetrun5 Jul 21, 2025
164f0c7
Use create transaction hash for mayan swaps
mpetrun5 Jul 21, 2025
c342faf
Implement fetching the allocator from chain
mpetrun5 Jul 22, 2025
1cfeb4c
Fix compact tests
mpetrun5 Jul 22, 2025
de18507
Add order validation
mpetrun5 Jul 22, 2025
c09eab6
Add order signing
mpetrun5 Jul 22, 2025
7bb029e
Use compact address to verify signature
mpetrun5 Jul 22, 2025
f5bf0f8
Add nonce and allocator on-chain verification
mpetrun5 Jul 23, 2025
989bd80
Move lifi api types to separate file
mpetrun5 Jul 23, 2025
e5e661d
Generate lifi calldata
mpetrun5 Jul 24, 2025
3287dc0
Fix compact types to match lifi
mpetrun5 Jul 24, 2025
43d765d
Lint
mpetrun5 Jul 24, 2025
0ff7314
Add lifi tests
mpetrun5 Jul 28, 2025
a298e0d
Add lifi compact to api
mpetrun5 Jul 28, 2025
fe104f4
Merge branch 'main' into mpetrun5/lifi-handler
mpetrun5 Jul 28, 2025
115df9c
Lint
mpetrun5 Jul 28, 2025
7a82d23
Change lifi compact to lifi escrow
mpetrun5 Sep 30, 2025
6230d1a
Separate confirmation watcher into value and token
mpetrun5 Oct 1, 2025
fab9f90
Implement borrow many unlock hash
mpetrun5 Oct 1, 2025
e971790
Remove extra code
mpetrun5 Oct 1, 2025
9126578
Fix protocol type
mpetrun5 Oct 1, 2025
7e21511
Add lifi escrow message handler initialization
mpetrun5 Oct 1, 2025
b20d6b5
Bump solver config
mpetrun5 Oct 2, 2025
cf39179
Add tests
mpetrun5 Oct 2, 2025
51b87d0
Tidy dependcies
mpetrun5 Oct 2, 2025
674a8c6
Lint
mpetrun5 Oct 2, 2025
318ec1f
Fix mocks check
mpetrun5 Oct 2, 2025
7382095
Regenerate mocks with version v0.5.0
mpetrun5 Oct 2, 2025
1eaf47d
Merge branch 'main' into mpetrun5/lifi-ecsrow-handler
mpetrun5 Oct 9, 2025
b92d5fb
Tidy go.mod
mpetrun5 Oct 9, 2025
6268a47
Bump lifi solver
mpetrun5 Oct 9, 2025
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
5 changes: 5 additions & 0 deletions .github/workflows/mocks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@

on: [pull_request]
name: Mocks check

env:
GO111MODULE: on
GOPRIVATE: github.com/sprintertech
TOKEN: ${{ secrets.REPO_ACCESS_TOKEN }}

jobs:
mocks-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: setup git access to private repos
run: git config --global url."https://${TOKEN}:[email protected]/sprintertech/".insteadOf "https://github.com/sprintertech/"

- uses: actions/setup-go@v2
with:
go-version: "^1.23"
Expand Down
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ genmocks:
mockgen -destination=./comm/p2p/mock/stream/stream.go github.com/libp2p/go-libp2p/core/network Stream,Conn
mockgen -source=./chains/evm/message/across.go -destination=./chains/evm/message/mock/across.go
mockgen -source=./chains/evm/message/rhinestone.go -destination=./chains/evm/message/mock/rhinestone.go
mockgen -source=./chains/evm/message/lifiEscrow.go -destination=./chains/evm/message/mock/lifiEscrow.go
mockgen -source=./chains/evm/message/mayan.go -destination=./chains/evm/message/mock/mayan.go
mockgen -source=./chains/evm/message/confirmations.go -destination=./chains/evm/message/mock/confirmations.go
mockgen -source=./api/handlers/signing.go -destination=./api/handlers/mock/signing.go
mockgen -package mock_message -destination=./chains/evm/message/mock/pricing.go github.com/sprintertech/lifi-solver/pkg/pricing OrderPricer



Expand Down
14 changes: 14 additions & 0 deletions api/handlers/signing.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const (
AcrossProtocol ProtocolType = "across"
MayanProtocol ProtocolType = "mayan"
RhinestoneProtocol ProtocolType = "rhinestone"
LifiEscrow ProtocolType = "lifi-escrow"
LifiProtocol ProtocolType = "lifi"
)

Expand Down Expand Up @@ -112,6 +113,19 @@ func (h *SigningHandler) HandleSigning(w http.ResponseWriter, r *http.Request) {
BorrowAmount: b.BorrowAmount.Int,
})
}
case LifiEscrow:
{
m = evmMessage.NewLifiEscrowData(0, b.ChainId, &evmMessage.LifiEscrowData{
OrderID: b.DepositId,
Nonce: b.Nonce.Int,
LiquidityPool: common.HexToAddress(b.LiquidityPool),
Caller: common.HexToAddress(b.Caller),
ErrChn: errChn,
Source: 0,
Destination: b.ChainId,
BorrowAmount: b.BorrowAmount.Int,
})
}
default:
JSONError(w, fmt.Errorf("invalid protocol %s", b.Protocol), http.StatusBadRequest)
return
Expand Down
34 changes: 34 additions & 0 deletions api/handlers/signing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,40 @@ func (s *SigningHandlerTestSuite) Test_HandleSigning_RhinestoneSuccess() {
s.Equal(http.StatusAccepted, recorder.Code)
}

func (s *SigningHandlerTestSuite) Test_HandleSigning_LifiSuccess() {
msgChn := make(chan []*message.Message)
handler := handlers.NewSigningHandler(msgChn, s.chains)

input := handlers.SigningBody{
DepositId: "depositID",
Protocol: "lifi-escrow",
LiquidityPool: "0xbe526bA5d1ad94cC59D7A79d99A59F607d31A657",
Caller: "0xbe526bA5d1ad94cC59D7A79d99A59F607d31A657",
Calldata: "0xbe5",
Nonce: &handlers.BigInt{big.NewInt(1001)},
BorrowAmount: &handlers.BigInt{big.NewInt(1000)},
}
body, _ := json.Marshal(input)

req := httptest.NewRequest(http.MethodPost, "/v1/chains/1/signatures", bytes.NewReader(body))
req = mux.SetURLVars(req, map[string]string{
"chainId": "1",
})
req.Header.Set("Content-Type", "application/json")

recorder := httptest.NewRecorder()

go func() {
msg := <-msgChn
ad := msg[0].Data.(*across.LifiEscrowData)
ad.ErrChn <- nil
}()

handler.HandleSigning(recorder, req)

s.Equal(http.StatusAccepted, recorder.Code)
}

type StatusHandlerTestSuite struct {
suite.Suite

Expand Down
38 changes: 38 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ import (
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
"github.com/sprintertech/lifi-solver/pkg/pricing"
lifiTypes "github.com/sprintertech/lifi-solver/pkg/protocols/lifi"
"github.com/sprintertech/lifi-solver/pkg/protocols/lifi/validation"
"github.com/sprintertech/lifi-solver/pkg/token"
"github.com/sprintertech/lifi-solver/pkg/tokenpricing/pyth"
solverConfig "github.com/sprintertech/solver-config/go/config"
"github.com/sprintertech/sprinter-signing/api"
"github.com/sprintertech/sprinter-signing/api/handlers"
Expand All @@ -36,6 +41,7 @@ import (
"github.com/sprintertech/sprinter-signing/metrics"
"github.com/sprintertech/sprinter-signing/price"
"github.com/sprintertech/sprinter-signing/protocol/across"
"github.com/sprintertech/sprinter-signing/protocol/lifi"
"github.com/sprintertech/sprinter-signing/protocol/mayan"
"github.com/sprintertech/sprinter-signing/topology"
"github.com/sprintertech/sprinter-signing/tss"
Expand Down Expand Up @@ -153,6 +159,7 @@ func Run() error {
var hubPoolContract across.TokenMatcher
acrossPools := make(map[uint64]common.Address)
mayanPools := make(map[uint64]common.Address)
lifiOutputSettlers := make(map[uint64]common.Address)
repayerAddresses := make(map[uint64]common.Address)
tokens := make(map[uint64]map[string]config.TokenConfig)
for _, chainConfig := range configuration.ChainConfigs {
Expand All @@ -175,6 +182,11 @@ func Run() error {
mayanPools[*c.GeneralChainConfig.Id] = poolAddress
}

if c.LifiOutputSettler != "" {
settlerAddress := common.HexToAddress(c.LifiOutputSettler)
lifiOutputSettlers[*c.GeneralChainConfig.Id] = settlerAddress
}

if c.AcrossHubPool != "" {
hubPoolAddress := common.HexToAddress(c.AcrossHubPool)
hubPoolContract = contracts.NewHubPoolContract(client, hubPoolAddress, c.Tokens)
Expand Down Expand Up @@ -269,6 +281,32 @@ func Run() error {
confirmationsPerChain[*c.GeneralChainConfig.Id] = c.ConfirmationsByValue
}

if c.LifiOutputSettler != "" {
usdPricer := pyth.NewClient(ctx)
resolver := token.NewTokenResolver(solverConfig, usdPricer)
orderPricer := pricing.NewStandardPricer(resolver)
lifiApi := lifi.NewLifiAPI()
lifiValidator := validation.NewLifiEscrowOrderValidator[lifiTypes.LifiOrder](solverConfig, orderPricer)

lifiMh := evmMessage.NewLifiEscrowMessageHandler(
*c.GeneralChainConfig.Id,
lifiOutputSettlers,
coordinator,
host,
communication,
keyshareStore,
watcher,
tokenStore,
lifiApi,
orderPricer,
lifiValidator,
sigChn,
)
mh.RegisterMessageHandler(evmMessage.LifiEscrowMessage, lifiMh)
supportedChains[*c.GeneralChainConfig.Id] = struct{}{}
confirmationsPerChain[*c.GeneralChainConfig.Id] = c.ConfirmationsByValue
}

lifiUnlockMh := evmMessage.NewLifiUnlockHandler(
*c.GeneralChainConfig.Id,
repayerAddresses,
Expand Down
33 changes: 33 additions & 0 deletions chains/evm/calls/consts/lifi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package consts

import (
"strings"

"github.com/ethereum/go-ethereum/accounts/abi"
)

var LifiABI, _ = abi.JSON(strings.NewReader(`[{
"name": "fillOrderOutputs",
"type": "function",
"stateMutability": "nonpayable",
"inputs": [
{"name": "fillDeadline", "type": "uint32"},
{"name": "orderId", "type": "bytes32"},
{
"name": "outputs",
"type": "tuple[]",
"components": [
{"name": "oracle", "type": "bytes32"},
{"name": "settler", "type": "bytes32"},
{"name": "chainId", "type": "uint256"},
{"name": "token", "type": "bytes32"},
{"name": "amount", "type": "uint256"},
{"name": "recipient", "type": "bytes32"},
{"name": "call", "type": "bytes"},
{"name": "context", "type": "bytes"}
]
},
{"name": "proposedSolver", "type": "bytes32"}
],
"outputs": []
}]`))
11 changes: 7 additions & 4 deletions chains/evm/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ type EVMConfig struct {
GeneralChainConfig chain.GeneralChainConfig
Admin string

AcrossPool string
AcrossHubPool string
MayanSwift string
Repayer string
AcrossPool string
AcrossHubPool string
MayanSwift string
LifiOutputSettler string
Repayer string

Tokens map[string]config.TokenConfig
// usd bucket -> confirmations
Expand Down Expand Up @@ -102,6 +103,8 @@ func NewEVMConfig(chainConfig map[string]interface{}, solverConfig solverConfig.

MayanSwift: solverConfig.ProtocolsMetadata.Mayan.SwiftContracts[id],

LifiOutputSettler: solverConfig.ProtocolsMetadata.Lifi.OutputSettler,

// nolint:gosec
BlockRetryInterval: time.Duration(c.BlockRetryInterval) * time.Second,
BlockInterval: big.NewInt(c.BlockInterval),
Expand Down
8 changes: 8 additions & 0 deletions chains/evm/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ func (s *NewEVMConfigTestSuite) Test_ValidConfig() {
"eip155:1": "repayer",
},
},
Lifi: &solverConfig.LifiMetadata{
OutputSettler: "settler",
},
},
})

Expand All @@ -128,6 +131,7 @@ func (s *NewEVMConfigTestSuite) Test_ValidConfig() {
AcrossPool: "acrossPool",
AcrossHubPool: "acrossHubPool",
MayanSwift: "mayanSwift",
LifiOutputSettler: "settler",
ConfirmationsByValue: make(map[uint64]uint64),
Tokens: make(map[string]config.TokenConfig),
})
Expand Down Expand Up @@ -215,6 +219,9 @@ func (s *NewEVMConfigTestSuite) Test_ValidConfigWithCustomTxParams() {
"eip155:1": "repayer",
},
},
Lifi: &solverConfig.LifiMetadata{
OutputSettler: "settler",
},
},
})

Expand All @@ -235,6 +242,7 @@ func (s *NewEVMConfigTestSuite) Test_ValidConfigWithCustomTxParams() {
AcrossPool: "acrossPool",
AcrossHubPool: "acrossHubPool",
MayanSwift: "mayanSwift",
LifiOutputSettler: "settler",
Repayer: "repayer",
ConfirmationsByValue: expectedBlockConfirmations,
Tokens: expectedTokens,
Expand Down
11 changes: 8 additions & 3 deletions chains/evm/message/across.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,17 @@ type Coordinator interface {
}

type ConfirmationWatcher interface {
WaitForConfirmations(
WaitForTokenConfirmations(
ctx context.Context,
chainID uint64,
txHash common.Hash,
token common.Address,
amount *big.Int) error
WaitForOrderConfirmations(
ctx context.Context,
chainID uint64,
txHash common.Hash,
orderValue float64) error
}

type DepositFetcher interface {
Expand Down Expand Up @@ -117,7 +122,7 @@ func (h *AcrossMessageHandler) HandleMessage(m *message.Message) (*proposal.Prop
return nil, err
}

err = h.confirmationWatcher.WaitForConfirmations(
err = h.confirmationWatcher.WaitForTokenConfirmations(
context.Background(),
h.chainID,
data.DepositTxHash,
Expand All @@ -136,7 +141,7 @@ func (h *AcrossMessageHandler) HandleMessage(m *message.Message) (*proposal.Prop
return nil, err
}

unlockHash, err := unlockHash(
unlockHash, err := borrowUnlockHash(
calldata,
d.OutputAmount,
common.BytesToAddress(d.OutputToken[12:]),
Expand Down
2 changes: 1 addition & 1 deletion chains/evm/message/across_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func (s *AcrossMessageHandlerTestSuite) Test_HandleMessage_ValidDeposit() {
}
s.mockDepositFetcher.EXPECT().Deposit(gomock.Any(), gomock.Any(), gomock.Any()).Return(deposit, nil)

s.mockWatcher.EXPECT().WaitForConfirmations(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
s.mockWatcher.EXPECT().WaitForTokenConfirmations(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
s.mockCoordinator.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)

errChn := make(chan error, 1)
Expand Down
Loading
Loading