Skip to content

Commit

Permalink
30 add earned fees processing (#36)
Browse files Browse the repository at this point in the history
* feat: first try at fees calculation

* feat: extended removal message to include earned tokens (tested)

* improvement: try to use ABIs instead of splitting data fields by hard coded lengths

* improvement: general improvements, renamings

* improvement: namings and ABI file embeding
  • Loading branch information
Ssimonas authored Nov 22, 2023
1 parent 27903d9 commit db6b3c9
Show file tree
Hide file tree
Showing 9 changed files with 2,380 additions and 88 deletions.

Large diffs are not rendered by default.

1,221 changes: 1,221 additions & 0 deletions publisher/internal/analytics/ethereum/Uniswap_Liquidity_Position_contract.json

Large diffs are not rendered by default.

22 changes: 21 additions & 1 deletion publisher/internal/analytics/ethereum/analytics.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,41 @@ package ethereum

import (
"context"
_ "embed"
"errors"

"github.com/SyntropyNet/swapscope/publisher/pkg/analytics"
"github.com/SyntropyNet/swapscope/publisher/pkg/repository"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/patrickmn/go-cache"
)

var (
mintSig string
transferSig string
burnSig string
collectSig string

//go:embed Uniswap_Liquidity_Pool_contract.json
uniswapLiqPoolsABIJson string
uniswapLiqPoolsABI abi.ABI

//go:embed Uniswap_Liquidity_Position_contract.json
uniswapLiqPositionsABIJson string
uniswapLiqPositionsABI abi.ABI
)

const (
subSubject = "syntropy.ethereum.log-event"
uniswapPositionsOwner = "0xC36442b4a4522E871399CD717aBDD847Ab11FE88"
mintEventHeader = "Mint(address,address,int24,int24,uint128,uint256,uint256)"
mintEventHeader = "Mint(address,address,int24,int24,uint128,uint256,uint256)" // Matches function's name and parameters types list
mintEvent = "Mint" // Matches function's name
transferEventHeader = "Transfer(address,address,uint256)"
transferEvent = "Transfer"
burnEventHeader = "Burn(address,int24,int24,uint128,uint256,uint256)"
burnEvent = "Burn"
collectEventHeader = "Collect(address,address,int24,int24,uint128,uint128)"
collectEvent = "Collect"
addressWETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" // https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
addressUSDT = "0xdAC17F958D2ee523a2206206994597C13D831ec7" // https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7
addressUSDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" // https://etherscan.io/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Expand All @@ -43,6 +59,7 @@ func init() {
mintSig = convertToEventSignature(mintEventHeader)
transferSig = convertToEventSignature(transferEventHeader)
burnSig = convertToEventSignature(burnEventHeader)
collectSig = convertToEventSignature(collectEventHeader)
}

func New(ctx context.Context, db repository.Repository, opts ...Option) (*Analytics, error) {
Expand All @@ -63,6 +80,9 @@ func New(ctx context.Context, db repository.Repository, opts ...Option) (*Analyt

ret.eventLogCache = &EventLogCache{cache.New(ret.Options.eventLogCacheExpirationTime, ret.Options.eventLogCachePurgeTime)}

uniswapLiqPoolsABI = parseJsonToAbi(uniswapLiqPoolsABIJson)
uniswapLiqPositionsABI = parseJsonToAbi(uniswapLiqPositionsABIJson)

return ret, nil
}

Expand Down
59 changes: 26 additions & 33 deletions publisher/internal/analytics/ethereum/convert.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package ethereum

import (
"encoding/hex"
"encoding/json"
"fmt"
"log"
"math"
"math/big"
"strings"

"github.com/ethereum/go-ethereum/accounts/abi"
"golang.org/x/crypto/sha3"
)

Expand Down Expand Up @@ -63,6 +65,14 @@ func parseEventLogMessage(data []byte) (EventLog, error) {
return eLog, nil
}

func parseJsonToAbi(jsonABI string) abi.ABI {
abi, err := abi.JSON(strings.NewReader(jsonABI))
if err != nil {
log.Fatal(err)
}
return abi
}

// convertTransferAmount converts Transfer's hex amount into scaled actual amount of tokens
func convertTransferAmount(amountHex string, decimals int) float64 {
amount := convertHexToBigInt(amountHex)
Expand All @@ -72,41 +82,24 @@ func convertTransferAmount(amountHex string, decimals int) float64 {
return amountScaled
}

func splitBurnDatatoHexStrings(data string) (string, string, string, error) {
const (
AmountOffset = 2
AmountToken0Size = 64
AmountToken1Size = 64
RequiredDataFieldLength = 194
)

if len(data) != RequiredDataFieldLength {
return "", "", "", fmt.Errorf("the data field length is not of expected size, could not parse amount fields.")
func convertLogDataToHexAmounts(rawData string, eventName string) (string, string, error) {
var abiToUse abi.ABI
switch {
case eventName == collectEvent:
abiToUse = uniswapLiqPositionsABI
default:
abiToUse = uniswapLiqPoolsABI
}
amountHex := "0x" + data[AmountOffset:AmountOffset+AmountToken0Size]
amountToken0Hex := "0x" + data[AmountOffset+AmountToken0Size:AmountOffset+AmountToken0Size+AmountToken0Size]
amountToken1Hex := "0x" + data[AmountOffset+AmountToken0Size+AmountToken1Size:]
hexString := strings.TrimPrefix(rawData, "0x")
data, err := hex.DecodeString(hexString)

return amountHex, amountToken0Hex, amountToken1Hex, nil
}

func splitMintDatatoHexFields(data string) (string, string, string, error) {
const (
AmountOffset = 2
AmountOwnerAddress = 64
AmountSize = 64
AmountToken0Size = 64
AmountToken1Size = 64
RequiredDataFieldLength = 258
AmountSkip = AmountOffset + AmountOwnerAddress
)

if len(data) != RequiredDataFieldLength {
return "", "", "", fmt.Errorf("the data field length is not of expected size, could not parse amount fields.")
var args = make(map[string]interface{})
err = abiToUse.UnpackIntoMap(args, eventName, []byte(data))
if err != nil {
return "", "", err
}
amountHex := "0x" + data[AmountSkip:AmountSkip+AmountSize]
amountToken0Hex := "0x" + data[AmountSkip+AmountSize:AmountSkip+AmountSize+AmountToken0Size]
amountToken1Hex := "0x" + data[AmountSkip+AmountSize+AmountToken0Size:]

return amountHex, amountToken0Hex, amountToken1Hex, nil
resAmount0Hex := "0x" + args["amount0"].(*big.Int).Text(16)
resAmount1Hex := "0x" + args["amount1"].(*big.Int).Text(16)
return resAmount0Hex, resAmount1Hex, nil
}
4 changes: 2 additions & 2 deletions publisher/internal/analytics/ethereum/ethereum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ func Test_hasTopics(t *testing.T) {
}
}

func Test_isOrderCorrect(t *testing.T) {
func Test_isToken0StableAndToken1Native(t *testing.T) {
tests := []struct {
name string
input Position
Expand All @@ -185,7 +185,7 @@ func Test_isOrderCorrect(t *testing.T) {
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
res := test.input.isOrderCorrect()
res := test.input.isToken0StableAndToken1Native()
if res != test.trueRes {
t.Errorf("isOrderCorrect(%v) = (%v); expected (%v)", test.input, res, test.trueRes)
}
Expand Down
Loading

0 comments on commit db6b3c9

Please sign in to comment.