Skip to content

Commit 1f5f623

Browse files
Merge pull request #20 from RoboVault/fix/logger-examples
add logger, deno tasks, and README to examples
2 parents 70368b6 + 973458f commit 1f5f623

34 files changed

+524
-73
lines changed

cli/start/mod.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { ArkiverMetadata } from '../../src/arkiver/arkive-metadata.ts'
1010
import { createManifestHandlers } from './logger.ts'
1111
import { colors, mongoose, SchemaComposer } from '../../src/deps.ts'
1212
import { logger } from '../../src/logger.ts'
13+
import { collectRpcUrls } from '../utils.ts'
14+
1315

1416
export const action = async (
1517
options: {
@@ -114,11 +116,17 @@ export const action = async (
114116
},
115117
})
116118

119+
// An RPC for our Arkive is going to be assigned at some point.
120+
// The order of assignment is as follows:
121+
// 1. CLI command line option -r, --rpc-url
122+
// 2. Env variables such as {CHAIN}_RPC_URL
123+
// 3. RPC url defined in manifest
124+
// 4. Default RPC of Viem
117125
const rpcUrls = options.rpcUrl?.reduce((acc, rpc) => {
118126
const [name, url] = rpc.split('=')
119127
acc[name] = url
120128
return acc
121-
}, {} as Record<string, string>) ?? {}
129+
}, {} as Record<string, string>) ?? collectRpcUrls() ?? {}
122130

123131
logger('arkiver').debug(`Connecting to database...`)
124132
const connectionString = options.mongoConnection ??

cli/utils.ts

+21
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { SUPABASE_ANON_PUBLIC_KEY, SUPABASE_URL } from './constants.ts'
22
import { createClient, Input, Secret, z } from './deps.ts'
33
import { login } from './login/mod.ts'
44
import { spinner } from './spinner.ts'
5+
import { supportedChains } from '../src/chains.ts'
56

67
export const getEmail = async () => {
78
const email = await Input.prompt('✉️ Email:')
@@ -127,3 +128,23 @@ export const craftEndpoint = (
127128
majorVersion ? majorVersion + '/' : ''
128129
}graphql`
129130
}
131+
132+
export const getEnv = (key: string, defaultValue?: string): string => {
133+
const value = Deno.env.get(key)
134+
if (!value && !defaultValue) {
135+
throw new Error(`Missing environment variable: ${key}`)
136+
}
137+
return value || defaultValue || ''
138+
}
139+
140+
export const collectRpcUrls = () => {
141+
const rpcUrls: Record<string, string> = {}
142+
for (const chain of Object.keys(supportedChains)) {
143+
try {
144+
rpcUrls[chain] = getEnv(`${chain.toUpperCase()}_RPC_URL`)
145+
} catch (_e) {
146+
// ignore
147+
}
148+
}
149+
return rpcUrls
150+
}

deno.lock

+45-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# ERC20 Balance History
2+
This Arkive keeps an accurate historical record of the sharePrice of a given set of YearnV2 Abi Vaults. sharePrice increases as profits are distributed to the vaults, but may also decrease if loss is incurred. It may be valuable to track this information in case of incidents or in order to optimize the vaults for instance.
3+
### Dependencies
4+
* Docker
5+
* Full Archive RPC (Infura, Ankr, Alchemy, etc)
6+
7+
### Arkive Usage
8+
9+
First make sure .env is configured correctly with your RPC endpoint. In this example we are connecting the `mainnet` with the Ankr public ETH endpoint.
10+
> MAINNET_RPC_URL=https://rpc.ankr.com/eth
11+
12+
All available tasks can been seen with
13+
> deno task
14+
15+
To start a new instance of the Arkive you can use `deno task` to run the `new` script with the following command
16+
> deno task new
17+
18+
To reset the database and resync the Arkive run `reset` task
19+
> deno task reset
20+
21+
### Using the GraphQL Explorer
22+
If Arkiver is running there should now be webpage avaiable at http://0.0.0.0:4000/graphql
23+
24+
In the left side you can use the no-code explorer to pick and choose which Entities and what fields of the Entities you would like to look at. Here is an example query for this Arkive. This fetches the latest VaultSnapshot entity.
25+
```
26+
query MyQuery {
27+
VaultSnapshot(sort: _ID_DESC) {
28+
vault
29+
name
30+
symbol
31+
block
32+
timestamp
33+
sharePrice
34+
}
35+
}
36+
```
37+
38+

examples/block-handler-vaults/abis/YearnV2.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const YearnV2Abi = [{
1+
export const YEARN_V2_ABI = [{
22
'name': 'Transfer',
33
'inputs': [{ 'name': 'sender', 'type': 'address', 'indexed': true }, {
44
'name': 'receiver',
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"tasks": {
3+
"start": "arkiver start ./ -c mongodb://localhost:27017",
4+
"new": "docker run --name mongo -d -p 27017:27017 mongodb/mongodb-community-server:latest && arkiver start ./ -c mongodb://localhost:27017",
5+
"resetdb": "docker stop mongo && docker rm mongo && docker run --name mongo -d -p 27017:27017 mongodb/mongodb-community-server:latest",
6+
"reset": "docker stop mongo && docker rm mongo && docker run --name mongo -d -p 27017:27017 mongodb/mongodb-community-server:latest && arkiver start ./ -c mongodb://localhost:27017",
7+
"newdb": "docker run --name mongo -d -p 27017:27017 mongodb/mongodb-community-server:latest",
8+
"stopdb": "docker stop mongo",
9+
"rmdb": "docker rm mongo",
10+
"startdb": "docker start mongo",
11+
"deploy": "arkiver deploy ./"
12+
}
13+
}

examples/block-handler-vaults/handlers/vault.ts

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { formatUnits, getContract } from 'npm:viem'
22
import { type BlockHandler } from 'https://deno.land/x/robo_arkiver@v0.4.19/mod.ts'
33
import { VaultSnapshot } from '../entities/vault.ts'
4-
import { YearnV2Abi } from '../abis/YearnV2.ts'
4+
import { YEARN_V2_ABI } from '../abis/YearnV2.ts'
55

66
const VAULTS = [
77
{ address: '0xdA816459F1AB5631232FE5e97a05BBBb94970c95', block: 12796965 }, // yvDAI
@@ -12,6 +12,7 @@ export const snapshotVault: BlockHandler = async ({
1212
block,
1313
client,
1414
store,
15+
logger,
1516
}): Promise<void> => {
1617
// Filter out vaults that haven't been deployed yet
1718
const liveVaults = VAULTS.filter((e) => e.block < Number(block.number))
@@ -20,12 +21,12 @@ export const snapshotVault: BlockHandler = async ({
2021
const vaults = await Promise.all(liveVaults.map(async (vault) => {
2122
const contract = getContract({
2223
address: vault.address,
23-
abi: YearnV2Abi,
24+
abi: YEARN_V2_ABI,
2425
publicClient: client,
2526
})
2627
return {
2728
address: vault.address,
28-
vault: { address: vault.address, abi: YearnV2Abi } as const,
29+
vault: { address: vault.address, abi: YEARN_V2_ABI } as const,
2930
contract,
3031
name: await store.retrieve(
3132
`${vault.address}:name`,
@@ -46,22 +47,24 @@ export const snapshotVault: BlockHandler = async ({
4647
const sharePrices = await Promise.all(vaults.map((e) => {
4748
return client.readContract({
4849
address: e.address,
49-
abi: YearnV2Abi,
50+
abi: YEARN_V2_ABI,
5051
functionName: 'pricePerShare',
5152
blockNumber: block.number,
5253
})
5354
}))
5455

5556
// Save the vault snapshots
5657
vaults.map((vault, i) => {
58+
const sharePrice = parseFloat(
59+
formatUnits(sharePrices[i], Number(vault.decimals)),
60+
)
61+
logger.info(`${vault.name} share price updated to ${sharePrice}`)
5762
return new VaultSnapshot({
58-
id: `${vault.address}-${Number(block.number)}`,
63+
// id: `${vault.address}-${Number(block.number)}`,
5964
block: Number(block.number),
6065
timestamp: Number(block.timestamp),
6166
vault: vault.address,
62-
sharePrice: parseFloat(
63-
formatUnits(sharePrices[i], Number(vault.decimals)),
64-
),
67+
sharePrice: sharePrice,
6568
name: vault.name,
6669
symbol: vault.symbol,
6770
})

examples/block-handler-vaults/manifest.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ const manifest = new Manifest('yearn-vaults')
66

77
manifest
88
.addEntity(VaultSnapshot)
9-
.addChain('mainnet')
10-
.addBlockHandler({
11-
blockInterval: 1000,
12-
startBlockHeight: 12790000n,
13-
handler: snapshotVault,
14-
})
9+
.addChain('mainnet', (chain) =>
10+
chain
11+
.addBlockHandler({
12+
blockInterval: 1000,
13+
startBlockHeight: 12790000n,
14+
handler: snapshotVault,
15+
}))
1516

1617
export default manifest
1718
.build()

examples/erc20-balance-history/erc20.ts examples/erc20-balance-history/Erc20.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export default [{
1+
export const ERC_20_ABI = [{
22
'inputs': [],
33
'stateMutability': 'nonpayable',
44
'type': 'constructor',
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# ERC20 Balance History
2+
This Arkive keeps an accurate historical record of the balance of an account of a given ERC20 token. It uses the Balance entity as a mutable variable updates as events are handled and is used to keep track of an accounts balance as we sync eventually reflecting true onchain balance. BalanceHistory is an unchanging entity which stores balance over time and is indexed by the `block` field.
3+
### Dependencies
4+
* Docker
5+
* Full Archive RPC (Infura, Ankr, Alchemy, etc)
6+
7+
### Arkive Usage
8+
9+
First make sure .env is configured correctly with your RPC endpoint. In this example we are connecting the `mainnet` with the Ankr public ETH endpoint.
10+
> MAINNET_RPC_URL=https://rpc.ankr.com/eth
11+
12+
All available tasks can been seen with
13+
> deno task
14+
15+
To start a new instance of the Arkive you can use `deno task` to run the `new` script with the following command
16+
> deno task new
17+
18+
To reset the database and resync the Arkive run `reset` task
19+
> deno task reset
20+
21+
### Using the GraphQL Explorer
22+
If Arkiver is running there should now be webpage avaiable at http://0.0.0.0:4000/graphql
23+
24+
In the left side you can use the no-code explorer to pick and chose which Entities and what fields of the Entities you would like to look at. Here is an example query for this Arkive. This fetches the latest Balance and BalanceHistory entities.
25+
```
26+
query MyQuery {
27+
Balance(sort: _ID_DESC) {
28+
token
29+
user
30+
balance
31+
}
32+
BalanceHistory(sort: _ID_DESC) {
33+
token
34+
block
35+
user
36+
balance
37+
}
38+
}
39+
```
40+
41+
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"tasks": {
3+
"start": "arkiver start ./ -c mongodb://localhost:27017",
4+
"new": "docker run --name mongo -d -p 27017:27017 mongodb/mongodb-community-server:latest && arkiver start ./ -c mongodb://localhost:27017",
5+
"resetdb": "docker stop mongo && docker rm mongo && docker run --name mongo -d -p 27017:27017 mongodb/mongodb-community-server:latest",
6+
"reset": "docker stop mongo && docker rm mongo && docker run --name mongo -d -p 27017:27017 mongodb/mongodb-community-server:latest && arkiver start ./ -c mongodb://localhost:27017",
7+
"newdb": "docker run --name mongo -d -p 27017:27017 mongodb/mongodb-community-server:latest",
8+
"stopdb": "docker stop mongo",
9+
"rmdb": "docker rm mongo",
10+
"startdb": "docker start mongo",
11+
"deploy": "arkiver deploy ./"
12+
}
13+
}

examples/erc20-balance-history/entities.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ export const Transfer = createEntity('Transfer', {
1616
export const Balance = createEntity('Balance', {
1717
token: String,
1818
user: String,
19-
balance: Number,
19+
balance: String,
2020
})
2121

2222
// Contains all balance changes for every user
2323
export const BalanceHistory = createEntity('BalanceHistory', {
2424
token: String,
2525
block: { type: Number, index: true },
2626
user: String,
27-
balance: Number,
27+
balance: String,
2828
})
2929

3030
export const Entities = [Balance, BalanceHistory, Transfer]

0 commit comments

Comments
 (0)