Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CCIP-2958] Token price reader implementation #67

Merged
merged 22 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7a78a26
WIP new token price reader
asoliman92 Aug 14, 2024
b324085
Bind first token aggregator to price reader
asoliman92 Aug 14, 2024
a64c23b
Moving price reader binding to chainlink inprocess.go and removing fr…
asoliman92 Aug 14, 2024
f942eea
Calculate USD price per 1e18 of smallest token denomination with 18 d…
asoliman92 Aug 15, 2024
6829d88
Fix call to GetLatestValue
asoliman92 Aug 15, 2024
2b55c95
Merge branch 'ccip-develop' into price-reader
asoliman92 Aug 15, 2024
9c4952d
Add decimals to offchain config
asoliman92 Aug 16, 2024
dc73503
Use TokenDecimals in on chain reader
asoliman92 Aug 19, 2024
19851b0
Normalize raw token prices
asoliman92 Aug 19, 2024
8bcd098
Validate all tokens has decimals in offchain config
asoliman92 Aug 19, 2024
691c7a6
Add comments
asoliman92 Aug 19, 2024
cf816e6
Merge branch 'ccip-develop' into price-reader
asoliman92 Aug 19, 2024
c31764c
Add new on chain prices reader to commitocb factory
asoliman92 Aug 19, 2024
2fe0c01
Validate ArbitrumPriceSource in the offchain config
asoliman92 Aug 19, 2024
2bc1395
Add comments
asoliman92 Aug 19, 2024
4e88e66
Merge branch 'ccip-develop' into price-reader
asoliman92 Aug 19, 2024
6ef8ee4
Fix tests - failing because of race condition
asoliman92 Aug 19, 2024
2b33e54
Make the test work with one token as expected
asoliman92 Aug 20, 2024
952025a
Update pluginconfig/commit.go
asoliman92 Aug 20, 2024
1661bba
Update pluginconfig/commit.go
asoliman92 Aug 20, 2024
fad8a3a
review comments
asoliman92 Aug 20, 2024
0f52997
Merge branch 'ccip-develop' into price-reader
asoliman92 Aug 20, 2024
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
18 changes: 10 additions & 8 deletions commit/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"math/big"

"google.golang.org/grpc"

Expand All @@ -15,7 +14,6 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/types/core"
"github.com/smartcontractkit/libocr/commontypes"
"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types"

"github.com/smartcontractkit/chainlink-ccip/internal/reader"
Expand Down Expand Up @@ -94,12 +92,16 @@ func (p *PluginFactory) NewReportingPlugin(config ocr3types.ReportingPluginConfi
oracleIDToP2PID[commontypes.OracleID(oracleID)] = p2pID
}

onChainTokenPricesReader := reader.NewOnchainTokenPricesReader(
reader.TokenPriceConfig{ // TODO: Inject config
StaticPrices: map[ocr2types.Account]big.Int{},
},
nil, // TODO: Inject this
)
var onChainTokenPricesReader reader.TokenPrices
// The node supports the chain that the token prices are on.
tokenPricesCr, ok := p.contractReaders[cciptypes.ChainSelector(offchainConfig.TokenPriceChainSelector)]
if ok {
onChainTokenPricesReader = reader.NewOnchainTokenPricesReader(
tokenPricesCr,
offchainConfig.PriceSources,
)
}

ccipReader := reader.NewCCIPChainReader(
p.lggr,
p.contractReaders,
Expand Down
3 changes: 2 additions & 1 deletion commit/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ func (p *Plugin) Observation(
// observe token prices if the node supports the token price chain
// otherwise move on to gas prices.
var tokenPrices []cciptypes.TokenPrice
if supportTPChain, err := p.supportsTokenPriceChain(); err == nil && supportTPChain {
if supportTPChain, err := p.supportsTokenPriceChain(); err == nil && supportTPChain && p.tokenPricesReader != nil {
p.lggr.Infow("observing token prices")
tokenPrices, err = observeTokenPrices(
ctx,
p.tokenPricesReader,
Expand Down
19 changes: 9 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ go 1.21.7
require (
github.com/deckarep/golang-set/v2 v2.6.0
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240712162033-89bd3351ce6e
github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c
github.com/smartcontractkit/libocr v0.0.0-20240717100443-f6226e09bee7
github.com/stretchr/testify v1.9.0
go.uber.org/zap v1.26.0
golang.org/x/crypto v0.24.0
golang.org/x/crypto v0.25.0
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
golang.org/x/sync v0.7.0
google.golang.org/grpc v1.64.1
Expand All @@ -20,28 +20,27 @@ require (
github.com/buger/jsonparser v1.1.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/invopop/jsonschema v0.12.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.17.0 // indirect
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.11.1 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/santhosh-tekuri/jsonschema/v5 v5.2.0 // indirect
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 // indirect
google.golang.org/protobuf v1.34.1 // indirect
Expand Down
40 changes: 18 additions & 22 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
Expand All @@ -28,8 +25,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/nolag/mapstructure v1.5.2-0.20240625151721-90ea83a3f479 h1:1jCGDLFXDOHF2sdeTJYKrIuSLGMpQZpgXXHNGXR5Ouk=
Expand All @@ -43,22 +40,22 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/santhosh-tekuri/jsonschema/v5 v5.2.0 h1:WCcC4vZDS1tYNxjWlwRJZQy28r8CMoggKnxNzxsVDMQ=
github.com/santhosh-tekuri/jsonschema/v5 v5.2.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0=
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240712162033-89bd3351ce6e h1:vKVNJfFXy4Wdq5paOV0/fNgql2GoXkei10+D+SmC+Qs=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240712162033-89bd3351ce6e/go.mod h1:fh9eBbrReCmv31bfz52ENCAMa7nTKQbdhb2B3+S2VGo=
github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c h1:lIyMbTaF2H0Q71vkwZHX/Ew4KF2BxiKhqEXwF8rn+KI=
github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM=
github.com/smartcontractkit/libocr v0.0.0-20240717100443-f6226e09bee7 h1:e38V5FYE7DA1JfKXeD5Buo/7lczALuVXlJ8YNTAUxcw=
github.com/smartcontractkit/libocr v0.0.0-20240717100443-f6226e09bee7/go.mod h1:fb1ZDVXACvu4frX3APHZaEBp0xi1DIm34DcA0CwTsZM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
Expand All @@ -77,17 +74,16 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
Expand Down
119 changes: 88 additions & 31 deletions internal/reader/onchain_prices_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ import (
"fmt"
"math/big"

"github.com/smartcontractkit/chainlink-ccip/pkg/consts"
"github.com/smartcontractkit/chainlink-ccip/pluginconfig"

"github.com/smartcontractkit/libocr/offchainreporting2plus/types"
ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
"golang.org/x/sync/errgroup"

commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
commontyps "github.com/smartcontractkit/chainlink-common/pkg/types"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"

"golang.org/x/sync/errgroup"
)

type TokenPrices interface {
Expand All @@ -18,55 +23,55 @@ type TokenPrices interface {
GetTokenPricesUSD(ctx context.Context, tokens []ocr2types.Account) ([]*big.Int, error)
}

type TokenPriceConfig struct {
// This is mainly used for inputTokens on testnet to give them a price
StaticPrices map[ocr2types.Account]big.Int `json:"staticPrices"`
}

type OnchainTokenPricesReader struct {
TokenPriceConfig TokenPriceConfig
// Reader for the chain that will have the token prices on-chain
ContractReader commontypes.ContractReader
ContractReader commontyps.ContractReader
PriceSources map[types.Account]pluginconfig.ArbitrumPriceSource
}

func NewOnchainTokenPricesReader(
tokenPriceConfig TokenPriceConfig, contractReader commontypes.ContractReader,
contractReader commontyps.ContractReader,
priceSources map[types.Account]pluginconfig.ArbitrumPriceSource,
) *OnchainTokenPricesReader {
return &OnchainTokenPricesReader{
TokenPriceConfig: tokenPriceConfig,
ContractReader: contractReader,
ContractReader: contractReader,
PriceSources: priceSources,
}
}

type LatestRoundData struct {
makramkd marked this conversation as resolved.
Show resolved Hide resolved
RoundID *big.Int
Answer *big.Int
StartedAt *big.Int
UpdatedAt *big.Int
AnsweredInRound *big.Int
}

func (pr *OnchainTokenPricesReader) GetTokenPricesUSD(
ctx context.Context, tokens []ocr2types.Account,
) ([]*big.Int, error) {
const (
contractName = "PriceAggregator"
functionName = "getTokenPrice"
)
prices := make([]*big.Int, len(tokens))
eg := new(errgroup.Group)
for idx, token := range tokens {
idx := idx
token := token
eg.Go(func() error {
price := new(big.Int)
if staticPrice, exists := pr.TokenPriceConfig.StaticPrices[token]; exists {
price.Set(&staticPrice)
} else {
if err :=
pr.ContractReader.GetLatestValue(
ctx,
contractName,
functionName,
primitives.Finalized,
token,
price); err != nil {
return fmt.Errorf("failed to get token price for %s: %w", token, err)
}
//TODO: Once chainreader new changes https://github.com/smartcontractkit/chainlink-common/pull/603
// are merged we'll need to use the bound contract
//boundContract := commontypes.BoundContract{
// Address: pr.PriceSources[token].AggregatorAddress,
// Name: consts.ContractNamePriceAggregator,
//}
rawTokenPrice, err := pr.getRawTokenPrice(ctx, token)
if err != nil {
return fmt.Errorf("failed to get token price for %s: %w", token, err)
}
decimals, err := pr.getTokenDecimals(ctx, token)
if err != nil {
return fmt.Errorf("failed to get decimals for %s: %w", token, err)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if you can use the BatchGetLatestValue API to do these calls as a batch call, it should be more efficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But they're different contracts for each token, What's the efficiency you mean here?

}
prices[idx] = price

prices[idx] = calculateUsdPer1e18TokenAmount(rawTokenPrice, *decimals)
return nil
})
}
Expand All @@ -84,5 +89,57 @@ func (pr *OnchainTokenPricesReader) GetTokenPricesUSD(
return prices, nil
}

func (pr *OnchainTokenPricesReader) getRawTokenPrice(ctx context.Context, token types.Account) (*big.Int, error) {
var latestRoundData *LatestRoundData
if err :=
pr.ContractReader.GetLatestValue(
ctx,
consts.ContractNamePriceAggregator,
consts.MethodNameGetLatestRoundData,
primitives.Unconfirmed,
asoliman92 marked this conversation as resolved.
Show resolved Hide resolved
nil,
&latestRoundData,
//boundContract,
asoliman92 marked this conversation as resolved.
Show resolved Hide resolved
); err != nil {
return nil, fmt.Errorf("latestRoundData call failed for token %s: %w", token, err)
}

if latestRoundData == nil {
return nil, fmt.Errorf("latestRoundData is nil for token %s", token)
}

return latestRoundData.Answer, nil
}

func (pr *OnchainTokenPricesReader) getTokenDecimals(ctx context.Context, token types.Account) (*uint8, error) {
var decimals *uint8
if err :=
pr.ContractReader.GetLatestValue(
ctx,
consts.ContractNamePriceAggregator,
consts.MethodNameGetDecimals,
primitives.Unconfirmed,
nil,
&decimals,
//boundContract,
); err != nil {
return nil, fmt.Errorf("decimals call failed for token %s: %w", token, err)
}

return decimals, nil
}

// Input price is USD per full token, with 18 decimal precision
// Result price is USD per 1e18 of smallest token denomination, with 18 decimal precision
// Examples:
//
// 1 USDC = 1.00 USD per full token, each full token is 1e6 units -> 1 * 1e18 * 1e18 / 1e6 = 1e30
// 1 ETH = 2,000 USD per full token, each full token is 1e18 units -> 2000 * 1e18 * 1e18 / 1e18 = 2_000e18
// 1 LINK = 5.00 USD per full token, each full token is 1e18 units -> 5 * 1e18 * 1e18 / 1e18 = 5e18
func calculateUsdPer1e18TokenAmount(price *big.Int, decimals uint8) *big.Int {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm the token price isn't always to 18 decimals though, that depends on the feed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is what the function is doing. It also shows in the tests, it's normalizing to 18 decimals depending on the decimals sent as a parameter.

tmp := big.NewInt(0).Mul(price, big.NewInt(1e18))
return tmp.Div(tmp, big.NewInt(0).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil))
}

// Ensure OnchainTokenPricesReader implements TokenPrices
var _ TokenPrices = (*OnchainTokenPricesReader)(nil)
Loading
Loading