How to mapping the price of an asset with chain links and solidity? - oracle

I have a contract that has to save the time and price of eth via chainlink. The time works and has no problems. The price, on the other hand, fails to be recorded either with an array or with a mapping. I have tried several solutions, which include push().
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
interface EACAggregatorProxy {
function latestAnswer() external view returns (int256);
}
contract oracleLink {
uint256 deadline;
uint256 startTime = startTimes[block.timestamp];
mapping(uint => uint) startTimes;
address public chainLinkETHUSDAddress = 0x9326BFA02ADD2366b30bacB125260Af641031331;
uint public ethPrice = 0;
uint256 price = ethPrice;
mapping(uint => uint) ethPrice;
function priceOnTime() public payable {
deadline = block.timestamp + (numberOfSeconds * 1 seconds);
int256 chainLinkEthPrice = EACAggregatorProxy(chainLinkETHUSDAddress).latestAnswer();
ethPrice = uint(chainLinkEthPrice / 100000000);
return ethPrice;
}
}

The chainLinkETHUSDAddress address hardcoded in your source contains a contract only on the Kovan testnet. Meaning, this code works only on this testnet or its forks, and fails on other networks.
If you want to use the returned value in Remix, you need to create a local fork of the Kovan testnet and then connect to this local network using the Environment selectbox in Remix.

Your code is not using the mapping correctly. I mapping is like an array, just more efficient in some ways, but also has some limitations.
so to use your mapping you need to use it as
ethPrice[x] = y;
Where both x and y are an uint (as you specified the mapping uint => uint). So each unique uint maps (refers) to another uint.
ethPrice[x] = uint(chainLinkEthPrice / 100000000);
Where x is an uint you use to lookup the value later on with.

You're incorrectly storing the mapping. Mapping has to be stored as variable[key]=value.
https://www.tutorialspoint.com/solidity/solidity_mappings.htm

Related

How get USDT balance BEP-20? web3.eth.getBalance

Good day! Can you please tell me how you can get the balance of the USDT address? I found a way to get BNB balance (https://docs.binance.org/smart-chain/developer/BEP20.html), but there is no example for USDT
Token balance of an address is not a property of the address. It is stored in each of the token's contract. So you need to call the balanceOf() function of the token contract, passing it the holder address as a parameter.
For example the BUSD token:
const busdAddress = "0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56";
const holderAddress = "0x8894e0a0c962cb723c1976a4421c95949be2d4e3";
// just the `balanceOf()` is sufficient in this case
const abiJson = [
{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},
];
const contract = new web3.eth.Contract(abiJson, busdAddress);
const balance = await contract.methods.balanceOf(holderAddress).call();
// note that this number includes the decimal places (in case of BUSD, that's 18 decimal places)
console.log(balance);

How to structure many complex conditionals on a class

I have a class (as a protobuf) OrderChange, that represents when an order (imagine Amazon.com) changes:
message OrderChange {
Order old_order = 1;
Order new_order = 2;
}
message Order {
OrderType order_type = 1;
OrderCategory order_category = 2;
OrderStatus order_status = 3;
// many more fields
}
enum OrderType {
ORDER_TYPE_RETAIL = 0;
ORDER_TYPE_BUSINESS = 1;
}
enum OrderCategory {
ORDER_CATEGORY_ELECTRONICS = 0;
ORDER_CATEGORY_FOOD = 1;
ORDER_CATEGORY_FURNITURE = 2;
ORDER_CATEGORY_FITNESS = 3;
ORDER_CATEGORY_HOUSEHOLD = 4;
}
enum OrderStatus {
ORDER_STATUS_PAID = 0;
ORDER_STATUS_SHIPPED = 1;
ORDER_STATUS_DELIVERED = 2;
}
For each OrderChange object, I want to trigger some code for each conditional. For example if Order is RETAIL, FURNITURE, and PAID, I want to send a specific email.
OrderType and OrderCategory probably won't change between old_order and new_order, so my code can look at only new_order for these fields. Other fields such as OrderType will change, and my code can compare old_order and new_order to know what changed.
My problem is that Order has many fields, each with many values, so the number of conditional combinations is huge. Using only if/else or switch/case would be unmaintainable code.
So my question is, what pattern can I use to make these conditionals more maintainable?
Maybe I can break the fields into handlers - a handler for each OrderType, then each of these handlers contain a list of handlers for each OrderCategory, and continuing to nest a single field for each level until there are no more fields. My issue would be that beyond maybe the OrderType being the highest level field, there is no clear hierarchical relationship for the other fields. As in, it's not clear that OrderCategory handlers should contain OrderType handlers.
How should I design this?
Is the intent that there is only one action that should be triggered? Say you have actions that should run on RETAIL + PAID and RETAIL + FURNITURE + PAID, these clearly can compete with each other and there would need to be a priority type system to deal with ensuring only one handled it. Something like chain of responsibility could be used, where you register the handlers in priority order. If on the other hand, you want all eligible handlers to process it, then you can simply iterate all registered change handlers and pass each the change notification and allow each to process it, which is effectively just a simple observer.

How to make Javers compare by field values rather than ID/object reference

I have an object like:
class Person {
Phone phone;
}
class Phone {
String number;
String prefix;
Phone(String n, String p) {
number = n;
prefix = p;
}
}
Now consider this code:
Person p = new Person();
p.phone = new Phone("444444", "01");
javers.commit(p);
p.phone = new Phone("555555", "01");
javers.commit(p);
In this case sees that the reference of Phone has changed. While that's good info, I don't really care about that. I just want to know when the value of the number field has changed, that's really what I am tracking.
How would I achieve that? I tried defining the Phone class as a ValueObject, but it doesn't seem to do the job, I still get it as reference change rather than value change in the resulting Commit snapshot. Should I register it as a Value instead?
Map Phone as ValueObject or let JaVers to apply default mapping, which is also ValueObject object. ValueObject are always compared property by property and never by reference. What do you mean by it doesn't seem to do the job?

Sorting for Azure DocumentDB

I want to use DocumentDB to store roughly 200.000 documents of the same type. The documents each get an integer id field and I would like to retrieve them paged, in reverse order (highest id first).
So recently I found out there is no sorting for DocumentDB (see also DocumentDB - query result order). Perhaps it is better to go for a different database (such as RavenDB) however, time is pressing and I want to avoid the cost of switching to another database.
The question:
I have been looking at implementing my own sorted index of the documents on the client side (ASP Web API 2). I was thinking of creating a SortedList of key(id) and value(document.selflink). Then I could create a Getter with parameters for count, offset and a predicate to filter the documents. Below I added a quick example.
I just have the feeling this is a bad idea; either slow, costing too many resources or can be better done another way. So I am open for implementation suggestions...
public class SortableDocumentDbRepository
{
private SortedList _sorted = new SortedList();
private readonly string _sortedPropertyName;
private DocumentCollection ReadOrCreateCollection(string databaseLink) {
DocumentCollection col = base.ReadOrCreateCollection(databaseLink);
var docs = Client.CreateDocumentQuery(Collection.DocumentsLink)
.AsEnumerable();
lock (_sorted.SyncRoot) {
foreach (Document doc in docs) {
var propVal = doc.GetPropertyValue<string>(_sortedPropertyName);
if (propVal != null) {
_sorted.Add(propVal, doc.SelfLink);
}
}
}
return col;
}
public List<T> GetItems<T>(int count, int offset, Expression<Func<T, bool>> predicate) {
List<T> result = new List<T>();
lock (_sorted.SyncRoot) {
var values = _sorted.GetValueList();
for (int i = offset; i < _sorted.Count; i++) {
var queryable = predicate != null ?
Client.CreateDocumentQuery<T>(values[i].ToString()).Where(predicate) :
Client.CreateDocumentQuery<T>(values[i].ToString());
T item = queryable.AsEnumerable().FirstOrDefault();
if (item == null || item.Equals(default(T))) continue;
result.Add(item);
if (result.Count >= count) return result;
}
}
return result;
}
}
Microsoft has implemented Sorting:
https://learn.microsoft.com/en-us/azure/cosmos-db/sql-api-sql-query-reference#bk_orderby_clause
Example: SELECT * FROM c ORDER BY c._ts DESC
As you mentioned, order by unfortunately isn't implemented yet.
Your approach looks reasonable to me.
I see you are using a predicate to narrow the query result set (pulling 200,000 records for any DB will be costly).
Since it looks like you are looking to order by id - you can also look in to setting up a range index on id allowing you to perform range queries (e.g. < and >) on the id and further narrow the query result set. There is also a range index included by default on the _ts (timestamp) system property on documents that may also be helpful in this context.
See: http://azure.microsoft.com/en-us/documentation/articles/documentdb-indexing-policies/

How to retrieve total view count of large number of pages combined from the GA API

We are interested in the statistics of the different pages combined from the Google Analytics core reporting API. The only way I found to query statistics multiple pages at the same is by creating a filter like so:
ga:pagePath==page?id=a,ga:pagePath==page?id=b,ga:pagePath==page?id=c
And this get escaped inside the filter parameter of the GET query.
However when the GET query gets over 2000 characters I get the following response:
414. That’s an error.
The requested URL /analytics/v3/data/ga... is too large to process. That’s all we know.
Note that just like in the example call the only part that is different per page is a GET parameter in the pagePath, but we have to OR a new filter specifying both the metric (pagePath) as well as the part of the path that is always identical.
Is there any way to specify a large number of different pages to query without hitting this limit in the GET query (I can't find any documentation for doing POST requests)? Or are there alternatives to creating batches of a max of X different pages per query and adding them up on my end?
Instead of using ga:pagePath as part of a filter you should use it as a dimension. You can get up to 10,000 rows per query this way and paginate to get all results. Then parse the results client side to get what you need. Additionally use a filter to scope the results down if possible based on your site structure or page names.
I am sharing a sample code where you can fetch more then 10,000 record data via help of Items PerPage
private void GetDataofPpcInfo(DateTime dtStartDate, DateTime dtEndDate, AnalyticsService gas, List<PpcReportData> lstPpcReportData, string strProfileID)
{
int intStartIndex = 1;
int intIndexCnt = 0;
int intMaxRecords = 10000;
var metrics = "ga:impressions,ga:adClicks,ga:adCost,ga:goalCompletionsAll,ga:CPC,ga:visits";
var r = gas.Data.Ga.Get("ga:" + strProfileID, dtStartDate.ToString("yyyy-MM-dd"), dtEndDate.ToString("yyyy-MM-dd"),
metrics);
r.Dimensions = "ga:campaign,ga:keyword,ga:adGroup,ga:source,ga:isMobile,ga:date";
r.MaxResults = 10000;
r.Filters = "ga:medium==cpc;ga:campaign!=(not set)";
while (true)
{
r.StartIndex = intStartIndex;
var dimensionOneData = r.Fetch();
dimensionOneData.ItemsPerPage = intMaxRecords;
if (dimensionOneData != null && dimensionOneData.Rows != null)
{
var enUS = new CultureInfo("en-US");
intIndexCnt++;
foreach (var lstFirst in dimensionOneData.Rows)
{
var objPPCReportData = new PpcReportData();
objPPCReportData.Campaign = lstFirst[dimensionOneData.ColumnHeaders.IndexOf(dimensionOneData.ColumnHeaders.FirstOrDefault(h => h.Name == "ga:campaign"))];
objPPCReportData.Keywords = lstFirst[dimensionOneData.ColumnHeaders.IndexOf(dimensionOneData.ColumnHeaders.FirstOrDefault(h => h.Name == "ga:keyword"))];
lstPpcReportData.Add(objPPCReportData);
}
intStartIndex = intIndexCnt * intMaxRecords + 1;
}
else break;
}
}
Only one thing is problamatic that your query length shouldn't exceed around 2000 odd characters

Resources