github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/pricing/uniswap.go (about) 1 package pricing 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/articulate" 8 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base" 9 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/call" 10 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/rpc" 11 "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/types" 12 ) 13 14 var ( 15 daiAddress = base.HexToAddress("0x6b175474e89094c44da98b954eedeac495271d0f") // DAI 16 wethAddress = base.HexToAddress("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2") // WETH 17 uniswapFactoryV2 = base.HexToAddress("0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f") 18 uniswapFactoryV2_deployed = base.Blknum(10000835) // why query for this immutable value each time we need it? 19 ) 20 21 // priceUsdUniswap returns the price of the given asset in USD as of the given block number. 22 func priceUsdUniswap(conn *rpc.Connection, statement *types.Statement) (price base.Float, source string, err error) { 23 multiplier := base.Float(1.0) 24 var first base.Address 25 var second base.Address 26 if statement.IsEth() { 27 first = daiAddress 28 second = wethAddress 29 30 } else { 31 temp := *statement 32 temp.AssetAddr = base.FAKE_ETH_ADDRESS 33 temp.AssetSymbol = "WEI" 34 multiplier, _, err = priceUsdUniswap(conn, &temp) 35 if err != nil { 36 return 0.0, "not-priced", err 37 } 38 first = wethAddress 39 second = statement.AssetAddr 40 } 41 42 reversed := false 43 if first.Hex() > second.Hex() { 44 save := second 45 second = first 46 first = save 47 reversed = true 48 } 49 50 theCall1 := fmt.Sprintf("getPair(%s, %s)", first.Hex(), second.Hex()) 51 contractCall, _, err := call.NewContractCall(conn, uniswapFactoryV2, theCall1) 52 if err != nil { 53 wrapped := fmt.Errorf("the --call value provided (%s) was not found: %s", theCall1, err) 54 return 0.0, "not-priced", wrapped 55 } 56 contractCall.BlockNumber = statement.BlockNumber 57 58 artFunc := func(str string, function *types.Function) error { 59 return articulate.ArticulateFunction(function, "", str[2:]) 60 } 61 result, err := contractCall.Call(artFunc) 62 if err != nil { 63 return 0.0, "not-priced", err 64 } 65 pairAddress := base.HexToAddress(result.Values["val_0"]) 66 if pairAddress.IsZero() { 67 msg := fmt.Sprintf("no pair found for %s and %s", first.Hex(), second.Hex()) 68 return 0.0, "not-priced", errors.New(msg) 69 } 70 theCall2 := "getReserves()" 71 contractCall, _, err = call.NewContractCall(conn, pairAddress, theCall2) 72 if err != nil { 73 wrapped := fmt.Errorf("the --call value provided (%s) was not found: %s", theCall2, err) 74 return 0.0, "not-priced", wrapped 75 } 76 contractCall.BlockNumber = statement.BlockNumber 77 result, err = contractCall.Call(artFunc) 78 if err != nil { 79 return 0.0, "not-priced", err 80 } 81 reserve0 := new(base.Ether) 82 if result.Values != nil && (result.Values["_reserve0"] == "" || result.Values["_reserve0"] == "0") { 83 reserve0.SetString("1") 84 } else { 85 reserve0.SetString(result.Values["_reserve0"]) 86 } 87 reserve1 := new(base.Ether) 88 if result.Values != nil && (result.Values["_reserve1"] == "" || result.Values["_reserve1"] == "0") { 89 reserve1.SetString("1") 90 } else { 91 reserve1.SetString(result.Values["_reserve1"]) 92 } 93 bigPrice := new(base.Ether) 94 bigPrice = bigPrice.Quo(reserve0, reserve1) 95 96 price = base.Float(bigPrice.Float64()) 97 price *= multiplier 98 source = "uniswap" 99 100 r := priceDebugger{ 101 address: statement.AssetAddr, 102 symbol: statement.AssetSymbol, 103 blockNumber: statement.BlockNumber, 104 source1: uniswapFactoryV2, 105 theCall1: theCall1, 106 source2: pairAddress, 107 theCall2: theCall2, 108 first: first, 109 second: second, 110 reversed: reversed, 111 float0: reserve0, 112 float1: reserve1, 113 float2: new(base.Ether).SetFloat64(float64(multiplier)), 114 bigPrice: bigPrice, 115 price: price, 116 source: source, 117 } 118 r.report("using Uniswap") 119 120 return price, source, nil 121 }