-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #33 from taikoxyz/ritsu
feat: index ritsu LP token transfers
- Loading branch information
Showing
13 changed files
with
4,184 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#/bin/sh | ||
|
||
names=("erc20", "ritsu") | ||
|
||
|
||
for (( i = 0; i < ${#names[@]}; ++i )); | ||
do | ||
lower=$(echo "${names[i]}" | tr '[:upper:]' '[:lower:]') | ||
abigen --abi ${names[i]}.json \ | ||
--pkg $lower \ | ||
--type ${names[i]} \ | ||
--out adapters/contracts/$lower/${names[i]}.go | ||
done | ||
|
||
exit 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
package ritsu | ||
|
||
import ( | ||
"context" | ||
"math/big" | ||
"strings" | ||
|
||
"github.com/ethereum/go-ethereum/accounts/abi" | ||
"github.com/ethereum/go-ethereum/accounts/abi/bind" | ||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/core/types" | ||
"github.com/ethereum/go-ethereum/crypto" | ||
"github.com/ethereum/go-ethereum/ethclient" | ||
"github.com/taikoxyz/trailblazer-adapters/adapters" | ||
"github.com/taikoxyz/trailblazer-adapters/adapters/contracts/erc20" | ||
"github.com/taikoxyz/trailblazer-adapters/adapters/contracts/ritsu" | ||
) | ||
|
||
var ( | ||
logTransferSigHash = crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)")) | ||
) | ||
|
||
// TransferIndexer is an implementation of LogsIndexer for ERC20 transfer logs. | ||
type TransferIndexer struct { | ||
token common.Address | ||
} | ||
|
||
// NewTransferIndexer creates a new TransferIndexer. | ||
func NewTransferIndexer(token common.Address) *TransferIndexer { | ||
return &TransferIndexer{ | ||
token: token, | ||
} | ||
} | ||
|
||
func (indexer *TransferIndexer) Address() common.Address { | ||
return indexer.token | ||
} | ||
|
||
// IndexLogs processes logs for ERC20 transfers. | ||
func (indexer *TransferIndexer) IndexLogs(ctx context.Context, chainID *big.Int, client *ethclient.Client, logs []types.Log) ([]adapters.LPTransfer, error) { | ||
var result []adapters.LPTransfer | ||
for _, vLog := range logs { | ||
if !isERC20Transfer(vLog) { | ||
continue | ||
} | ||
transferData, err := indexer.ProcessLog(ctx, chainID, client, vLog) | ||
if err != nil { | ||
return nil, err | ||
} | ||
result = append(result, *transferData) | ||
} | ||
return result, nil | ||
} | ||
|
||
func isERC20Transfer(vLog types.Log) bool { | ||
return len(vLog.Topics) == 3 && vLog.Topics[0].Hex() == logTransferSigHash.Hex() | ||
} | ||
|
||
func (indexer *TransferIndexer) ProcessLog(ctx context.Context, chainID *big.Int, client *ethclient.Client, vLog types.Log) (*adapters.LPTransfer, error) { | ||
// Extract "from" and "to" addresses from the log | ||
to := common.BytesToAddress(vLog.Topics[2].Bytes()[12:]) | ||
from := common.BytesToAddress(vLog.Topics[1].Bytes()[12:]) | ||
|
||
// Unpack the transfer event | ||
var transferEvent struct { | ||
Value *big.Int | ||
} | ||
if err := unpackTransferEvent(vLog, &transferEvent); err != nil { | ||
return nil, err | ||
} | ||
|
||
// Fetch the block details | ||
block, err := client.BlockByNumber(ctx, big.NewInt(int64(vLog.BlockNumber))) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Initialize the LP token caller | ||
token, err := ritsu.NewRitsuCaller(indexer.token, client) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Fetch reserve balances and token addresses | ||
reserves, token0Address, token1Address, err := fetchReservesAndTokens(token, block.Number()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Calculate user's share of the pool | ||
shareOfPool, err := calculateShareOfPool(transferEvent.Value, token, block.Number()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Fetch token details (decimals) | ||
_, token0Decimals, err := fetchTokenDetails(token0Address, client) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
_, token1Decimals, err := fetchTokenDetails(token1Address, client) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Calculate the user's share of each token in the pool | ||
token0Share := calculateTokenShare(shareOfPool, reserves.Reserve0) | ||
token1Share := calculateTokenShare(shareOfPool, reserves.Reserve1) | ||
|
||
// Return the LPTransfer struct with calculated values | ||
return &adapters.LPTransfer{ | ||
From: from, | ||
To: to, | ||
Token0Amount: token0Share, | ||
Token0Decimals: token0Decimals, | ||
Token0: token0Address, | ||
Token1Amount: token1Share, | ||
Token1Decimals: token1Decimals, | ||
Token1: token1Address, | ||
Time: block.Time(), | ||
BlockNumber: block.Number().Uint64(), | ||
}, nil | ||
} | ||
|
||
// Helper function to unpack the transfer event from the log | ||
func unpackTransferEvent(vLog types.Log, transferEvent *struct{ Value *big.Int }) error { | ||
ritsuABI, err := abi.JSON(strings.NewReader(erc20.Erc20ABI)) | ||
if err != nil { | ||
return err | ||
} | ||
return ritsuABI.UnpackIntoInterface(transferEvent, "Transfer", vLog.Data) | ||
} | ||
|
||
// Helper function to fetch reserves and token addresses from the LP contract | ||
func fetchReservesAndTokens(token *ritsu.RitsuCaller, blockNumber *big.Int) (reserves struct { | ||
Reserve0 *big.Int | ||
Reserve1 *big.Int | ||
}, token0Address, token1Address common.Address, err error) { | ||
reserves, err = token.GetReserves(nil) | ||
if err != nil { | ||
return | ||
} | ||
|
||
token0Address, err = token.Token0(&bind.CallOpts{BlockNumber: blockNumber}) | ||
if err != nil { | ||
return | ||
} | ||
|
||
token1Address, err = token.Token1(&bind.CallOpts{BlockNumber: blockNumber}) | ||
return | ||
} | ||
|
||
// Helper function to calculate the user's share of the pool | ||
func calculateShareOfPool(transferValue *big.Int, token *ritsu.RitsuCaller, blockNumber *big.Int) (*big.Rat, error) { | ||
totalSupply, err := token.TotalSupply(&bind.CallOpts{BlockNumber: blockNumber}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return new(big.Rat).SetFrac(transferValue, totalSupply), nil | ||
} | ||
|
||
// Helper function to fetch token details (caller and decimals) | ||
func fetchTokenDetails(tokenAddress common.Address, client *ethclient.Client) (token *erc20.Erc20Caller, decimals uint8, err error) { | ||
token, err = erc20.NewErc20Caller(tokenAddress, client) | ||
if err != nil { | ||
return | ||
} | ||
|
||
decimals, err = token.Decimals(nil) | ||
return | ||
} | ||
|
||
// Helper function to calculate the share of a specific token in the pool | ||
func calculateTokenShare(shareOfPool *big.Rat, reserve *big.Int) *big.Int { | ||
tokenShare := new(big.Int).Mul(shareOfPool.Num(), reserve) | ||
return tokenShare.Div(tokenShare, shareOfPool.Denom()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package cmd | ||
|
||
import ( | ||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/ethclient" | ||
"github.com/taikoxyz/trailblazer-adapters/adapters/projects/ritsu" | ||
) | ||
|
||
func processRitsuLPIndexer(client *ethclient.Client, blockNumber int64) error { | ||
processor := ritsu.NewTransferIndexer(common.HexToAddress("0x7c38E9389B27668280E5aaAc372eBCb2ECc1c5E0")) | ||
return processLPLogIndexer(client, processor, blockNumber) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.