Published
Edited
May 11, 2020
Insert cell
Insert cell
md`Current block is ${block}`
Insert cell
mutable block = null
Insert cell
eth_calls
Insert cell
Insert cell
{
sendWithMulti;
const mkrToken = new ethers.Contract(
"0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2",
DSTokenAbi,
new ethers.providers.Web3Provider(providerWithMulti)
);
return Generators.observe(next => {
const values = [];
next(values);
[...new Array(100)].forEach(() => {
mkrToken
.balanceOf("0x9eF05f7F6deB616fd37aC3c959a2dDD25A54E4F5")
.then(balance => {
values.push(balance.toString());
next(values);
});
});
});
}
Insert cell
eth_calls
Insert cell
Insert cell
{
sendWithoutMulti;
const mkrToken = new ethers.Contract(
"0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2",
DSTokenAbi,
new ethers.providers.Web3Provider(providerWithoutMulti)
);
return Generators.observe(next => {
const values = [];
next(values);
[...new Array(100)].forEach(() => {
mkrToken
.balanceOf("0x9eF05f7F6deB616fd37aC3c959a2dDD25A54E4F5")
.then(balance => {
values.push(balance.toString());
next(values);
});
});
});
}
Insert cell
providerWithMulti = {
engine1.addProvider(
new MulticallSubprovider({
multicallAddress: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441',
rpcUrl
}),
0
);

engine1.addProvider(
new RpcSubprovider({
rpcUrl
}),
1
);

engine1.on('block', function(block) {
mutable block = parseInt(block.number.toString('hex'), 16);
});

engine1.start();
return engine1;
}
Insert cell
providerWithoutMulti = {
engine2.addProvider(
new RpcSubprovider({
rpcUrl
}),
0
);

engine2.on('block', function(block) {
mutable block = parseInt(block.number.toString('hex'), 16);
});

engine2.start();
return engine2;
}
Insert cell
MulticallSubprovider = {
const AGGREGATE_SELECTOR = '0x252dba42'; // Function signature for: aggregate((address,bytes)[])
// https://www.4byte.directory/signatures/?bytes4_signature=57de26a4
const sigFuncMap = {
'57de26a4': 'read()',
'51f91066': 'tag()',
'59e02dd7': 'peek()'
};
const sigToFunc = sig => {
return sigFuncMap[`${sig}`] || null;
};
return class extends SubProvider {
constructor(opts) {
super(opts);
this.multicallAddress = opts.multicallAddress;
if (!this.multicallAddress)
throw new Error('No multicall contract address specified');
this.rpcUrl = opts.rpcUrl;
if (!this.rpcUrl) throw new Error('No rpcUrl specified');
this.id = 100000;
this.latestBlock = null;
this.batchTimer = null;
this.batchDelay = opts.batchDelay || 500;
this.batchedTxs = [];
this.batchedCallbacks = [];
}
setEngine(engine) {
this.engine = engine;
engine.on('block', block => {
const blockNumber = parseInt(block.number.toString('hex'), 16);
this.latestBlock = blockNumber;
});
}
sendBatchedTxs() {
const values = this.batchedTxs.map(({ params }) => [
params[0].to,
params[0].data
]);
const calldata = ethers.utils.defaultAbiCoder.encode(
[
{
components: [{ type: 'address' }, { type: 'bytes' }],
name: 'data',
type: 'tuple[]'
}
],
[values]
);
const payload = {
jsonrpc: '2.0',
id: this.id++,
method: 'eth_call',
params: [
{
to: this.multicallAddress,
data: AGGREGATE_SELECTOR + calldata.substr(2)
},
'latest'
]
};
const callbacks = [...this.batchedCallbacks];
// Clear batched txs and callbacks
this.batchTimer = null;
this.batchedTxs = [];
this.batchedCallbacks = [];
fetch(this.rpcUrl, {
method: 'POST',
body: JSON.stringify(payload)
})
.then(resp => resp.json())
.then(({ result }) => {
const decoded = ethers.utils.defaultAbiCoder.decode(
['uint256', 'bytes[]'],
result
);
const [blockNumber, ...results] = decoded;
callbacks.forEach((cb, i) => cb(null, results[0][i]));
});
}
handleRequest(payload, next, end) {
if (payload.method === 'eth_call' && !payload.skipMulticall) {
const sig = payload.params[0].data.substr(2, 10);
this.batchedTxs.push(payload);
this.batchedCallbacks.push(end);
if (!this.batchTimer)
this.batchTimer = setTimeout(
() => this.sendBatchedTxs(),
this.batchDelay
);
return;
} else next();
}
};
}
Insert cell
rpcUrl = 'https://mainnet.infura.io/v3/7d0d81d0919f4f05b9ab6634be01ee73'
Insert cell
eth_calls = {
const calls = [];
return Generators.observe(next => {
next(calls);
xhook.after((request, response) => {
if (request.url.includes("infura")) {
const body = JSON.parse(request.body);
const method = body.method;
if (!method || !method.includes("eth_call")) return;
calls.push(request);
next(calls);
}
});
});
}
Insert cell
Insert cell
Insert cell
Insert cell
engine1 = new Engine()
Insert cell
engine2 = new Engine()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more