diff --git a/src/utils/config/warpy_syncer.go b/src/utils/config/warpy_syncer.go index 8fab61cb..dc017948 100644 --- a/src/utils/config/warpy_syncer.go +++ b/src/utils/config/warpy_syncer.go @@ -89,20 +89,26 @@ type WarpySyncer struct { // Max number of transactions that wait in the worker queue SyncerDepositWorkerQueueSize int + // Accepted markets in which token is being deposited + SyncerDepositMarkets []string + + // Supported token + SyncerDepositToken string + // Max batch size before last block synced will be inserted into database StoreBatchSize int // After this time last block synced will be inserted into database StoreInterval time.Duration - // Sommelier functions for withdrawal + // Functions for withdrawal StoreDepositWithdrawFunctions []string - // Name of the deposit assets input name - StoreDepositDepositAssetsName string + // Names of the deposit assets input name + StoreDepositDepositAssetsNames []string - // Name of the withdraw assets input name - StoreDepositWithdrawAssetsName string + // Names of the withdraw assets input name + StoreDepositWithdrawAssetsNames []string // Max time between failed retries to save last block synced StoreMaxBackoffInterval time.Duration @@ -143,8 +149,8 @@ func setWarpySyncerDefaults() { viper.SetDefault("WarpySyncer.BlockDownloaderByHeader", true) viper.SetDefault("WarpySyncer.SyncerContractId", "p5OI99-BaY4QbZts266T7EDwofZqs-wVuYJmMCS0SUU") viper.SetDefault("WarpySyncer.SyncerNameServiceContractId", "p5OI99-BaY4QbZts266T7EDwofZqs-wVuYJmMCS0SUU") - viper.SetDefault("WarpySyncer.SyncerChain", eth.Manta) - viper.SetDefault("WarpySyncer.SyncerProtocol", eth.LayerBank) + viper.SetDefault("WarpySyncer.SyncerChain", eth.Arbitrum) + viper.SetDefault("WarpySyncer.SyncerProtocol", eth.Pendle) viper.SetDefault("WarpySyncer.SyncerDreUrl", "https://dre-warpy.warp.cc") viper.SetDefault("WarpySyncer.SyncerWarpyApiUrl", "https://api-warpy.warp.cc") viper.SetDefault("WarpySyncer.SyncerApiKey", "") @@ -157,15 +163,24 @@ func setWarpySyncerDefaults() { viper.SetDefault("WarpySyncer.SyncerDeltaRedstoneData", "000002ed57011e0000") viper.SetDefault("WarpySyncer.SyncerDeltaNumWorkers", "50") viper.SetDefault("WarpySyncer.SyncerDeltaWorkerQueueSize", "10") - viper.SetDefault("WarpySyncer.SyncerDepositContractId", "0xB7A23Fc0b066051dE58B922dC1a08f33DF748bbf") + viper.SetDefault("WarpySyncer.SyncerDepositContractId", "0x888888888889758f76e7103c6cbf23abbf58f946") viper.SetDefault("WarpySyncer.SyncerDepositBackoffInterval", "3s") - viper.SetDefault("WarpySyncer.SyncerDepositFunctions", []string{"supply", "redeemToken"}) - viper.SetDefault("WarpySyncer.StoreDepositWithdrawFunctions", []string{"redeemToken"}) + viper.SetDefault("WarpySyncer.SyncerDepositFunctions", []string{"swapExactTokenForPt", "swapExactPtForToken"}) + viper.SetDefault("WarpySyncer.SyncerDepositMarkets", []string{ + // wETH + "0x952083cde7aaa11AB8449057F7de23A970AA8472", + // rsETH + "0x6Ae79089b2CF4be441480801bb741A531d94312b", + // ezETH + "0x5E03C94Fc5Fb2E21882000A96Df0b63d2c4312e2", + }) + viper.SetDefault("WarpySyncer.SyncerDepositToken", "0x6A0d9584D88D22BcaD7D4F83E7d6AB7949895DDF") + viper.SetDefault("WarpySyncer.StoreDepositWithdrawFunctions", []string{"swapExactPtForToken"}) viper.SetDefault("WarpySyncer.StoreBatchSize", "500") viper.SetDefault("WarpySyncer.StoreInterval", "2s") viper.SetDefault("WarpySyncer.StoreMaxBackoffInterval", "30s") - viper.SetDefault("WarpySyncer.StoreDepositDepositAssetsName", "lAmount") - viper.SetDefault("WarpySyncer.StoreDepositWithdrawAssetsName", "uAmount") + viper.SetDefault("WarpySyncer.StoreDepositDepositAssetsNames", []string{"input", "netTokenIn"}) + viper.SetDefault("WarpySyncer.StoreDepositWithdrawAssetsNames", []string{"exactPtIn"}) viper.SetDefault("WarpySyncer.PollerDepositChannelBufferLength", 100) viper.SetDefault("WarpySyncer.PollerDepositInterval", "1m") viper.SetDefault("WarpySyncer.PollerDepositTimeout", "90s") diff --git a/src/utils/eth/client.go b/src/utils/eth/client.go index caaeb139..10aa2486 100644 --- a/src/utils/eth/client.go +++ b/src/utils/eth/client.go @@ -1,9 +1,12 @@ package eth import ( + "encoding/json" "errors" "fmt" + "io" "math/big" + "os" "strings" "github.com/ethereum/go-ethereum/accounts/abi" @@ -28,6 +31,7 @@ const ( Delta Protocol = iota Sommelier Protocol = iota LayerBank Protocol = iota + Pendle Protocol = iota ) type Chain int @@ -84,6 +88,8 @@ func (protocol Protocol) String() string { return "sommelier" case LayerBank: return "layer_bank" + case Pendle: + return "pendle" } return "" } @@ -189,3 +195,31 @@ func WeiToEther(wei *big.Int) float64 { ether, _ := new(big.Float).Quo(new(big.Float).SetInt(wei), big.NewFloat(params.Ether)).Float64() return ether } + +func GetContractABIFromFile(fileName string) (*abi.ABI, error) { + fileData, err := os.Open(fmt.Sprintf("src/warpy_sync/abi/%s", fileName)) + + if err != nil { + return nil, err + } + + byteValue, err := io.ReadAll(fileData) + if err != nil { + return nil, err + } + + rawABIResponse := &RawABIResponse{} + + err = json.Unmarshal(byteValue, rawABIResponse) + if err != nil { + return nil, err + } + + fileData.Close() + + contractABI, err := abi.JSON(strings.NewReader(*rawABIResponse.Result)) + if err != nil { + return nil, err + } + return &contractABI, nil +} diff --git a/src/warpy_sync/abi/IPActionSwapPTV3.json b/src/warpy_sync/abi/IPActionSwapPTV3.json new file mode 100644 index 00000000..6e894cbb --- /dev/null +++ b/src/warpy_sync/abi/IPActionSwapPTV3.json @@ -0,0 +1,5 @@ +{ + "status": "", + "message": "", + "result": "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"netPtToAccount\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"netSyToAccount\",\"type\":\"int256\"}],\"name\":\"SwapPtAndSy\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"netPtToAccount\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"netTokenToAccount\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"netSyInterm\",\"type\":\"uint256\"}],\"name\":\"SwapPtAndToken\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exactPtIn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minSyOut\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"limitRouter\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"epsSkipMarket\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"salt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"enumIPLimitOrderType.OrderType\",\"name\":\"orderType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"YT\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lnImpliedRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"failSafeRate\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"permit\",\"type\":\"bytes\"}],\"internalType\":\"structOrder\",\"name\":\"order\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"}],\"internalType\":\"structFillOrderParams[]\",\"name\":\"normalFills\",\"type\":\"tuple[]\"},{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"salt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"enumIPLimitOrderType.OrderType\",\"name\":\"orderType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"YT\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lnImpliedRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"failSafeRate\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"permit\",\"type\":\"bytes\"}],\"internalType\":\"structOrder\",\"name\":\"order\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"}],\"internalType\":\"structFillOrderParams[]\",\"name\":\"flashFills\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"optData\",\"type\":\"bytes\"}],\"internalType\":\"structLimitOrderData\",\"name\":\"limit\",\"type\":\"tuple\"}],\"name\":\"swapExactPtForSy\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"netSyOut\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"netSyFee\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exactPtIn\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"tokenOut\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minTokenOut\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenRedeemSy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pendleSwap\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"enumSwapType\",\"name\":\"swapType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"extRouter\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extCalldata\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"needScale\",\"type\":\"bool\"}],\"internalType\":\"structSwapData\",\"name\":\"swapData\",\"type\":\"tuple\"}],\"internalType\":\"structTokenOutput\",\"name\":\"output\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"limitRouter\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"epsSkipMarket\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"salt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"enumIPLimitOrderType.OrderType\",\"name\":\"orderType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"YT\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lnImpliedRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"failSafeRate\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"permit\",\"type\":\"bytes\"}],\"internalType\":\"structOrder\",\"name\":\"order\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"}],\"internalType\":\"structFillOrderParams[]\",\"name\":\"normalFills\",\"type\":\"tuple[]\"},{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"salt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"enumIPLimitOrderType.OrderType\",\"name\":\"orderType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"YT\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lnImpliedRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"failSafeRate\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"permit\",\"type\":\"bytes\"}],\"internalType\":\"structOrder\",\"name\":\"order\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"}],\"internalType\":\"structFillOrderParams[]\",\"name\":\"flashFills\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"optData\",\"type\":\"bytes\"}],\"internalType\":\"structLimitOrderData\",\"name\":\"limit\",\"type\":\"tuple\"}],\"name\":\"swapExactPtForToken\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"netTokenOut\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"netSyFee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"netSyInterm\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"exactSyIn\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"minPtOut\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"guessMin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"guessMax\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"guessOffchain\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxIteration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"eps\",\"type\":\"uint256\"}],\"internalType\":\"structApproxParams\",\"name\":\"guessPtOut\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"limitRouter\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"epsSkipMarket\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"salt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"enumIPLimitOrderType.OrderType\",\"name\":\"orderType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"YT\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lnImpliedRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"failSafeRate\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"permit\",\"type\":\"bytes\"}],\"internalType\":\"structOrder\",\"name\":\"order\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"}],\"internalType\":\"structFillOrderParams[]\",\"name\":\"normalFills\",\"type\":\"tuple[]\"},{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"salt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"enumIPLimitOrderType.OrderType\",\"name\":\"orderType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"YT\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lnImpliedRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"failSafeRate\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"permit\",\"type\":\"bytes\"}],\"internalType\":\"structOrder\",\"name\":\"order\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"}],\"internalType\":\"structFillOrderParams[]\",\"name\":\"flashFills\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"optData\",\"type\":\"bytes\"}],\"internalType\":\"structLimitOrderData\",\"name\":\"limit\",\"type\":\"tuple\"}],\"name\":\"swapExactSyForPt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"netPtOut\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"netSyFee\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"market\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minPtOut\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"guessMin\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"guessMax\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"guessOffchain\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxIteration\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"eps\",\"type\":\"uint256\"}],\"internalType\":\"structApproxParams\",\"name\":\"guessPtOut\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"tokenIn\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"netTokenIn\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"tokenMintSy\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"pendleSwap\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"enumSwapType\",\"name\":\"swapType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"extRouter\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extCalldata\",\"type\":\"bytes\"},{\"internalType\":\"bool\",\"name\":\"needScale\",\"type\":\"bool\"}],\"internalType\":\"structSwapData\",\"name\":\"swapData\",\"type\":\"tuple\"}],\"internalType\":\"structTokenInput\",\"name\":\"input\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"limitRouter\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"epsSkipMarket\",\"type\":\"uint256\"},{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"salt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"enumIPLimitOrderType.OrderType\",\"name\":\"orderType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"YT\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lnImpliedRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"failSafeRate\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"permit\",\"type\":\"bytes\"}],\"internalType\":\"structOrder\",\"name\":\"order\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"}],\"internalType\":\"structFillOrderParams[]\",\"name\":\"normalFills\",\"type\":\"tuple[]\"},{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"salt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"expiry\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"enumIPLimitOrderType.OrderType\",\"name\":\"orderType\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"YT\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"maker\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"lnImpliedRate\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"failSafeRate\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"permit\",\"type\":\"bytes\"}],\"internalType\":\"structOrder\",\"name\":\"order\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"signature\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"makingAmount\",\"type\":\"uint256\"}],\"internalType\":\"structFillOrderParams[]\",\"name\":\"flashFills\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"optData\",\"type\":\"bytes\"}],\"internalType\":\"structLimitOrderData\",\"name\":\"limit\",\"type\":\"tuple\"}],\"name\":\"swapExactTokenForPt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"netPtOut\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"netSyFee\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"netSyInterm\",\"type\":\"uint256\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]" +} diff --git a/src/warpy_sync/controller.go b/src/warpy_sync/controller.go index d9414584..1ec7d3ac 100644 --- a/src/warpy_sync/controller.go +++ b/src/warpy_sync/controller.go @@ -3,6 +3,7 @@ package warpy_sync import ( "errors" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/warp-contracts/syncer/src/utils/config" "github.com/warp-contracts/syncer/src/utils/eth" "github.com/warp-contracts/syncer/src/utils/model" @@ -90,15 +91,24 @@ func NewController(config *config.Config) (self *Controller, err error) { writerTask = writer.Task syncerTask = syncer.Task syncerOutput = syncer.Output - case eth.Sommelier, eth.LayerBank: - contractAbi, errAbi := eth.GetContractABI( - config.WarpySyncer.SyncerDepositContractId, - config.WarpySyncer.SyncerApiKey, - config.WarpySyncer.SyncerChain) - - err = errAbi - - // Checks wether block's transactions contain specific Sommelier transactions + case eth.Sommelier, eth.LayerBank, eth.Pendle: + var contractAbi *abi.ABI + switch config.WarpySyncer.SyncerProtocol { + + case eth.Sommelier, eth.LayerBank: + contractAbi, err = eth.GetContractABI( + config.WarpySyncer.SyncerDepositContractId, + config.WarpySyncer.SyncerApiKey, + config.WarpySyncer.SyncerChain) + case eth.Pendle: + contractAbi, err = eth.GetContractABIFromFile("IPActionSwapPTV3.json") + + default: + self.Log.WithError(err).Error("ETH Protocol not recognized") + return + } + + // Checks wether block's transactions contain specific transactions syncer := NewSyncerDeposit(config). WithMonitor(monitor). WithInputChannel(blockDownloader.Output). diff --git a/src/warpy_sync/poller_deposit.go b/src/warpy_sync/poller_deposit.go index e6109979..0e8b7e8a 100644 --- a/src/warpy_sync/poller_deposit.go +++ b/src/warpy_sync/poller_deposit.go @@ -66,10 +66,11 @@ func (self *PollerDeposit) handleNew() (err error) { Raw(`SELECT from_address, SUM(assets) FROM warpy_syncer_assets - WHERE timestamp < ? AND chain = ? AND protocol = ? + WHERE timestamp < ? AND chain = ? AND protocol = ? + AND from_address = ? group by from_address; `, time.Now().Unix()-self.Config.WarpySyncer.PollerDepositSecondsForSelect, - self.Config.WarpySyncer.SyncerChain, self.Config.WarpySyncer.SyncerProtocol). + self.Config.WarpySyncer.SyncerChain, self.Config.WarpySyncer.SyncerProtocol, "0x64937ab314bc1999396De341Aa66897C30008852"). Scan(&AssetsSums).Error if err != nil { diff --git a/src/warpy_sync/store_deposit.go b/src/warpy_sync/store_deposit.go index 1dc37034..5cae17d0 100644 --- a/src/warpy_sync/store_deposit.go +++ b/src/warpy_sync/store_deposit.go @@ -2,6 +2,7 @@ package warpy_sync import ( "context" + "encoding/json" "errors" "math" "math/big" @@ -77,13 +78,20 @@ func (self *StoreDeposit) run() (err error) { Transaction(func(dbTx *gorm.DB) error { err = self.insertLog(dbTx, payload.Transaction, payload.FromAddress, payload.Block, payload.Method, payload.ParsedInput) - var ethTxAssetsFieldName string + var assets interface{} if slices.Contains(self.Config.WarpySyncer.StoreDepositWithdrawFunctions, payload.Method.Name) { - ethTxAssetsFieldName = self.Config.WarpySyncer.StoreDepositDepositAssetsName + assets = self.getAssetsFromInput(self.Config.WarpySyncer.StoreDepositWithdrawAssetsNames, payload.Input) } else { - ethTxAssetsFieldName = self.Config.WarpySyncer.StoreDepositWithdrawAssetsName + assets = self.getAssetsFromInput(self.Config.WarpySyncer.StoreDepositDepositAssetsNames, payload.Input) } - err = self.insertAssets(dbTx, payload.Transaction, payload.FromAddress, eth.WeiToEther(payload.Input[ethTxAssetsFieldName].(*big.Int)), payload.Method.Name, payload.Block) + + assetsVal := self.convertAssets(assets) + + if assetsVal == nil { + return nil + } + + err = self.insertAssets(dbTx, payload.Transaction, payload.FromAddress, eth.WeiToEther(assetsVal), payload.Method.Name, payload.Block) if err != nil { return err } @@ -237,3 +245,37 @@ func (self *StoreDeposit) insertAssets(dbTx *gorm.DB, tx *types.Transaction, fro return } + +func (self *StoreDeposit) getAssetsFromInput(assetsNames []string, input map[string]interface{}) (assets interface{}) { + for i, a := range assetsNames { + if i == 0 { + assets = input[a] + } else { + var assetsInterface map[string]interface{} + assetsParsed, _ := json.Marshal(assets) + err := json.Unmarshal(assetsParsed, &assetsInterface) + if err != nil { + self.Log.WithError(err).Error("Could not parse assets input") + return nil + } + assets = assetsInterface[a] + } + } + + return +} + +func (self *StoreDeposit) convertAssets(assets interface{}) (assetsVal *big.Int) { + switch assets := assets.(type) { + case float64: + assetsVal = new(big.Int) + new(big.Float).SetFloat64(assets).Int(assetsVal) + case *big.Int: + assetsVal = assets + default: + self.Log.WithField("assets", assets).Error("Assets type unsupported") + return nil + } + + return +} diff --git a/src/warpy_sync/syncer_deposit.go b/src/warpy_sync/syncer_deposit.go index 816db978..b5c8bc03 100644 --- a/src/warpy_sync/syncer_deposit.go +++ b/src/warpy_sync/syncer_deposit.go @@ -6,10 +6,12 @@ import ( "errors" "fmt" "slices" + "strings" "sync" "github.com/cenkalti/backoff" "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/warp-contracts/syncer/src/utils/config" "github.com/warp-contracts/syncer/src/utils/eth" @@ -125,7 +127,7 @@ func (self *SyncerDeposit) checkTx(tx *types.Transaction, block *BlockInfoPayloa return err }). Run(func() error { - if tx.To() != nil && tx.To().String() == self.Config.WarpySyncer.SyncerDepositContractId { + if tx.To() != nil && strings.EqualFold(tx.To().String(), self.Config.WarpySyncer.SyncerDepositContractId) { self.Log.WithField("tx_id", tx.Hash()).Info("Found new on-chain transaction") method, inputsMap, err := eth.DecodeTransactionInputData(self.contractAbi, tx.Data()) if err != nil { @@ -135,31 +137,26 @@ func (self *SyncerDeposit) checkTx(tx *types.Transaction, block *BlockInfoPayloa if slices.Contains(self.Config.WarpySyncer.SyncerDepositFunctions, method.Name) { parsedInputsMap, err := json.Marshal(inputsMap) + if err != nil { + self.Log.WithError(err).Error("Could not parse transaction input") + return err + } - tokenName := inputsMap["lToken"] - tokenNameStr := fmt.Sprintf("%v", tokenName) - self.Log.WithField("token_name", tokenNameStr).Info("Token set for transfer") - - // TODO: do it properly (i.e. via params, not hardcoded) - if self.Config.WarpySyncer.SyncerChain == eth.Mode { - if tokenNameStr != "0x6A0d9584D88D22BcaD7D4F83E7d6AB7949895DDF" { - self.Log.WithField("token_name", tokenNameStr).Warn("Wrong token set for transfer") + if (self.Config.WarpySyncer.SyncerChain == eth.Mode) || (self.Config.WarpySyncer.SyncerChain == eth.Manta) { + contains := self.containsSpecificToken(inputsMap) + if !contains { return nil } } - if self.Config.WarpySyncer.SyncerChain == eth.Manta { - if tokenNameStr != "0x71384B2c17433Ba1D8F6Fe895E9B2E7953dCED68" { - self.Log.WithField("token_id", tokenNameStr).Warn("Wrong token set for transfer") + // need to check if deposit is being sent to one of the specific pools + if self.Config.WarpySyncer.SyncerProtocol == eth.Pendle { + belongs := self.belongsToMarket(inputsMap, tx.Hash()) + if !belongs { return nil } } - if err != nil { - self.Log.WithError(err).Error("Could not parse transaction input") - return err - } - self.Log.WithField("method_name", method.Name).WithField("inputs_map", string(parsedInputsMap)). Info("New transaction decoded") @@ -189,3 +186,39 @@ func (self *SyncerDeposit) checkTx(tx *types.Transaction, block *BlockInfoPayloa return } + +func (self *SyncerDeposit) containsSpecificToken(inputsMap map[string]interface{}) bool { + tokenName := inputsMap["lToken"] + tokenNameStr := fmt.Sprintf("%v", tokenName) + self.Log.WithField("token_name", tokenNameStr).Info("Token set for transfer") + + // TODO: do it properly (i.e. via params, not hardcoded) + if self.Config.WarpySyncer.SyncerChain == eth.Mode { + if tokenNameStr != self.Config.WarpySyncer.SyncerDepositToken { + self.Log.WithField("token_name", tokenNameStr).Warn("Wrong token set for transfer") + return false + } + } + + if self.Config.WarpySyncer.SyncerChain == eth.Manta { + if tokenNameStr != self.Config.WarpySyncer.SyncerDepositToken { + self.Log.WithField("token_id", tokenNameStr).Warn("Wrong token set for transfer") + return false + } + } + + return true +} + +func (self *SyncerDeposit) belongsToMarket(inputsMap map[string]interface{}, txHash common.Hash) bool { + market := inputsMap["market"] + marketStr := fmt.Sprintf("%v", market) + + if !(slices.Contains(self.Config.WarpySyncer.SyncerDepositMarkets, marketStr)) { + self.Log.WithField("tx_id", txHash).WithField("market", marketStr).Warn("Token deposit does not belong to desired market") + return false + } + + self.Log.WithField("tx_id", txHash).WithField("market", marketStr).Debug("Token deposit belongs to desired market") + return true +} diff --git a/tools/integration.go b/tools/integration.go new file mode 100644 index 00000000..60d730ad --- /dev/null +++ b/tools/integration.go @@ -0,0 +1,75 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "io" + "log" + "math/big" + "os" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/warp-contracts/syncer/src/utils/eth" +) + +func main() { + client, err := ethclient.Dial("https://arb1.arbitrum.io/rpc") + if err != nil { + log.Fatal(err) + } + + header, err := client.HeaderByNumber(context.Background(), big.NewInt(223091335)) + if err != nil { + log.Fatal(err) + } + + txCount, err := client.TransactionCount(context.Background(), header.Hash()) + if err != nil { + log.Fatal("tx count not executed") + } + + for i := 0; i < int(txCount); i++ { + tx, err := client.TransactionInBlock(context.Background(), header.Hash(), uint(i)) + if err != nil { + continue + } + + if tx.Hash().Hex() == "0xf05df1f98133fc32a32479eb6a0a85a9a1b697fa8ad348d30900b4d09dee829a" { + data, err := os.Open("src/warpy_sync/abi/IPActionSwapPTV3.json") + + if err != nil { + fmt.Println(err) + } + + byteValue, _ := io.ReadAll(data) + + rawABIResponse := ð.RawABIResponse{} + + err = json.Unmarshal(byteValue, rawABIResponse) + if err != nil { + log.Fatal(err) + } + + data.Close() + + contractAbi, _ := abi.JSON(strings.NewReader(*rawABIResponse.Result)) + + if err != nil { + log.Fatal(err) + } + + method, inputsMap, err := eth.DecodeTransactionInputData(&contractAbi, tx.Data()) + if err != nil { + log.Fatal(err) + } + + fmt.Println(method) + fmt.Println(inputsMap) + } + + } + +}