From a099345554c2dac7a1cf2a1e086ef43f6d7a81d1 Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Wed, 7 Jun 2023 14:45:53 +0000 Subject: [PATCH] build based on cc3d75a --- latest/api/index.html | 124 +++++++++++++++--------------- latest/bugs/index.html | 2 +- latest/build-a-binary/index.html | 2 +- latest/call-julia/index.html | 2 +- latest/calling-another/index.html | 2 +- latest/configuration/index.html | 4 +- latest/contributing/index.html | 2 +- latest/index.html | 2 +- latest/output/index.html | 2 +- latest/provided-binary/index.html | 2 +- latest/search/index.html | 2 +- latest/search_index.js | 2 +- 12 files changed, 74 insertions(+), 74 deletions(-) diff --git a/latest/api/index.html b/latest/api/index.html index 203009b..3a6bb41 100644 --- a/latest/api/index.html +++ b/latest/api/index.html @@ -19,7 +19,7 @@ julia> SemioticOpt.x(alg) 2-element Vector{Float64}: 2.5 - 2.5source
AllocationOpt.allocatablesubgraphsMethod
 allocatablesubgraphs(s::FlexTable, config::AbstractDict)

For the subgraphs s return a view of the subgraphs on which we can allocate.

julia> using AllocationOpt
+ 2.5
source
AllocationOpt.allocatablesubgraphsMethod
 allocatablesubgraphs(s::FlexTable, config::AbstractDict)

For the subgraphs s return a view of the subgraphs on which we can allocate.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> s = flextable([
             Dict("ipfsHash" => "Qma", "signalledTokens" => 10,),
@@ -38,7 +38,7 @@
      signalledTokens  ipfsHash
    ┌──────────────────────────
  1 │ 20               Qmb
- 2 │ 5                Qmc
source
AllocationOpt.allocate_actionMethod
allocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)

Create and push allocate actions to the action queue.

julia> using AllocationOpt
+ 2 │ 5                Qmc
source
AllocationOpt.allocate_actionMethod
allocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)

Create and push allocate actions to the action queue.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> a = flextable([
             Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa")
@@ -53,7 +53,7 @@
 julia> TheGraphData.client!(config["indexer_url"])
 julia> AllocationOpt.allocate_action(Val(:actionqueue), a, t, Dict())
 1-element Vector{Dict{String, Any}}:
- Dict("amount" => "2", "priority" => 0, "status" => AllocationOpt.queued, "source" => "AllocationOpt", "reason" => "Expected profit: 0", "type" => AllocationOpt.allocate, "deploymentID" => "Qmb")
source
AllocationOpt.allocate_actionMethod
allocate_action(::Val{:none}, a, t, config)

Do nothing.

julia> using AllocationOpt
+ Dict("amount" => "2", "priority" => 0, "status" => AllocationOpt.queued, "source" => "AllocationOpt", "reason" => "Expected profit: 0", "type" => AllocationOpt.allocate, "deploymentID" => "Qmb")
source
AllocationOpt.allocate_actionMethod
allocate_action(::Val{:none}, a, t, config)

Do nothing.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> a = flextable([
             Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa")
@@ -62,10 +62,10 @@
             Dict("amount" => "1", "profit" => "0", "ipfshash" => "Qma"),
             Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"),
         ])
-julia> AllocationOpt.allocate_action(Val(:none), a, t, Dict())
source
AllocationOpt.allocate_actionMethod
allocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)

Print the rules that allocates to new subgraphs.

```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa") ]) julia> t = flextable([ Dict("amount" => "1", "profit" => "0", "ipfshash" => "Qma"), Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"), ]) julia> AllocationOpt.allocate_action(Val(:rules), a, t, Dict()) graph indexer rules set Qmb decisionBasis always allocationAmount 2 1-element Vector{String}: "graph indexer rules set Qmb decisionBasis always allocationAmount 2"

source
AllocationOpt.aqueryMethod
aquery(id::AbstractString)

Return the components of a GraphQL query for active allocations of indexer id.

For use with the TheGraphData.jl package.

julia> using AllocationOpt
+julia> AllocationOpt.allocate_action(Val(:none), a, t, Dict())
source
AllocationOpt.allocate_actionMethod
allocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)

Print the rules that allocates to new subgraphs.

```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa") ]) julia> t = flextable([ Dict("amount" => "1", "profit" => "0", "ipfshash" => "Qma"), Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"), ]) julia> AllocationOpt.allocate_action(Val(:rules), a, t, Dict()) graph indexer rules set Qmb decisionBasis always allocationAmount 2 1-element Vector{String}: "graph indexer rules set Qmb decisionBasis always allocationAmount 2"

source
AllocationOpt.aqueryMethod
aquery(id::AbstractString)

Return the components of a GraphQL query for active allocations of indexer id.

For use with the TheGraphData.jl package.

julia> using AllocationOpt
 julia> id = "0xa"
 julia> value, args, fields = AllocationOpt.aquery(id)
-("allocations", Dict{String, Union{Dict{String, String}, String}}("where" => Dict("status" => "Active", "indexer" => "0xa")), ["allocatedTokens", "id", "subgraphDeployment{ipfsHash}"])

Extended Help

You can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl

source
AllocationOpt.availablestakeMethod
available(::Val{:indexer}, x)

The tokens available for the indexer to allocate in table x.

julia> using AllocationOpt
+("allocations", Dict{String, Union{Dict{String, String}, String}}("where" => Dict("status" => "Active", "indexer" => "0xa")), ["allocatedTokens", "id", "subgraphDeployment{ipfsHash}"])

Extended Help

You can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl

source
AllocationOpt.availablestakeMethod
available(::Val{:indexer}, x)

The tokens available for the indexer to allocate in table x.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> x = flextable([
     Dict(
@@ -75,16 +75,16 @@
     ),
 ])
 julia> AllocationOpt.availablestake(Val(:indexer), x)
-25.0
source
AllocationOpt.bestprofitpernzMethod
bestprofitpernz(ixs::AbstractVector{Integer}, profitmatrix::AbstractMatrix{Real})

Compute the best profit amongst the given ixs given profit matrix p

julia> using AllocationOpt
+25.0
source
AllocationOpt.bestprofitpernzMethod
bestprofitpernz(ixs::AbstractVector{Integer}, profitmatrix::AbstractMatrix{Real})

Compute the best profit amongst the given ixs given profit matrix p

julia> using AllocationOpt
 julia> ixs = Dict([1] => [1], [2] => [2])
 julia> profitmatrix = [[2.5 5.0]; [2.5 1.0]]
 julia> AllocationOpt.bestprofitpernz.(values(ixs), Ref(profitmatrix))
 2-element Vector{NamedTuple{(:profit, :index), Tuple{Float64, Int64}}}:
  (profit = 5.0, index = 1)
- (profit = 6.0, index = 2)
source
AllocationOpt.blockissuanceMethod
blockissuance(::Val{:network}, x)

The tokens issued per block.

```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "totalSupply" => 1, "networkGRTIssuance" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.blockissuance(Val(:network), n) 1

source
AllocationOpt.blocksperepochMethod
blocksperepoch(::Val{:network}, x)

The number of blocks in each epoch.

```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "totalSupply" => 1, "networkGRTIssuance" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.blocksperepoch(Val(:network), n) 28

source
AllocationOpt.closeipfsMethod
closeipfs(existingipfs, proposedipfs, frozenlist)

Get the list of the ipfs hashes of allocations to close.

julia> using AllocationOpt
+ (profit = 6.0, index = 2)
source
AllocationOpt.blockissuanceMethod
blockissuance(::Val{:network}, x)

The tokens issued per block.

```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "totalSupply" => 1, "networkGRTIssuance" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.blockissuance(Val(:network), n) 1

source
AllocationOpt.blocksperepochMethod
blocksperepoch(::Val{:network}, x)

The number of blocks in each epoch.

```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "totalSupply" => 1, "networkGRTIssuance" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.blocksperepoch(Val(:network), n) 28

source
AllocationOpt.closeipfsMethod
closeipfs(existingipfs, proposedipfs, frozenlist)

Get the list of the ipfs hashes of allocations to close.

julia> using AllocationOpt
 julia> AllocationOpt.closeipfs(["Qma"], ["Qmb"], String[])
 1-element Vector{String}:
- "Qma"
source
AllocationOpt.configuredefaults!Method
configuredefaults!(config::AbstractDict)

Set default values for the config dictionary if the value was not specified in the config file.

Config Specification

  • id::String: The ID of the indexer for whom we're optimising. No default value.
  • network_subgraph_endpoint::String: The network subgraph endpoint to query. By default, "https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet"
  • writedir::String: The directory to which to write the results of optimisation. If don't specify readdir, writedir also specifies the path to which to save the input data tables. By default, "."
  • readdir::Union{String, Nothing}: The directory from which to read saved data tables. This speeds up the process as we won't have to query the network subgraph for the relevant data. If you don't specify readdir, we will query your specified network_subgraph_endpoint for the data and write it to CSV files in writedir. This way, you can use your previous writedir as your readdir in future runs. By default, nothing
  • whitelist::Vector{String}: A list of subgraph IPFS hashes that you want to consider as candidates to which to allocate. If you leave this empty, we'll assume all subgraphs are in the whitelist. By default, String[]
  • blacklist::Vector{String}: A list of subgraph IPFS hashes that you do not want to consider allocating to. For example, this list could include broken subgraphs or subgraphs that you don't want to index. By default, String[]
  • frozenlist::Vector{String}: If you have open allocations that you don't want to change, add the corresponding subgraph IPFS hashes to this list. By default, String[]
  • pinnedlist::Vector{String}: If you have subgraphs that you absolutely want to be allocated to, even if only with a negligible amount of GRT, add it to this list. By default, String[]
  • allocation_lifetime::Integer: The number of epochs for which you expect the allocations the optimiser finds to be open. By default, 28
  • gas::Real: The estimated gas cost in GRT to open/close allocations. By default, 100
  • min_signal::Real: The minimum amount of signal in GRT that must be on a subgraph in order for you to consider allocating to it. By default, 1000
  • max_allocations::Integer: The maximum number of new allocations you'd like the optimiser to consider opening. By default, 10
  • num_reported_options::Integer: The number of proposed allocation strategies to report. For example, if you select 10 we'd report best 10 allocation strategies ranked by profit. By default, 1
  • verbose::Bool: If true, the optimiser will print details about what it is doing to stdout. By default, false
  • execution_mode::String: How the optimiser should execute the allocation strategies it finds. Options are "none", which won't do anything, "actionqueue", which will push actions to the action queue, and "rules", which will generate indexing rules. By default, "none"
  • indexer_url::Union{String, Nothing}: The URL of the indexer management server you want to execute the allocation strategies on. If you specify "actionqueue", you must also specify indexer_url. By default, nothing
  • opt_mode::String: We support two optimisation modes. One is "fast". This mode is fast, but may not find the optimal allocation. This mode is also used to the top num_reported_options allocation strategies. The other mode is "optimal". This mode is slower, but will find the optimal allocation. In general, we recommend exploring config options using "fast" mode first, and then using "optimal" mode to find the optimal allocation. By default, "fast"
julia> using AllocationOpt
+ "Qma"
source
AllocationOpt.configuredefaults!Method
configuredefaults!(config::AbstractDict)

Set default values for the config dictionary if the value was not specified in the config file.

Config Specification

  • id::String: The ID of the indexer for whom we're optimising. No default value.
  • network_subgraph_endpoint::String: The network subgraph endpoint to query. By default, "https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet"
  • writedir::String: The directory to which to write the results of optimisation. If don't specify readdir, writedir also specifies the path to which to save the input data tables. By default, "."
  • readdir::Union{String, Nothing}: The directory from which to read saved data tables. This speeds up the process as we won't have to query the network subgraph for the relevant data. If you don't specify readdir, we will query your specified network_subgraph_endpoint for the data and write it to CSV files in writedir. This way, you can use your previous writedir as your readdir in future runs. By default, nothing
  • whitelist::Vector{String}: A list of subgraph IPFS hashes that you want to consider as candidates to which to allocate. If you leave this empty, we'll assume all subgraphs are in the whitelist. By default, String[]
  • blacklist::Vector{String}: A list of subgraph IPFS hashes that you do not want to consider allocating to. For example, this list could include broken subgraphs or subgraphs that you don't want to index. By default, String[]
  • frozenlist::Vector{String}: If you have open allocations that you don't want to change, add the corresponding subgraph IPFS hashes to this list. By default, String[]
  • pinnedlist::Vector{String}: If you have subgraphs that you absolutely want to be allocated to, even if only with a negligible amount of GRT, add it to this list. By default, String[]
  • allocation_lifetime::Integer: The number of epochs for which you expect the allocations the optimiser finds to be open. By default, 28
  • gas::Real: The estimated gas cost in GRT to open/close allocations. By default, 100
  • min_signal::Real: The minimum amount of signal in GRT that must be on a subgraph in order for you to consider allocating to it. By default, 1000
  • max_allocations::Integer: The maximum number of new allocations you'd like the optimiser to consider opening. By default, 10
  • num_reported_options::Integer: The number of proposed allocation strategies to report. For example, if you select 10 we'd report best 10 allocation strategies ranked by profit. By default, 1
  • verbose::Bool: If true, the optimiser will print details about what it is doing to stdout. By default, false
  • execution_mode::String: How the optimiser should execute the allocation strategies it finds. Options are "none", which won't do anything, "actionqueue", which will push actions to the action queue, and "rules", which will generate indexing rules. By default, "none"
  • indexer_url::Union{String, Nothing}: The URL of the indexer management server you want to execute the allocation strategies on. If you specify "actionqueue", you must also specify indexer_url. By default, nothing
  • opt_mode::String: We support two optimisation modes. One is "fast". This mode is fast, but may not find the optimal strategy. This mode is also used to the top num_reported_options allocation strategies. The other mode is "optimal". This mode is slower, but it satisfy stronger optimality conditions. It will find strategies at least as good as "fast", but not guaranteed to be better. In general, we recommend exploring config options using "fast" mode first, and then using "optimal" mode to find the optimal allocation. By default, "optimal"
julia> using AllocationOpt
 julia> config = Dict{String, Any}("id" => "0xa")
 julia> config = AllocationOpt.configuredefaults!(config)
 Dict{String, Any} with 16 entries:
@@ -102,7 +102,7 @@
   "min_signal"                => 1000
   "network_subgraph_endpoint" => "https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet"
   "whitelist"                 => String[]
-  ⋮                           => ⋮
source
AllocationOpt.correcttypes!Method
correcttypes!(i::FlexTable, a::FlexTable, s::FlexTable, n::FlexTable)

Convert all tables to be in GRT.

julia> using AllocationOpt
+  ⋮                           => ⋮
source
AllocationOpt.correcttypes!Method
correcttypes!(i::FlexTable, a::FlexTable, s::FlexTable, n::FlexTable)

Convert all tables to be in GRT.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> i = flextable([
     Dict(
@@ -135,7 +135,7 @@
         "currentEpoch" => 1,
     )
 ])
-julia> i, a, s, n = AllocationOpt.correcttypes!(i, a, s, n)
source
AllocationOpt.correcttypes!Method
correcttypes!(::Val{:allocation}, a::FlexTable)

Convert the string currency fields in the allocation table to be in GRT.

julia> using AllocationOpt
+julia> i, a, s, n = AllocationOpt.correcttypes!(i, a, s, n)
source
AllocationOpt.correcttypes!Method
correcttypes!(::Val{:allocation}, a::FlexTable)

Convert the string currency fields in the allocation table to be in GRT.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> a = flextable([
     Dict(
@@ -147,7 +147,7 @@
 FlexTable with 2 columns and 1 row:
      subgraphDeployment.ipfsHash  allocatedTokens
    ┌─────────────────────────────────────────────
- 1 │ Qma                          1.0e-18
source
AllocationOpt.correcttypes!Method
correcttypes!(::Val{:indexer}, i::FlexTable)

Convert the string currency fields in the indexer table to be in GRT.

julia> using AllocationOpt
+ 1 │ Qma                          1.0e-18
source
AllocationOpt.correcttypes!Method
correcttypes!(::Val{:indexer}, i::FlexTable)

Convert the string currency fields in the indexer table to be in GRT.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> i = flextable([
     Dict(
@@ -161,7 +161,7 @@
 FlexTable with 4 columns and 1 row:
      stakedTokens  delegatedTokens  id   lockedTokens
    ┌─────────────────────────────────────────────────
- 1 │ 1.0e-18       0.0              0xa  0.0
source
AllocationOpt.correcttypes!Method
correcttypes!(::Val{:network}, n::FlexTable)

Convert the string currency fields in the network table to be in GRT.

julia> using AllocationOpt
+ 1 │ 1.0e-18       0.0              0xa  0.0
source
AllocationOpt.correcttypes!Method
correcttypes!(::Val{:network}, n::FlexTable)

Convert the string currency fields in the network table to be in GRT.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> n = flextable([
     Dict(
@@ -177,7 +177,7 @@
 FlexTable with 6 columns and 1 row:
      totalTokensSignalled  currentEpoch  totalSupply  id  networkGRTIssuance  epochLength
    ┌─────────────────────────────────────────────────────────────────────────────────────
- 1 │ 2.0e-18               1             1.0e-18      1   1.0e-18             28
source
AllocationOpt.correcttypes!Method
correcttypes!(::Val{:subgraph}, s::FlexTable)

Convert the string currency fields in the subgraph table to be in GRT.

julia> using AllocationOpt
+ 1 │ 2.0e-18               1             1.0e-18      1   1.0e-18             28
source
AllocationOpt.correcttypes!Method
correcttypes!(::Val{:subgraph}, s::FlexTable)

Convert the string currency fields in the subgraph table to be in GRT.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> s = flextable([
     Dict(
@@ -191,7 +191,7 @@
 FlexTable with 4 columns and 1 row:
      deniedAt  stakedTokens  signalledTokens  ipfsHash
    ┌──────────────────────────────────────────────────
- 1 │ 0         1.0e-18       0.0              Qma
source
AllocationOpt.currentepochMethod
currentepoch(::Val{:network}, x)

The current epoch.

```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "totalSupply" => 1, "networkGRTIssuance" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.currentepoch(Val(:network), n) 1

source
AllocationOpt.delegationMethod
delegation(::Val{:indexer}, x)

The tokens delegated to the indexer in table x.

julia> using AllocationOpt
+ 1 │ 0         1.0e-18       0.0              Qma
source
AllocationOpt.currentepochMethod
currentepoch(::Val{:network}, x)

The current epoch.

```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "totalSupply" => 1, "networkGRTIssuance" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.currentepoch(Val(:network), n) 1

source
AllocationOpt.delegationMethod
delegation(::Val{:indexer}, x)

The tokens delegated to the indexer in table x.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> x = flextable([
     Dict(
@@ -199,7 +199,7 @@
     ),
 ])
 julia> AllocationOpt.delegation(Val(:indexer), x)
-10
source
AllocationOpt.deniedatMethod
deniedat(::Val{:subgraph}, x)

If this value is non-zero, the subgraph doesn't receive indexing rewards.

julia> using AllocationOpt
+10
source
AllocationOpt.deniedatMethod
deniedat(::Val{:subgraph}, x)

If this value is non-zero, the subgraph doesn't receive indexing rewards.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> x = flextable([
     Dict("deniedAt" => 10,),
@@ -208,7 +208,7 @@
 julia> AllocationOpt.deniedat(Val(:subgraph), x)
 2-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:
  10
-  0
source
AllocationOpt.deniedzeroixsMethod
deniedzeroixs(s::FlexTable)

Find the indices of subgraphs that have "deniedAt" equal to zero.

julia> using AllocationOpt
+  0
source
AllocationOpt.deniedzeroixsMethod
deniedzeroixs(s::FlexTable)

Find the indices of subgraphs that have "deniedAt" equal to zero.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> s = flextable([
            Dict("ipfsHash" => "Qma", "signalledTokens" => 5.0, "deniedAt" => 0),
@@ -218,7 +218,7 @@
 julia> AllocationOpt.deniedzeroixs(s)
 2-element Vector{Int64}:
  1
- 3
source
AllocationOpt.dualMethod
dual(Ω, ψ, σ)

Analytic solution of the dual form of the optimisation problem given signals ψ, allocation vector Ω, and stake σ.

Note

You should probably not use this function directly. Use optimizeanalytic instead.

source
AllocationOpt.executeMethod
execute(
+ 3
source
AllocationOpt.dualMethod
dual(Ω, ψ, σ)

Analytic solution of the dual form of the optimisation problem given signals ψ, allocation vector Ω, and stake σ.

Note

You should probably not use this function directly. Use optimizeanalytic instead.

source
AllocationOpt.executeMethod
execute(
     a::FlexTable,
     ix::Integer,
     s::FlexTable,
@@ -238,11 +238,11 @@
         ])
 julia> config = Dict("execution_mode" => "none")
 julia> ix = 1
-julia> AllocationOpt.execute(a, ix, s, xs, ps, config)
source
AllocationOpt.formatconfig!Method
formatconfig!(config::AbstractDict)

Given a config, reformat values that need to be standardised.

julia> using AllocationOpt
+julia> AllocationOpt.execute(a, ix, s, xs, ps, config)
source
AllocationOpt.formatconfig!Method
formatconfig!(config::AbstractDict)

Given a config, reformat values that need to be standardised.

julia> using AllocationOpt
 julia> config = Dict("id" => "0xA")
 julia> AllocationOpt.formatconfig!(config)
 Dict{String, String} with 1 entry:
-  "id" => "0xa"
source
AllocationOpt.frozenMethod
frozen(a::FlexTable, config::AbstractDict)

The frozen stake of the indexer with allocations a.

julia> using AllocationOpt
+  "id" => "0xa"
source
AllocationOpt.frozenMethod
frozen(a::FlexTable, config::AbstractDict)

The frozen stake of the indexer with allocations a.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> a = flextable([
             Dict("subgraphDeployment.ipfsHash" => "Qma", "allocatedTokens" => 5),
@@ -250,13 +250,13 @@
        ])
 julia> config = Dict("frozenlist" => ["Qma", "Qmb"])
 julia> AllocationOpt.frozen(a, config)
-15.0
source
AllocationOpt.groupuniqueMethod
groupunique(x::AbstractVector)

Find the indices of each unique value in x

julia> using AllocationOpt
+15.0
source
AllocationOpt.groupuniqueMethod
groupunique(x::AbstractVector)

Find the indices of each unique value in x

julia> using AllocationOpt
 julia> x = [1, 2, 1, 3, 2, 3]
 julia> AllocationOpt.groupunique(x)
 Dict{Vector{Int64}, Vector{Int64}} with 3 entries:
   [3] => [4, 6]
   [1] => [1, 3]
-  [2] => [2, 5]
source
AllocationOpt.idMethod
id(::Val{:allocation}, x)

Get the allocation id for each allocation in x.

julia> using AllocationOpt
+  [2] => [2, 5]
source
AllocationOpt.idMethod
id(::Val{:allocation}, x)

Get the allocation id for each allocation in x.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> x = flextable([
     Dict(
@@ -265,21 +265,21 @@
 ])
 julia> AllocationOpt.id(Val(:allocation), x)
 1-element view(lazystack(::Vector{Vector{String}}), 1, :) with eltype String:
- "0x1"
source
AllocationOpt.indexingrewardMethod
indexingreward(x::Real, Ω::Real, ψ::Real, Φ::Real, Ψ::Real)

The indexing rewards for the allocation scalar x given signals ψ, the existing allocation on subgraphs Ω, token issuance Φ, and total signal Ψ.

julia> using AllocationOpt
+ "0x1"
source
AllocationOpt.indexingrewardMethod
indexingreward(x::Real, Ω::Real, ψ::Real, Φ::Real, Ψ::Real)

The indexing rewards for the allocation scalar x given signals ψ, the existing allocation on subgraphs Ω, token issuance Φ, and total signal Ψ.

julia> using AllocationOpt
 julia> ψ = 0.0
 julia> Ω = 1.0
 julia> Φ = 1.0
 julia> Ψ = 2.0
 julia> x = 1.0
 julia> AllocationOpt.indexingreward(x, Ω, ψ, Φ, Ψ)
-0.0
source
AllocationOpt.indexingrewardMethod
indexingreward(
+0.0
source
AllocationOpt.indexingrewardMethod
indexingreward(
     ixs::AbstractArray{Integer},
     x::AbstractVector{Real},
     Ω::AbstractVector{Real},
     ψ::AbstractVector{Real},
     Φ::Real,
     Ψ::Real
-)

The indexing rewards for the allocation vector x given signals ψ, the existing allocations on subgraphs Ω, token issuance Φ, and total signal Ψ. Here ixs is a vector of indices Ω, and ψ. x will be filtered by SemioticOpt, so we don't do this here.

julia julia> using AllocationOpt julia> ixs = Int32[2] julia> ψ = [0.0, 1.0] julia> Ω = [1.0, 1.0] julia> Φ = 1.0 julia> Ψ = 2.0 julia> x = [0.0, 1.0] julia> AllocationOpt.indexingreward(ixs, x, Ω, ψ, Φ, Ψ) 0.25`

source
AllocationOpt.indexingrewardMethod
indexingreward(
+)

The indexing rewards for the allocation vector x given signals ψ, the existing allocations on subgraphs Ω, token issuance Φ, and total signal Ψ. Here ixs is a vector of indices Ω, and ψ. x will be filtered by SemioticOpt, so we don't do this here.

julia julia> using AllocationOpt julia> ixs = Int32[2] julia> ψ = [0.0, 1.0] julia> Ω = [1.0, 1.0] julia> Φ = 1.0 julia> Ψ = 2.0 julia> x = [0.0, 1.0] julia> AllocationOpt.indexingreward(ixs, x, Ω, ψ, Φ, Ψ) 0.25`

source
AllocationOpt.indexingrewardMethod
indexingreward(
     x::AbstractVector{Real},
     Ω::AbstractVector{Real},
     ψ::AbstractVector{Real},
@@ -292,7 +292,7 @@
 julia> Ψ = 2.0
 julia> x = [0.0, 1.0]
 julia> AllocationOpt.indexingreward(x, Ω, ψ, Φ, Ψ)
-0.25
source
AllocationOpt.ipfshashMethod
ipfshash(::Val{:allocation}, x)

Get the ipfs hash of x when x is part of the allocation table.

julia> using AllocationOpt
+0.25
source
AllocationOpt.ipfshashMethod
ipfshash(::Val{:allocation}, x)

Get the ipfs hash of x when x is part of the allocation table.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> x = flextable([
     Dict(
@@ -301,7 +301,7 @@
 ])
 julia> AllocationOpt.ipfshash(Val(:allocation), x)
 1-element view(lazystack(::Vector{Vector{String}}), 1, :) with eltype String:
- "Qma"
source
AllocationOpt.ipfshashMethod
ipfshash(::Val{:subgraph}, x)

Get the ipfs hash of x when x is part of the allocation table.

julia> using AllocationOpt
+ "Qma"
source
AllocationOpt.ipfshashMethod
ipfshash(::Val{:subgraph}, x)

Get the ipfs hash of x when x is part of the allocation table.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> x = flextable([
     Dict(
@@ -310,14 +310,14 @@
 ])
 julia> AllocationOpt.ipfshash(Val(:subgraph), x)
 1-element view(lazystack(::Vector{Vector{String}}), 1, :) with eltype String:
- "Qma"
source
AllocationOpt.iqueryMethod
iquery(id::AbstractString)

Return the components of a GraphQL query for the stake of indexer id.

For use with the TheGraphData.jl package.

julia> using AllocationOpt
+ "Qma"
source
AllocationOpt.iqueryMethod
iquery(id::AbstractString)

Return the components of a GraphQL query for the stake of indexer id.

For use with the TheGraphData.jl package.

julia> using AllocationOpt
 julia> id = "0xa"
 julia> value, args, fields = AllocationOpt.iquery(id)
-("indexer", Dict{String, Union{Int64, Dict{String, String}, String}}("id" => "0xa"), ["delegatedTokens", "stakedTokens", "lockedTokens"])

Extended Help

You can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl

source
AllocationOpt.lipschitzconstantMethod
lipschitzconstant(ψ, Ω)

The Lipschitz constant of the indexing reward function given signals ψ and allocations Ω.

julia> using AllocationOpt
+("indexer", Dict{String, Union{Int64, Dict{String, String}, String}}("id" => "0xa"), ["delegatedTokens", "stakedTokens", "lockedTokens"])

Extended Help

You can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl

source
AllocationOpt.lipschitzconstantMethod
lipschitzconstant(ψ, Ω)

The Lipschitz constant of the indexing reward function given signals ψ and allocations Ω.

julia> using AllocationOpt
 julia> ψ = [0.0, 1.0]
 julia> Ω = [1.0, 1.0]
 julia> AllocationOpt.lipschitzconstant(ψ, Ω)
-2.0
source
AllocationOpt.lockedMethod
locked(::Val{:indexer}, x)

The locked tokens of the indexer in table x.

julia> using AllocationOpt
+2.0
source
AllocationOpt.lockedMethod
locked(::Val{:indexer}, x)

The locked tokens of the indexer in table x.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> x = flextable([
     Dict(
@@ -325,7 +325,7 @@
     ),
 ])
 julia> AllocationOpt.locked(Val(:indexer), x)
-10
source
AllocationOpt.newtokenissuanceMethod
newtokenissuance(n::FlexTable, config::Dict)

How many new tokens are issued over the allocation lifetime given network parameters n.

julia> using AllocationOpt
+10
source
AllocationOpt.newtokenissuanceMethod
newtokenissuance(n::FlexTable, config::Dict)

How many new tokens are issued over the allocation lifetime given network parameters n.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> n = flextable([
             Dict(
@@ -339,13 +339,13 @@
         ])
 julia> config = Dict("allocation_lifetime" => 1)
 julia> AllocationOpt.newtokenissuance(n, config)
-1.0
source
AllocationOpt.nonzeroMethod
nonzero(v::AbstractVector)

Get the non-zero elements of vector v.

julia> using AllocationOpt
+1.0
source
AllocationOpt.nonzeroMethod
nonzero(v::AbstractVector)

Get the non-zero elements of vector v.

julia> using AllocationOpt
 julia> v = [0.0, 1.0]
 julia> AllocationOpt.nonzero(v)
 1-element view(::Vector{Float64}, [2]) with eltype Float64:
- 1.0
source
AllocationOpt.nqueryMethod
nquery()

Return the components of a GraphQL query for network parameters.

For use with the TheGraphData.jl package.

julia> using AllocationOpt
+ 1.0
source
AllocationOpt.nqueryMethod
nquery()

Return the components of a GraphQL query for network parameters.

For use with the TheGraphData.jl package.

julia> using AllocationOpt
 julia> value, args, fields = AllocationOpt.nquery()
-("graphNetwork", Dict("id" => 1), ["id", "totalSupply", "networkGRTIssuance", "epochLength", "totalTokensSignalled", "currentEpoch"])

Extended Help

You can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl

source
AllocationOpt.optimizeMethod
optimize(Ω, ψ, σ, K, Φ, Ψ, g, rixs, config::AbstractDict)

Find the optimal solution vector given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas in grt g. rixs are the indices of subgraphs that are eligible to receive indexing rewards.

Dispatches to optimize with the opt_mode key.

If opt_mode is fast, then run projected gradient descent with GSSP and Halpern. If opt_mode is optimal, then run Pairwise Greedy Optimisation.

julia> using AllocationOpt
+("graphNetwork", Dict("id" => 1), ["id", "totalSupply", "networkGRTIssuance", "epochLength", "totalTokensSignalled", "currentEpoch"])

Extended Help

You can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl

source
AllocationOpt.optimizeMethod
optimize(Ω, ψ, σ, K, Φ, Ψ, g, rixs, config::AbstractDict)

Find the optimal solution vector given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas in grt g. rixs are the indices of subgraphs that are eligible to receive indexing rewards.

Dispatches to optimize with the opt_mode key.

If opt_mode is fast, then run projected gradient descent with GSSP and Halpern. If opt_mode is optimal, then run Pairwise Greedy Optimisation.

julia> using AllocationOpt
 julia> config = Dict("opt_mode" => "fast")
 julia> rixs = [1, 2]
 julia> Ω = [1.0, 1.0]
@@ -356,7 +356,7 @@
 julia> Ψ = 20.0
 julia> g = 0.01
 julia> xs, nonzeros, profits = AllocationOpt.optimize(Ω, ψ, σ, K, Φ, Ψ, g, rixs, config)
-([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])
source
AllocationOpt.optimizeMethod
optimize(::Val{:fast}, Ω, ψ, σ, K, Φ, Ψ, g, rixs)

Find the optimal vectors for k ∈ [1,K] given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas in grt g. rixs are the indices of subgraphs that are eligible to receive indexing rewards.

julia> using AllocationOpt
+([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])
source
AllocationOpt.optimizeMethod
optimize(::Val{:fast}, Ω, ψ, σ, K, Φ, Ψ, g, rixs)

Find the optimal vectors for k ∈ [1,K] given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas in grt g. rixs are the indices of subgraphs that are eligible to receive indexing rewards.

julia> using AllocationOpt
 julia> rixs = [1, 2]
 julia> Ω = [1.0, 1.0]
 julia> ψ = [10.0, 10.0]
@@ -366,7 +366,7 @@
 julia> Ψ = 20.0
 julia> g = 0.01
 julia> xs, nonzeros, profits = AllocationOpt.optimize(Val(:fast), Ω, ψ, σ, K, Φ, Ψ, g, rixs)
-([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])
source
AllocationOpt.optimizeMethod
optimize(::Val{:optimal}, Ω, ψ, σ, K, Φ, Ψ, g, rixs)

Find the optimal solution vector given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas in grt g. rixs are the indices of subgraphs that are eligible to receive indexing rewards.

Example

julia> using AllocationOpt
+([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])
source
AllocationOpt.optimizeMethod
optimize(::Val{:optimal}, Ω, ψ, σ, K, Φ, Ψ, g, rixs)

Find the optimal solution vector given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas in grt g. rixs are the indices of subgraphs that are eligible to receive indexing rewards.

Example

julia> using AllocationOpt
 julia> rixs = [1, 2]
 julia> Ω = [1.0, 1.0]
 julia> ψ = [10.0, 10.0]
@@ -378,14 +378,14 @@
 julia> xs, nonzeros, profits = AllocationOpt.optimize(
            Val(:optimal), Ω, ψ, σ, K, Φ, Ψ, g, rixs
        )
-([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])
source
AllocationOpt.optimizeanalyticMethod
optimizeanalytic(Ω, ψ, σ)

Optimise analytically over existing allocation vector Ω, signals ψ, and stake σ.

julia> using AllocationOpt
+([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])
source
AllocationOpt.optimizeanalyticMethod
optimizeanalytic(Ω, ψ, σ)

Optimise analytically over existing allocation vector Ω, signals ψ, and stake σ.

julia> using AllocationOpt
 julia> Ω = [1.0, 7.0]
 julia> ψ = [10.0, 5.0]
 julia> σ = 5.0
 julia> AllocationOpt.optimizeanalytic(Ω, ψ, σ)
 2-element Vector{Float64}:
  3.5283092056122474
- 1.4716907943877526
source
AllocationOpt.optimizekMethod
optimizek(::Val{:fast}, x₀, Ω, ψ, σ, k, Φ, Ψ)

Find the optimal k sparse vector given initial value x₀, allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, and total signal Ψ.

julia> using AllocationOpt
+ 1.4716907943877526
source
AllocationOpt.optimizekMethod
optimizek(::Val{:fast}, x₀, Ω, ψ, σ, k, Φ, Ψ)

Find the optimal k sparse vector given initial value x₀, allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, and total signal Ψ.

julia> using AllocationOpt
 julia> x₀ = [2.5, 2.5]
 julia> Ω = [1.0, 1.0]
 julia> ψ = [10.0, 10.0]
@@ -396,7 +396,7 @@
 julia> AllocationOpt.optimizek(Val(:fast), x₀, Ω, ψ, σ, k, Φ, Ψ)
 2-element Vector{Float64}:
  5.0
- 0.0
source
AllocationOpt.optimizekMethod
optimizek(::Val{:optimal}, x₀, Ω, ψ, σ, k, Φ, Ψ, g)

Find the optimal k sparse vector given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas g.

Example

julia> using AllocationOpt
+ 0.0
source
AllocationOpt.optimizekMethod
optimizek(::Val{:optimal}, x₀, Ω, ψ, σ, k, Φ, Ψ, g)

Find the optimal k sparse vector given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas g.

Example

julia> using AllocationOpt
 julia> Ω = [1.0, 1.0]
 julia> ψ = [10.0, 10.0]
 julia> σ = 5.0
@@ -408,7 +408,7 @@
 julia> x = AllocationOpt.optimizek(Val(:optimal), x₀, Ω, ψ, σ, k, Φ, Ψ, g)
 2-element Vector{Float64}:
  5.0
- 0.0
source
AllocationOpt.pinnedMethod
pinned(config::AbstractDict)

The pinned vector of the indexer.

julia> using AllocationOpt
+ 0.0
source
AllocationOpt.pinnedMethod
pinned(config::AbstractDict)

The pinned vector of the indexer.

julia> using AllocationOpt
 julia> s = flextable([
     Dict("ipfsHash" => "Qma", "signalledTokens" => 5.0),
     Dict("ipfsHash" => "Qmb", "signalledTokens" => 10.0),
@@ -419,11 +419,11 @@
 3-element Vector{Float64}:
  0.1
  0.1
- 0.0
source
AllocationOpt.primalMethod
primal(Ω, ψ, ν)

Analytic solution of the primal form of the optimisation problem given signals ψ, allocations Ω, and a dual solution vector ν.

Note

You should probably not use this function directly. Use optimizeanalytic instead.

source
AllocationOpt.profitMethod
profit(r::Real, g::Real)

Compute the profit for one allocation with reward r and gas cost g.

julia> using AllocationOpt
+ 0.0
source
AllocationOpt.primalMethod
primal(Ω, ψ, ν)

Analytic solution of the primal form of the optimisation problem given signals ψ, allocations Ω, and a dual solution vector ν.

Note

You should probably not use this function directly. Use optimizeanalytic instead.

source
AllocationOpt.profitMethod
profit(r::Real, g::Real)

Compute the profit for one allocation with reward r and gas cost g.

julia> using AllocationOpt
 julia> r = 10
 julia> g = 1
 julia> AllocationOpt.profit(r, g)
-9
source
AllocationOpt.readMethod
read(config::AbstractDict)

Given a config, read the data in as flextables.

If you have specified a "readdir" in the config, this will read from CSV files in that directory. Otherwise, this will query the specified "network_subgraph_endpoint"

julia> using AllocationOpt
+9
source
AllocationOpt.readMethod
read(config::AbstractDict)

Given a config, read the data in as flextables.

If you have specified a "readdir" in the config, this will read from CSV files in that directory. Otherwise, this will query the specified "network_subgraph_endpoint"

julia> using AllocationOpt
 julia> config = Dict("verbose" => false, "readdir" => "mydatadir")
 julia> i, a, s, n = AllocationOpt.read(config)  # Read data from CSVs
julia> using AllocationOpt
 julia> config = Dict(
@@ -431,13 +431,13 @@
     "network_subgraph_endpoint" => "https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet",
     "readdir" => nothing,
 )
-julia> i, a, s, n = AllocationOpt.read(config)  # Query GQL endpoint
source
AllocationOpt.readMethod
read(f::AbstractString, config::AbstractDict)

Read the CSV files from f and return the tables from those files.

julia> using AllocationOpt
-julia> i, a, s, n = AllocationOpt.read("myreaddir", Dict("verbose" => true))
source
AllocationOpt.readMethod
read(::Nothing, config::AbstractDict)

Query the required data from the provided endpoint in the config.

julia> using AllocationOpt
+julia> i, a, s, n = AllocationOpt.read(config)  # Query GQL endpoint
source
AllocationOpt.readMethod
read(f::AbstractString, config::AbstractDict)

Read the CSV files from f and return the tables from those files.

julia> using AllocationOpt
+julia> i, a, s, n = AllocationOpt.read("myreaddir", Dict("verbose" => true))
source
AllocationOpt.readMethod
read(::Nothing, config::AbstractDict)

Query the required data from the provided endpoint in the config.

julia> using AllocationOpt
 julia> config = Dict(
             "verbose" => true,
             "network_subgraph_endpoint" => "https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet",
         )
-julia> i, a, s, n = AllocationOpt.read(nothing, config)
source
AllocationOpt.readconfigMethod
readconfig(p::AbstractString)

Read the config file from path p. The config file must be specifed as a TOML.

See configuredefaults! to see which fields you should specify in the config.

julia> using AllocationOpt
+julia> i, a, s, n = AllocationOpt.read(nothing, config)
source
AllocationOpt.readconfigMethod
readconfig(p::AbstractString)

Read the config file from path p. The config file must be specifed as a TOML.

See configuredefaults! to see which fields you should specify in the config.

julia> using AllocationOpt
 julia> path = "myconfig.toml"
 julia> config = AllocationOpt.readconfig(path)
 Dict{String, Any} with 13 entries:
@@ -453,7 +453,7 @@
   "min_signal"           => 1000
   "whitelist"            => Union{}[]
   "max_allocations"      => 5
-  "frozenlist"           => Union{}[]
source
AllocationOpt.reallocate_actionMethod
reallocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)

Create and push reallocate actions to the action queue.

julia> using AllocationOpt
+  "frozenlist"           => Union{}[]
source
AllocationOpt.reallocate_actionMethod
reallocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)

Create and push reallocate actions to the action queue.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> a = flextable([
             Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa")
@@ -466,7 +466,7 @@
 julia> TheGraphData.client!(config["indexer_url"])
 julia> AllocationOpt.reallocate_action(Val(:actionqueue), a, t, config)
 1-element Vector{Dict{String, Any}}:
- Dict("amount" => "1", "priority" => 0, "status" => AllocationOpt.queued, "allocationID" => "0xa", "source" => "AllocationOpt", "reason" => "Expected profit: 0", "type" => AllocationOpt.reallocate, "deploymentID" => "Qma")
source
AllocationOpt.reallocate_actionMethod
reallocate_action(::Val{:none}, a, t, config)

Do nothing.

```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa") ]) julia> t = flextable([ Dict("amount" => "1", "profit" => "0", "ipfshash" => "Qma"), Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"), ]) julia> AllocationOpt.reallocate_action(Val(:none), a, t, Dict())

source
AllocationOpt.reallocate_actionMethod
reallocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)

Print a rule that reallocates the old allocation with a new allocation amount

julia> using AllocationOpt
+ Dict("amount" => "1", "priority" => 0, "status" => AllocationOpt.queued, "allocationID" => "0xa", "source" => "AllocationOpt", "reason" => "Expected profit: 0", "type" => AllocationOpt.reallocate, "deploymentID" => "Qma")
source
AllocationOpt.reallocate_actionMethod
reallocate_action(::Val{:none}, a, t, config)

Do nothing.

```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa") ]) julia> t = flextable([ Dict("amount" => "1", "profit" => "0", "ipfshash" => "Qma"), Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"), ]) julia> AllocationOpt.reallocate_action(Val(:none), a, t, Dict())

source
AllocationOpt.reallocate_actionMethod
reallocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)

Print a rule that reallocates the old allocation with a new allocation amount

julia> using AllocationOpt
 julia> using TheGraphData
 julia> a = flextable([
             Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa")
@@ -479,7 +479,7 @@
 graph indexer rules stop Qma
 Check allocation status being closed before submitting: graph indexer rules set Qma decisionBasis always allocationAmount 1
 1-element Vector{String}:
- "graph indexer rules stop Qm" ⋯ 122 bytes ⋯ "asis always allocationAmount 1"
source
AllocationOpt.reportingtableMethod
reportingtable(
+ "graph indexer rules stop Qm" ⋯ 122 bytes ⋯ "asis always allocationAmount 1"
source
AllocationOpt.reportingtableMethod
reportingtable(
     s::FlexTable, xs::AbstractMatrix{Real}, ps::AbstractMatrix{Real}, i::Integer
 )

Construct a table for the strategy mapping the ipfshash, allocation amount, and profit

julia> using AllocationOpt
 julia> s = flextable([
@@ -494,10 +494,10 @@
      ipfshash  amount  profit
    ┌─────────────────────────
  1 │ Qma       2.5     3.0
- 2 │ Qmb       2.5     3.0
source
AllocationOpt.savenamesMethod
savenames(p::AbstractString)

Return a generator of the generic names of the CSV files containing the data with the path specified by p.

julia> using AllocationOpt
+ 2 │ Qmb       2.5     3.0
source
AllocationOpt.savenamesMethod
savenames(p::AbstractString)

Return a generator of the generic names of the CSV files containing the data with the path specified by p.

julia> using AllocationOpt
 julia> path = "mypath"
 julia> paths = AllocationOpt.savenames(path)
-Base.Generator{NTuple{4, String}, AllocationOpt.var"#1#2"{String}}(AllocationOpt.var"#1#2"{String}("mypath"), ("indexer.csv", "allocation.csv", "subgraph.csv", "network.csv"))
source
AllocationOpt.signalMethod
signal(::Val{:network}, x)

The total signal in the network

```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "totalSupply" => 1, "networkGRTIssuance" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.signal(Val(:network), n) 2

source
AllocationOpt.signalMethod
signal(::Val{:subgraph}, x)

The tokens signalled on the subgraphs in table x.

julia> using AllocationOpt
+Base.Generator{NTuple{4, String}, AllocationOpt.var"#1#2"{String}}(AllocationOpt.var"#1#2"{String}("mypath"), ("indexer.csv", "allocation.csv", "subgraph.csv", "network.csv"))
source
AllocationOpt.signalMethod
signal(::Val{:network}, x)

The total signal in the network

```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "totalSupply" => 1, "networkGRTIssuance" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.signal(Val(:network), n) 2

source
AllocationOpt.signalMethod
signal(::Val{:subgraph}, x)

The tokens signalled on the subgraphs in table x.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> x = flextable([
     Dict("signalledTokens" => 10,),
@@ -506,7 +506,7 @@
 julia> AllocationOpt.signal(Val(:subgraph), x)
 2-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:
  10
-  5
source
AllocationOpt.sortprofits!Method
sortprofits!(NamedTuple{Tuple{Float64, Int64}})

Sort the nonzero best profits from highest to lowest

julia> using AllocationOpt
+  5
source
AllocationOpt.sortprofits!Method
sortprofits!(NamedTuple{Tuple{Float64, Int64}})

Sort the nonzero best profits from highest to lowest

julia> using AllocationOpt
 julia> popts = [
         (; :profit => 5.0, :index => 2),
         (; :profit => 6.0, :index => 1)
@@ -514,9 +514,9 @@
 julia> popts = AllocationOpt.sortprofits!(popts)
 2-element Vector{NamedTuple{(:profit, :index), Tuple{Float64, Int64}}}:
  (profit = 6.0, index = 1)
- (profit = 5.0, index = 2)
source
AllocationOpt.squeryMethod
squery()

Return the components of a GraphQL query for subgraphs.

For use with the TheGraphData.jl package.

julia> using AllocationOpt
+ (profit = 5.0, index = 2)
source
AllocationOpt.squeryMethod
squery()

Return the components of a GraphQL query for subgraphs.

For use with the TheGraphData.jl package.

julia> using AllocationOpt
 julia> value, args, fields = AllocationOpt.squery()
-("subgraphDeployments", Dict{String, Union{Dict{String, String}, String}}(), ["ipfsHash", "signalledTokens", "stakedTokens"])

Extended Help

You can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl

source
AllocationOpt.stakeMethod
stake(::Val{:allocation}, x)

Get the allocated tokens for each allocation in x.

julia> using AllocationOpt
+("subgraphDeployments", Dict{String, Union{Dict{String, String}, String}}(), ["ipfsHash", "signalledTokens", "stakedTokens"])

Extended Help

You can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl

source
AllocationOpt.stakeMethod
stake(::Val{:allocation}, x)

Get the allocated tokens for each allocation in x.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> x = flextable([
     Dict(
@@ -525,7 +525,7 @@
 ])
 julia> AllocationOpt.stake(Val(:allocation), x)
 1-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:
- 1
source
AllocationOpt.stakeMethod
stake(::Val{:indexer}, x)

The tokens staked by the indexer in table x.

julia> using AllocationOpt
+ 1
source
AllocationOpt.stakeMethod
stake(::Val{:indexer}, x)

The tokens staked by the indexer in table x.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> x = flextable([
     Dict(
@@ -533,7 +533,7 @@
     ),
 ])
 julia> AllocationOpt.stake(Val(:indexer), x)
-10
source
AllocationOpt.stakeMethod
stake(::Val{:subgraph}, x)

The tokens staked on the subgraphs in table x.

julia> using AllocationOpt
+10
source
AllocationOpt.stakeMethod
stake(::Val{:subgraph}, x)

The tokens staked on the subgraphs in table x.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> x = flextable([
     Dict("stakedTokens" => 10,),
@@ -542,7 +542,7 @@
 julia> AllocationOpt.stake(Val(:subgraph), x)
 2-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:
  10
-  5
source
AllocationOpt.strategydictMethod
strategydict(
+  5
source
AllocationOpt.strategydictMethod
strategydict(
     p::NamedTuple,
     xs::AbstractMatrix{Real},
     nonzeros::AbstractVector{Integer},
@@ -564,7 +564,7 @@
 julia> AllocationOpt.strategydict.(popts, Ref(xs), Ref(nonzeros), Ref(fs), Ref(profits))
 2-element Vector{Dict{String, Any}}:
  Dict("num_allocations" => 2, "profit" => 6.0, "allocations" => Dict{String, Any}[Dict("allocationAmount" => "2.5", "profit" => 3.0, "deploymentID" => "Qma"), Dict("allocationAmount" => "2.5", "profit" => 3.0, "deploymentID" => "Qmb")])
- Dict("num_allocations" => 1, "profit" => 5.0, "allocations" => Dict{String, Any}[Dict("allocationAmount" => "5", "profit" => 5.0, "deploymentID" => "Qma")])
source
AllocationOpt.subtractindexer!Method
subtractindexer!(a::FlexTable, s::FlexTable)

Subtract the indexer's allocated tokens from the total allocated tokens on each subgraph.

julia> using AllocationOpt
+ Dict("num_allocations" => 1, "profit" => 5.0, "allocations" => Dict{String, Any}[Dict("allocationAmount" => "5", "profit" => 5.0, "deploymentID" => "Qma")])
source
AllocationOpt.subtractindexer!Method
subtractindexer!(a::FlexTable, s::FlexTable)

Subtract the indexer's allocated tokens from the total allocated tokens on each subgraph.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> s = flextable([
             Dict("ipfsHash" => "Qmb", "stakedTokens" => 20),
@@ -576,9 +576,9 @@
             Dict("subgraphDeployment.ipfsHash" => "Qmb", "allocatedTokens" => 10, "id" => "0xb"),
         ])
 julia> a, s = AllocationOpt.subtractindexer!(a, s)
-(NamedTuple[(var"subgraphDeployment.ipfsHash" = "Qma", allocatedTokens = 5, id = "0xa"), (var"subgraphDeployment.ipfsHash" = "Qmb", allocatedTokens = 10, id = "0xb")], NamedTuple[(stakedTokens = 5.0, ipfsHash = "Qma"), (stakedTokens = 10, ipfsHash = "Qmb"), (stakedTokens = 5, ipfsHash = "Qmc")])
source
AllocationOpt.togrtMethod
togrt(x::AbstractString)

Convert x to GRT.

Note

This function is meant to be used with freshly queried data, so it operates on strings.

julia> using AllocationOpt
+(NamedTuple[(var"subgraphDeployment.ipfsHash" = "Qma", allocatedTokens = 5, id = "0xa"), (var"subgraphDeployment.ipfsHash" = "Qmb", allocatedTokens = 10, id = "0xb")], NamedTuple[(stakedTokens = 5.0, ipfsHash = "Qma"), (stakedTokens = 10, ipfsHash = "Qmb"), (stakedTokens = 5, ipfsHash = "Qmc")])
source
AllocationOpt.togrtMethod
togrt(x::AbstractString)

Convert x to GRT.

Note

This function is meant to be used with freshly queried data, so it operates on strings.

julia> using AllocationOpt
 julia> AllocationOpt.togrt("1")
-1.0e-18
source
AllocationOpt.totalsupplyMethod
totalsupply(::Val{:network}, x)

The total GRT supply.

```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "totalSupply" => 1, "networkGRTIssuance" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.totalsupply(Val(:network), n) 1

source
AllocationOpt.unallocate_actionMethod
unallocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)

Create and push the unallocate actions to the action queue.

```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa") ]) julia> t = flextable([ Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"), ]) julia> config = Dict( "frozenlist" => [], "indexerurl" => "http://localhost:18000" ) julia> TheGraphData.client!(config["indexerurl"]) julia> AllocationOpt.unallocate_action(Val(:actionqueue), a, t, config) 1-element Vector{Dict{String, Any}}: Dict("priority" => 0, "status" => AllocationOpt.queued, "allocationID" => "0xa", "source" => "AllocationOpt", "reason" => "AllocationOpt", "type" => AllocationOpt.unallocate, "deploymentID" => "Qma")

source
AllocationOpt.unallocate_actionMethod
unallocate_action(::Val{:none}, a, t, config)

Do nothing.

julia> using AllocationOpt
+1.0e-18
source
AllocationOpt.totalsupplyMethod
totalsupply(::Val{:network}, x)

The total GRT supply.

```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( "id" => 1, "totalSupply" => 1, "networkGRTIssuance" => 1, "epochLength" => 28, "totalTokensSignalled" => 2, "currentEpoch" => 1, ) ]) julia> AllocationOpt.totalsupply(Val(:network), n) 1

source
AllocationOpt.unallocate_actionMethod
unallocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)

Create and push the unallocate actions to the action queue.

```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa") ]) julia> t = flextable([ Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"), ]) julia> config = Dict( "frozenlist" => [], "indexerurl" => "http://localhost:18000" ) julia> TheGraphData.client!(config["indexerurl"]) julia> AllocationOpt.unallocate_action(Val(:actionqueue), a, t, config) 1-element Vector{Dict{String, Any}}: Dict("priority" => 0, "status" => AllocationOpt.queued, "allocationID" => "0xa", "source" => "AllocationOpt", "reason" => "AllocationOpt", "type" => AllocationOpt.unallocate, "deploymentID" => "Qma")

source
AllocationOpt.unallocate_actionMethod
unallocate_action(::Val{:none}, a, t, config)

Do nothing.

julia> using AllocationOpt
 julia> a = flextable([
             Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa")
         ])
@@ -586,7 +586,7 @@
             Dict("amount" => "1", "profit" => "0", "ipfshash" => "Qma"),
             Dict("amount" => "2", "profit" => "0", "ipfshash" => "Qmb"),
         ])
-julia> AllocationOpt.unallocate_action(Val(:none), a, t, Dict())
source
AllocationOpt.unallocate_actionMethod
unallocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)

Print a rule that stops old allocations that the optimiser has not chosen and that aren't frozen.

julia> using AllocationOpt
+julia> AllocationOpt.unallocate_action(Val(:none), a, t, Dict())
source
AllocationOpt.unallocate_actionMethod
unallocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)

Print a rule that stops old allocations that the optimiser has not chosen and that aren't frozen.

julia> using AllocationOpt
 julia> a = flextable([
             Dict("subgraphDeployment.ipfsHash" => "Qma", "id" => "0xa")
         ])
@@ -596,7 +596,7 @@
 julia> AllocationOpt.unallocate_action(Val(:rules), a, t, Dict("frozenlist" => []))
 graph indexer rules stop Qma
 1-element Vector{String}:
- "graph indexer rules stop Qma"
source
AllocationOpt.writeMethod
write(i::FlexTable, a::FlexTable, s::FlexTable, n::FlexTable, config::AbstractDict)

Write the tables to the writedir specified in the config.

julia> using AllocationOpt
+ "graph indexer rules stop Qma"
source
AllocationOpt.writeMethod
write(i::FlexTable, a::FlexTable, s::FlexTable, n::FlexTable, config::AbstractDict)

Write the tables to the writedir specified in the config.

julia> using AllocationOpt
 julia> using TheGraphData
 julia> config = Dict("verbose" => true, "writedir" => "datadir")
 julia> t = flextable([
@@ -604,7 +604,7 @@
             Dict("ipfsHash" => "Qmb", "signalledTokens" => "2"),
         ])
 julia> i, a, s, n = repeat([t,], 4)
-juila> AllocationOpt.write(i, a, s, n, config)
source
AllocationOpt.writejsonMethod
function writejson(results::AbstractString, config::AbstractDict)

Write the optimized results to the writedir specified in the config.

julia> Using AllocationOpt
+juila> AllocationOpt.write(i, a, s, n, config)
source
AllocationOpt.writejsonMethod
function writejson(results::AbstractString, config::AbstractDict)

Write the optimized results to the writedir specified in the config.

julia> Using AllocationOpt
 julia> results = "{"strategies":[{"num_allocations":2,"profit":6.0,"allocations":[{"allocationAmount":2.5,"profit":3.0,"deploymentID":"Qma"},{"allocationAmount":2.5,"profit":3.0,"deploymentID":"Qmb"}]},{"num_allocations":1,"profit":5.0,"allocations":[{"allocationAmount":5.0,"profit":5.0,"deploymentID":"Qma"}]}]}"
 julia> config = Dict{"writedir" => "."}
-julia> AllocationOpt.writejson(results, config)
source
SemioticOpt.iterationMethod
iteration(f::Function, a::AnalyticOpt)

Perform the analytic optimisation.

source
SemioticOpt.x!Method
x!(a::AnalyticOpt, v)

In-place setting of a.x to v

See SemioticOpt.x.

source
SemioticOpt.xMethod
x(a::AnalyticOpt)

Return the current best guess for the solution.

source
+julia> AllocationOpt.writejson(results, config)source
SemioticOpt.iterationMethod
iteration(f::Function, a::AnalyticOpt)

Perform the analytic optimisation.

source
SemioticOpt.x!Method
x!(a::AnalyticOpt, v)

In-place setting of a.x to v

See SemioticOpt.x.

source
SemioticOpt.xMethod
x(a::AnalyticOpt)

Return the current best guess for the solution.

source
diff --git a/latest/bugs/index.html b/latest/bugs/index.html index 22a0b9b..e98685b 100644 --- a/latest/bugs/index.html +++ b/latest/bugs/index.html @@ -1,2 +1,2 @@ -Reporting Bugs · The Allocation Optimizer

Reporting Bugs

If something breaks, we hope you'll submit a bug report! There are a few things we'll need from you to reproduce the failure mode you're experiencing.

  1. Your config file
  2. The CSVs (if any) that the Optimizer saved.
  3. The stacktrace displaying the error message.
  4. The version of the Allocation Optimizer you are running.

These are a good place to start. We may ask you for more information as we investigate the bug.

+Reporting Bugs · The Allocation Optimizer

Reporting Bugs

If something breaks, we hope you'll submit a bug report! There are a few things we'll need from you to reproduce the failure mode you're experiencing.

  1. Your config file
  2. The CSVs (if any) that the Optimizer saved.
  3. The stacktrace displaying the error message.
  4. The version of the Allocation Optimizer you are running.

These are a good place to start. We may ask you for more information as we investigate the bug.

diff --git a/latest/build-a-binary/index.html b/latest/build-a-binary/index.html index 9133346..8d04457 100644 --- a/latest/build-a-binary/index.html +++ b/latest/build-a-binary/index.html @@ -2,4 +2,4 @@ Build Your Own Binary · The Allocation Optimizer

Build Your Own Binary

Compiling the binary yourself is an excellent way to use the Allocation Optimizer. You should use this route if a couple of reasons speak to you.

  1. You'd prefer not to trust a random binary off the internet.
  2. You have added your own features to the Allocation Optimizer, but would prefer the large, one-time cost of AOT compilation as opposed the small, every-time cost of JIT compilation.

In this documentation, we'll take you through the process of generating an app binary.

Note

You can instead compile to a sysimage or to a library, but we don't natively support those ourselves. Look through the PackageCompiler documentation for steps if you would prefer one of those options..

Install Julia! We prefer to use juliaup. You can install this via:

curl -fsSL https://install.julialang.org | sh
Note

As of writing this documentation, the latest version of Julia is v1.8. This the version the Allocation Optimizer currently uses, and the version juliaup will install by default. If juliaup begins to use v1.9, then you may need to use juliaup to manually install v1.8 via juliaup add 1.8. Then, you can either set the default to be v1.8 using juliaup default 1.8, or you can replace every time you see julia with julia +1.8 below.

Clone this repository and cd into it.

git clone https://github.com/graphprotocol/allocation-optimizer.git
 cd allocation-optimizer

Start Julia.

julia --project

Install the dependencies

julia> ]
 pkg> instantiate

Install a C-compiler such as GCC or Clang.

From the Julia REPL (the TUI that comes up when you use julia --project), compile your app.

julia> using PackageCompiler
-julia> create_app(".", "app")
Note

If you are still in Pkg mode, pkg>, hitting backspace will bring you back into the REPL.

Set up your configuration file. See Configuration for details.

Run the binary pointing at the configuration TOML that you would like to use.

./app/bin/AllocationOpt /path/to/your_config.toml
+julia> create_app(".", "app")
Note

If you are still in Pkg mode, pkg>, hitting backspace will bring you back into the REPL.

Set up your configuration file. See Configuration for details.

Run the binary pointing at the configuration TOML that you would like to use.

./app/bin/AllocationOpt /path/to/your_config.toml
diff --git a/latest/call-julia/index.html b/latest/call-julia/index.html index 1561ddb..b866468 100644 --- a/latest/call-julia/index.html +++ b/latest/call-julia/index.html @@ -3,4 +3,4 @@ cd allocation-optimizer

Start Julia.

julia --project

Install the dependencies

julia> ]
 pkg> instantiate

Set up your configuration file. See Configuration for details.

From the Julia REPL (the TUI that comes up when you use julia --project), run the main function with the path to your config.

julia> using AllocationOpt
 julia> path = "config.toml"  # path to your config file
-julia> AllocationOpt.main(path)
Note

If you are still in Pkg mode, pkg>, hitting backspace will bring you back into the REPL.

+julia> AllocationOpt.main(path)
Note

If you are still in Pkg mode, pkg>, hitting backspace will bring you back into the REPL.

diff --git a/latest/calling-another/index.html b/latest/calling-another/index.html index e633724..d756432 100644 --- a/latest/calling-another/index.html +++ b/latest/calling-another/index.html @@ -70,4 +70,4 @@ execute(a, ix, fs, xs, profitmatrix, config) return nothing -end

For details on any of the specific functions called, look at the API Reference.

+end

For details on any of the specific functions called, look at the API Reference.

diff --git a/latest/configuration/index.html b/latest/configuration/index.html index 7d4bf46..84b67fe 100644 --- a/latest/configuration/index.html +++ b/latest/configuration/index.html @@ -13,7 +13,7 @@ verbose = true num_reported_options = 2 execution_mode = "none" -opt_mode = "fast"

Detailed Field Descriptions

Example Configurations

ActionQueue

Set execution_mode to "actionqueue" and provide an indexer_url.

id = "0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c"
+opt_mode = "fast"

Detailed Field Descriptions

Example Configurations

ActionQueue

Set execution_mode to "actionqueue" and provide an indexer_url.

id = "0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c"
 writedir = "data"
 readdir = "data"
 max_allocations = 10
@@ -82,4 +82,4 @@
 min_signal = 1000
 verbose = false
 num_reported_options = 2
-execution_mode = "none"
+execution_mode = "none" diff --git a/latest/contributing/index.html b/latest/contributing/index.html index 0651068..4787ed6 100644 --- a/latest/contributing/index.html +++ b/latest/contributing/index.html @@ -1,2 +1,2 @@ -Contributing · The Allocation Optimizer

Contributing

We're excited you are interested in contributing! Please follow the standards put forth in ColPrac to contribute to the Allocation Optimizer.

Most importantly, we'd like to emphasise a few points.

  • PRs should do a single thing.
    • We'd prefer that you submit ten small PRs that are easy to understand as compared with one massive PR that requires a full day of review.
  • PRs should add tests which cover the new or fixed functionality.
  • PRs introducing breaking changes should make this clear when opening the PR.
+Contributing · The Allocation Optimizer

Contributing

We're excited you are interested in contributing! Please follow the standards put forth in ColPrac to contribute to the Allocation Optimizer.

Most importantly, we'd like to emphasise a few points.

  • PRs should do a single thing.
    • We'd prefer that you submit ten small PRs that are easy to understand as compared with one massive PR that requires a full day of review.
  • PRs should add tests which cover the new or fixed functionality.
  • PRs introducing breaking changes should make this clear when opening the PR.
diff --git a/latest/index.html b/latest/index.html index 87b21a7..bc037c7 100644 --- a/latest/index.html +++ b/latest/index.html @@ -1,2 +1,2 @@ -Home · The Allocation Optimizer

The Allocation Optimizer

This repository contains the code for the Indexer Allocation Optimizer. The goal of this project is to enable indexers to quickly determine how to allocate so as to maximise their indexing rewards.

Warning

We do not optimise for query fees directly, as we expect signal on a subgraph to be proportional to the query fees, as was the intention behind curation. Query fee information is also not public. It is local to each gateway. As a result, we will never be able to optimise with respect to query fees unless this changes.

Note

By default, opt_mode="fast". Fast-mode is not guaranteed to converge to a global optimum. If you get strange results, you should try opt_mode="optimal". This mode is still experimental, and will take longer to run, but you may get more reasonable results with it.

We will focus on usage of the code in this documentation. We refer you to these blog posts for more technical details. We also plan to post a yellowpaper at some point diving into our approach in even more detail. Stay tuned for that! If interested in how the code works, take a peek Under The Hood!

There are a few different ways you can run the allocation optimizer.

+Home · The Allocation Optimizer

The Allocation Optimizer

This repository contains the code for the Indexer Allocation Optimizer. The goal of this project is to enable indexers to quickly determine how to allocate so as to maximise their indexing rewards.

Warning

We do not optimise for query fees directly, as we expect signal on a subgraph to be proportional to the query fees, as was the intention behind curation. Query fee information is also not public. It is local to each gateway. As a result, we will never be able to optimise with respect to query fees unless this changes.

Note

By default, opt_mode="fast". Fast-mode is not guaranteed to converge to a global optimum. If you get strange results, you should try opt_mode="optimal". This mode is still experimental, and will take longer to run, but you may get more reasonable results with it.

We will focus on usage of the code in this documentation. We refer you to these blog posts for more technical details. We also plan to post a yellowpaper at some point diving into our approach in even more detail. Stay tuned for that! If interested in how the code works, take a peek Under The Hood!

There are a few different ways you can run the allocation optimizer.

diff --git a/latest/output/index.html b/latest/output/index.html index 427f615..d3bd3bb 100644 --- a/latest/output/index.html +++ b/latest/output/index.html @@ -50,4 +50,4 @@ graph indexer rules stop Qmaz1R8vcv9v3gUfksqiS9JUz7K9G8S5By3JYn8kTiiP5K graph indexer rules stop QmcBSr5R3K2M5tk8qeHFaX8pxAhdViYhcKD8ZegYuTcUhC graph indexer rules set QmT2Y7SHXGRt7EKXzFPYMjnrgX64PQr86EjbsHoDLNzwLy decisionBasis always allocationAmount 13539706.9 -graph indexer rules set QmXT4PhR9pwAUqkxg6tgqR8xWUsTYN7V8UgmqhrrimcqXf decisionBasis always allocationAmount 9194401.2

If instead you use "actionqueue" as the execution_mode, the Optimizer will populate your instance of the action queue.

+graph indexer rules set QmXT4PhR9pwAUqkxg6tgqR8xWUsTYN7V8UgmqhrrimcqXf decisionBasis always allocationAmount 9194401.2

If instead you use "actionqueue" as the execution_mode, the Optimizer will populate your instance of the action queue.

diff --git a/latest/provided-binary/index.html b/latest/provided-binary/index.html index 47a500e..37e090e 100644 --- a/latest/provided-binary/index.html +++ b/latest/provided-binary/index.html @@ -1,2 +1,2 @@ -Using The Provided Binary · The Allocation Optimizer

Using The Provided Binary

Using the provided binary has the advantage of being that only method that doesn't require that you use the Julia runtime. If you want to get running as quickly as possible, this is the path for you.

Note

We only release binaries for x86 Linux.

All you have to do is download the binary for the platform and release you want to use, unzip it, set up your configuration (Configuration) file, and run the binary from your terminal.

./path/to/unzipped/folder/bin/AllocationOpt /path/to/your_config.toml
+Using The Provided Binary · The Allocation Optimizer

Using The Provided Binary

Using the provided binary has the advantage of being that only method that doesn't require that you use the Julia runtime. If you want to get running as quickly as possible, this is the path for you.

Note

We only release binaries for x86 Linux.

All you have to do is download the binary for the platform and release you want to use, unzip it, set up your configuration (Configuration) file, and run the binary from your terminal.

./path/to/unzipped/folder/bin/AllocationOpt /path/to/your_config.toml
diff --git a/latest/search/index.html b/latest/search/index.html index 94b78a4..67ade38 100644 --- a/latest/search/index.html +++ b/latest/search/index.html @@ -1,2 +1,2 @@ -Search · The Allocation Optimizer

Loading search...

    +Search · The Allocation Optimizer

    Loading search...

      diff --git a/latest/search_index.js b/latest/search_index.js index 695b0c1..7fb6ef4 100644 --- a/latest/search_index.js +++ b/latest/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"","page":"Home","title":"Home","text":"CurrentModule = AllocationOpt","category":"page"},{"location":"#The-Allocation-Optimizer","page":"Home","title":"The Allocation Optimizer","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"This repository contains the code for the Indexer Allocation Optimizer. The goal of this project is to enable indexers to quickly determine how to allocate so as to maximise their indexing rewards.","category":"page"},{"location":"","page":"Home","title":"Home","text":"warning: Warning\nWe do not optimise for query fees directly, as we expect signal on a subgraph to be proportional to the query fees, as was the intention behind curation. Query fee information is also not public. It is local to each gateway. As a result, we will never be able to optimise with respect to query fees unless this changes.","category":"page"},{"location":"","page":"Home","title":"Home","text":"note: Note\nBy default, opt_mode=\"fast\". Fast-mode is not guaranteed to converge to a global optimum. If you get strange results, you should try opt_mode=\"optimal\". This mode is still experimental, and will take longer to run, but you may get more reasonable results with it.","category":"page"},{"location":"","page":"Home","title":"Home","text":"We will focus on usage of the code in this documentation. We refer you to these blog posts for more technical details. We also plan to post a yellowpaper at some point diving into our approach in even more detail. Stay tuned for that! If interested in how the code works, take a peek Under The Hood!","category":"page"},{"location":"","page":"Home","title":"Home","text":"There are a few different ways you can run the allocation optimizer.","category":"page"},{"location":"","page":"Home","title":"Home","text":"Using The Provided Binary\nCalling From Julia\nBuild Your Own Binary\nCalling From Another Language","category":"page"},{"location":"bugs/#Reporting-Bugs","page":"Reporting Bugs","title":"Reporting Bugs","text":"","category":"section"},{"location":"bugs/","page":"Reporting Bugs","title":"Reporting Bugs","text":"If something breaks, we hope you'll submit a bug report! There are a few things we'll need from you to reproduce the failure mode you're experiencing.","category":"page"},{"location":"bugs/","page":"Reporting Bugs","title":"Reporting Bugs","text":"Your config file\nThe CSVs (if any) that the Optimizer saved.\nThe stacktrace displaying the error message.\nThe version of the Allocation Optimizer you are running.","category":"page"},{"location":"bugs/","page":"Reporting Bugs","title":"Reporting Bugs","text":"These are a good place to start. We may ask you for more information as we investigate the bug.","category":"page"},{"location":"api/#API-Reference","page":"API Reference","title":"API Reference","text":"","category":"section"},{"location":"api/","page":"API Reference","title":"API Reference","text":"Modules = [AllocationOpt]","category":"page"},{"location":"api/#AllocationOpt.AnalyticOpt","page":"API Reference","title":"AllocationOpt.AnalyticOpt","text":"AnalyticOpt{\n T<:Real,\n V<:AbstractArray{T},\n U<:AbstractArray{T},\n A<:AbstractArray{T},\n S<:AbstractVector{<:Hook},\n} <: SemioticOpt.OptAlgorithm\n\nOptimise the indexing reward analytically.\n\nFields\n\nx::V is the current best guess for the solution. Typically zeros.\nΩ::U is the allocation vector of other indexers.\nψ::A is the signal vector.\nσ::T is the stake.\nhooks::S are the hooks\n\nExample\n\njulia> using AllocationOpt\njulia> using SemioticOpt\njulia> x = zeros(2)\njulia> Ω = [1.0, 1.0]\njulia> ψ = [10.0, 10.0]\njulia> σ = 5.0\njulia> alg = AllocationOpt.AnalyticOpt(;\n x=x, Ω=Ω, ψ=ψ, σ=σ, hooks=[StopWhen((a; kws...) -> kws[:i] > 1)]\n )\njulia> f = x -> x # This doesn't matter. `f` isn't used by the algorithm.\njulia> alg = minimize!(f, alg)\njulia> SemioticOpt.x(alg)\n2-element Vector{Float64}:\n 2.5\n 2.5\n\n\n\n\n\n","category":"type"},{"location":"api/#AllocationOpt.allocatablesubgraphs-Tuple{TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.allocatablesubgraphs","text":" allocatablesubgraphs(s::FlexTable, config::AbstractDict)\n\nFor the subgraphs s return a view of the subgraphs on which we can allocate.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> s = flextable([\n Dict(\"ipfsHash\" => \"Qma\", \"signalledTokens\" => 10,),\n Dict(\"ipfsHash\" => \"Qmb\", \"signalledTokens\" => 20),\n Dict(\"ipfsHash\" => \"Qmc\", \"signalledTokens\" => 5),\n ])\njulia> config = Dict(\n \"whitelist\" => String[\"Qmb\", \"Qmc\"],\n \"blacklist\" => String[],\n \"frozenlist\" => String[],\n \"pinnedlist\" => String[],\n \"min_signal\" => 0.0\n)\njulia> fs = AllocationOpt.allocatablesubgraphs(s, config)\nFlexTable with 2 columns and 2 rows:\n signalledTokens ipfsHash\n ┌──────────────────────────\n 1 │ 20 Qmb\n 2 │ 5 Qmc\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.allocate_action-Tuple{Val{:actionqueue}, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.allocate_action","text":"allocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)\n\nCreate and push allocate actions to the action queue.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> t = flextable([\n Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"),\n Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"),\n])\njulia> config = Dict(\n \"indexer_url\" => \"http://localhost:18000\"\n)\njulia> TheGraphData.client!(config[\"indexer_url\"])\njulia> AllocationOpt.allocate_action(Val(:actionqueue), a, t, Dict())\n1-element Vector{Dict{String, Any}}:\n Dict(\"amount\" => \"2\", \"priority\" => 0, \"status\" => AllocationOpt.queued, \"source\" => \"AllocationOpt\", \"reason\" => \"Expected profit: 0\", \"type\" => AllocationOpt.allocate, \"deploymentID\" => \"Qmb\")\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.allocate_action-Tuple{Val{:none}, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.allocate_action","text":"allocate_action(::Val{:none}, a, t, config)\n\nDo nothing.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> t = flextable([\n Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"),\n Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"),\n ])\njulia> AllocationOpt.allocate_action(Val(:none), a, t, Dict())\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.allocate_action-Tuple{Val{:rules}, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.allocate_action","text":"allocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)\n\nPrint the rules that allocates to new subgraphs.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\") ]) julia> t = flextable([ Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"), Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"), ]) julia> AllocationOpt.allocate_action(Val(:rules), a, t, Dict()) graph indexer rules set Qmb decisionBasis always allocationAmount 2 1-element Vector{String}: \"\u001b[0mgraph indexer rules set Qmb decisionBasis always allocationAmount 2\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.aquery-Tuple{AbstractString}","page":"API Reference","title":"AllocationOpt.aquery","text":"aquery(id::AbstractString)\n\nReturn the components of a GraphQL query for active allocations of indexer id.\n\nFor use with the TheGraphData.jl package.\n\njulia> using AllocationOpt\njulia> id = \"0xa\"\njulia> value, args, fields = AllocationOpt.aquery(id)\n(\"allocations\", Dict{String, Union{Dict{String, String}, String}}(\"where\" => Dict(\"status\" => \"Active\", \"indexer\" => \"0xa\")), [\"allocatedTokens\", \"id\", \"subgraphDeployment{ipfsHash}\"])\n\nExtended Help\n\nYou can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.availablestake-Tuple{Val{:indexer}, Any}","page":"API Reference","title":"AllocationOpt.availablestake","text":"available(::Val{:indexer}, x)\n\nThe tokens available for the indexer to allocate in table x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"stakedTokens\" => 10,\n \"delegatedTokens\" => 20,\n \"lockedTokens\" => 5,\n ),\n])\njulia> AllocationOpt.availablestake(Val(:indexer), x)\n25.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.bestprofitpernz-Union{Tuple{S}, Tuple{T}, Tuple{AbstractVector{T}, AbstractMatrix{S}}} where {T<:Integer, S<:Real}","page":"API Reference","title":"AllocationOpt.bestprofitpernz","text":"bestprofitpernz(ixs::AbstractVector{Integer}, profitmatrix::AbstractMatrix{Real})\n\nCompute the best profit amongst the given ixs given profit matrix p\n\njulia> using AllocationOpt\njulia> ixs = Dict([1] => [1], [2] => [2])\njulia> profitmatrix = [[2.5 5.0]; [2.5 1.0]]\njulia> AllocationOpt.bestprofitpernz.(values(ixs), Ref(profitmatrix))\n2-element Vector{NamedTuple{(:profit, :index), Tuple{Float64, Int64}}}:\n (profit = 5.0, index = 1)\n (profit = 6.0, index = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.blockissuance-Tuple{Val{:network}, Any}","page":"API Reference","title":"AllocationOpt.blockissuance","text":"blockissuance(::Val{:network}, x)\n\nThe tokens issued per block.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( \"id\" => 1, \"totalSupply\" => 1, \"networkGRTIssuance\" => 1, \"epochLength\" => 28, \"totalTokensSignalled\" => 2, \"currentEpoch\" => 1, ) ]) julia> AllocationOpt.blockissuance(Val(:network), n) 1\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.blocksperepoch-Tuple{Val{:network}, Any}","page":"API Reference","title":"AllocationOpt.blocksperepoch","text":"blocksperepoch(::Val{:network}, x)\n\nThe number of blocks in each epoch.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( \"id\" => 1, \"totalSupply\" => 1, \"networkGRTIssuance\" => 1, \"epochLength\" => 28, \"totalTokensSignalled\" => 2, \"currentEpoch\" => 1, ) ]) julia> AllocationOpt.blocksperepoch(Val(:network), n) 28\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.closeipfs-Tuple{Any, Any, Any}","page":"API Reference","title":"AllocationOpt.closeipfs","text":"closeipfs(existingipfs, proposedipfs, frozenlist)\n\nGet the list of the ipfs hashes of allocations to close.\n\njulia> using AllocationOpt\njulia> AllocationOpt.closeipfs([\"Qma\"], [\"Qmb\"], String[])\n1-element Vector{String}:\n \"Qma\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.configuredefaults!-Tuple{AbstractDict}","page":"API Reference","title":"AllocationOpt.configuredefaults!","text":"configuredefaults!(config::AbstractDict)\n\nSet default values for the config dictionary if the value was not specified in the config file.\n\nConfig Specification\n\nid::String: The ID of the indexer for whom we're optimising. No default value.\nnetwork_subgraph_endpoint::String: The network subgraph endpoint to query. By default, \"https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet\"\nwritedir::String: The directory to which to write the results of optimisation. If don't specify readdir, writedir also specifies the path to which to save the input data tables. By default, \".\"\nreaddir::Union{String, Nothing}: The directory from which to read saved data tables. This speeds up the process as we won't have to query the network subgraph for the relevant data. If you don't specify readdir, we will query your specified network_subgraph_endpoint for the data and write it to CSV files in writedir. This way, you can use your previous writedir as your readdir in future runs. By default, nothing\nwhitelist::Vector{String}: A list of subgraph IPFS hashes that you want to consider as candidates to which to allocate. If you leave this empty, we'll assume all subgraphs are in the whitelist. By default, String[]\nblacklist::Vector{String}: A list of subgraph IPFS hashes that you do not want to consider allocating to. For example, this list could include broken subgraphs or subgraphs that you don't want to index. By default, String[]\nfrozenlist::Vector{String}: If you have open allocations that you don't want to change, add the corresponding subgraph IPFS hashes to this list. By default, String[]\npinnedlist::Vector{String}: If you have subgraphs that you absolutely want to be allocated to, even if only with a negligible amount of GRT, add it to this list. By default, String[]\nallocation_lifetime::Integer: The number of epochs for which you expect the allocations the optimiser finds to be open. By default, 28\ngas::Real: The estimated gas cost in GRT to open/close allocations. By default, 100\nmin_signal::Real: The minimum amount of signal in GRT that must be on a subgraph in order for you to consider allocating to it. By default, 1000\nmax_allocations::Integer: The maximum number of new allocations you'd like the optimiser to consider opening. By default, 10\nnum_reported_options::Integer: The number of proposed allocation strategies to report. For example, if you select 10 we'd report best 10 allocation strategies ranked by profit. By default, 1\nverbose::Bool: If true, the optimiser will print details about what it is doing to stdout. By default, false\nexecution_mode::String: How the optimiser should execute the allocation strategies it finds. Options are \"none\", which won't do anything, \"actionqueue\", which will push actions to the action queue, and \"rules\", which will generate indexing rules. By default, \"none\"\nindexer_url::Union{String, Nothing}: The URL of the indexer management server you want to execute the allocation strategies on. If you specify \"actionqueue\", you must also specify indexer_url. By default, nothing\nopt_mode::String: We support two optimisation modes. One is \"fast\". This mode is fast, but may not find the optimal allocation. This mode is also used to the top num_reported_options allocation strategies. The other mode is \"optimal\". This mode is slower, but will find the optimal allocation. In general, we recommend exploring config options using \"fast\" mode first, and then using \"optimal\" mode to find the optimal allocation. By default, \"fast\"\n\njulia> using AllocationOpt\njulia> config = Dict{String, Any}(\"id\" => \"0xa\")\njulia> config = AllocationOpt.configuredefaults!(config)\nDict{String, Any} with 16 entries:\n \"execution_mode\" => \"none\"\n \"readdir\" => nothing\n \"writedir\" => \".\"\n \"num_reported_options\" => 1\n \"id\" => \"0xa\"\n \"pinnedlist\" => String[]\n \"indexer_url\" => nothing\n \"gas\" => 100\n \"allocation_lifetime\" => 28\n \"blacklist\" => String[]\n \"verbose\" => false\n \"min_signal\" => 1000\n \"network_subgraph_endpoint\" => \"https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet\"\n \"whitelist\" => String[]\n ⋮ => ⋮\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.correcttypes!-NTuple{4, TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.correcttypes!","text":"correcttypes!(i::FlexTable, a::FlexTable, s::FlexTable, n::FlexTable)\n\nConvert all tables to be in GRT.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> i = flextable([\n Dict(\n \"stakedTokens\" => \"1\",\n \"delegatedTokens\" => \"0\",\n \"id\" => \"0xa\",\n \"lockedTokens\" => \"0\",\n ),\n])\njulia> s = flextable([\n Dict(\n \"stakedTokens\" => \"1\",\n \"signalledTokens\" => \"0\",\n \"ipfsHash\" => \"Qma\",\n ),\n])\njulia> a = flextable([\n Dict(\n \"allocatedTokens\" => \"1\",\n \"subgraphDeployment.ipfsHash\" => \"Qma\",\n ),\n])\njulia> n = flextable([\n Dict(\n \"id\" => 1,\n \"totalSupply\" => \"1\",\n \"networkGRTIssuance\" => \"1\",\n \"epochLength\" => 28,\n \"totalTokensSignalled\" => \"2\",\n \"currentEpoch\" => 1,\n )\n])\njulia> i, a, s, n = AllocationOpt.correcttypes!(i, a, s, n)\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.correcttypes!-Tuple{Val{:allocation}, TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.correcttypes!","text":"correcttypes!(::Val{:allocation}, a::FlexTable)\n\nConvert the string currency fields in the allocation table to be in GRT.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\n \"allocatedTokens\" => \"1\",\n \"subgraphDeployment.ipfsHash\" => \"Qma\",\n ),\n])\njulia> AllocationOpt.correcttypes!(Val(:allocation), a)\nFlexTable with 2 columns and 1 row:\n subgraphDeployment.ipfsHash allocatedTokens\n ┌─────────────────────────────────────────────\n 1 │ Qma 1.0e-18\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.correcttypes!-Tuple{Val{:indexer}, TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.correcttypes!","text":"correcttypes!(::Val{:indexer}, i::FlexTable)\n\nConvert the string currency fields in the indexer table to be in GRT.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> i = flextable([\n Dict(\n \"stakedTokens\" => \"1\",\n \"delegatedTokens\" => \"0\",\n \"id\" => \"0xa\",\n \"lockedTokens\" => \"0\",\n ),\n])\njulia> AllocationOpt.correcttypes!(Val(:indexer), i)\nFlexTable with 4 columns and 1 row:\n stakedTokens delegatedTokens id lockedTokens\n ┌─────────────────────────────────────────────────\n 1 │ 1.0e-18 0.0 0xa 0.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.correcttypes!-Tuple{Val{:network}, TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.correcttypes!","text":"correcttypes!(::Val{:network}, n::FlexTable)\n\nConvert the string currency fields in the network table to be in GRT.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> n = flextable([\n Dict(\n \"id\" => 1,\n \"totalSupply\" => \"1\",\n \"networkGRTIssuance\" => \"1\",\n \"epochLength\" => 28,\n \"totalTokensSignalled\" => \"2\",\n \"currentEpoch\" => 1,\n )\n])\njulia> AllocationOpt.correcttypes!(Val(:network), n)\nFlexTable with 6 columns and 1 row:\n totalTokensSignalled currentEpoch totalSupply id networkGRTIssuance epochLength\n ┌─────────────────────────────────────────────────────────────────────────────────────\n 1 │ 2.0e-18 1 1.0e-18 1 1.0e-18 28\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.correcttypes!-Tuple{Val{:subgraph}, TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.correcttypes!","text":"correcttypes!(::Val{:subgraph}, s::FlexTable)\n\nConvert the string currency fields in the subgraph table to be in GRT.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> s = flextable([\n Dict(\n \"stakedTokens\" => \"1\",\n \"signalledTokens\" => \"0\",\n \"ipfsHash\" => \"Qma\",\n \"deniedAt\" => 0,\n ),\n])\njulia> AllocationOpt.correcttypes!(Val(:subgraph), s)\nFlexTable with 4 columns and 1 row:\n deniedAt stakedTokens signalledTokens ipfsHash\n ┌──────────────────────────────────────────────────\n 1 │ 0 1.0e-18 0.0 Qma\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.currentepoch-Tuple{Val{:network}, Any}","page":"API Reference","title":"AllocationOpt.currentepoch","text":"currentepoch(::Val{:network}, x)\n\nThe current epoch.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( \"id\" => 1, \"totalSupply\" => 1, \"networkGRTIssuance\" => 1, \"epochLength\" => 28, \"totalTokensSignalled\" => 2, \"currentEpoch\" => 1, ) ]) julia> AllocationOpt.currentepoch(Val(:network), n) 1\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.delegation-Tuple{Val{:indexer}, Any}","page":"API Reference","title":"AllocationOpt.delegation","text":"delegation(::Val{:indexer}, x)\n\nThe tokens delegated to the indexer in table x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"delegatedTokens\" => 10,\n ),\n])\njulia> AllocationOpt.delegation(Val(:indexer), x)\n10\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.deniedat-Tuple{Val{:subgraph}, Any}","page":"API Reference","title":"AllocationOpt.deniedat","text":"deniedat(::Val{:subgraph}, x)\n\nIf this value is non-zero, the subgraph doesn't receive indexing rewards.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\"deniedAt\" => 10,),\n Dict(\"deniedAt\" => 0,),\n])\njulia> AllocationOpt.deniedat(Val(:subgraph), x)\n2-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:\n 10\n 0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.deniedzeroixs-Tuple{TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.deniedzeroixs","text":"deniedzeroixs(s::FlexTable)\n\nFind the indices of subgraphs that have \"deniedAt\" equal to zero.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> s = flextable([\n Dict(\"ipfsHash\" => \"Qma\", \"signalledTokens\" => 5.0, \"deniedAt\" => 0),\n Dict(\"ipfsHash\" => \"Qmb\", \"signalledTokens\" => 10.0, \"deniedAt\" => 10),\n Dict(\"ipfsHash\" => \"Qmc\", \"signalledTokens\" => 15.0, \"deniedAt\" => 0),\n ])\njulia> AllocationOpt.deniedzeroixs(s)\n2-element Vector{Int64}:\n 1\n 3\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.dual-Tuple{Any, Any, Any}","page":"API Reference","title":"AllocationOpt.dual","text":"dual(Ω, ψ, σ)\n\nAnalytic solution of the dual form of the optimisation problem given signals ψ, allocation vector Ω, and stake σ.\n\nnote: Note\nYou should probably not use this function directly. Use optimizeanalytic instead.\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.execute-Union{Tuple{T}, Tuple{TypedTables.FlexTable, Integer, TypedTables.FlexTable, AbstractMatrix{T}, AbstractMatrix{T}, AbstractDict}} where T<:Real","page":"API Reference","title":"AllocationOpt.execute","text":"execute(\n a::FlexTable,\n ix::Integer,\n s::FlexTable,\n xs::AbstractMatrix{T},\n ps::AbstractMatrix{T},\n config::AbstractDict\n) where {T<:Real}\n\nExecute the actions picked by the optimiser.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> xs = [[2.5 5.0]; [2.5 0.0]]\njulia> ps = [[3.0 5.0]; [3.0 0.0]]\njulia> s = flextable([\n Dict(\"stakedTokens\" => \"1\", \"signalledTokens\" => \"0\", \"ipfsHash\" => \"Qma\"),\n Dict(\"stakedTokens\" => \"2\", \"signalledTokens\" => \"0\", \"ipfsHash\" => \"Qmb\"),\n ])\njulia> config = Dict(\"execution_mode\" => \"none\")\njulia> ix = 1\njulia> AllocationOpt.execute(a, ix, s, xs, ps, config)\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.formatconfig!-Tuple{AbstractDict}","page":"API Reference","title":"AllocationOpt.formatconfig!","text":"formatconfig!(config::AbstractDict)\n\nGiven a config, reformat values that need to be standardised.\n\njulia> using AllocationOpt\njulia> config = Dict(\"id\" => \"0xA\")\njulia> AllocationOpt.formatconfig!(config)\nDict{String, String} with 1 entry:\n \"id\" => \"0xa\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.frozen-Tuple{TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.frozen","text":"frozen(a::FlexTable, config::AbstractDict)\n\nThe frozen stake of the indexer with allocations a.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"allocatedTokens\" => 5),\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qmb\", \"allocatedTokens\" => 10),\n ])\njulia> config = Dict(\"frozenlist\" => [\"Qma\", \"Qmb\"])\njulia> AllocationOpt.frozen(a, config)\n15.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.groupunique-Tuple{AbstractVector}","page":"API Reference","title":"AllocationOpt.groupunique","text":"groupunique(x::AbstractVector)\n\nFind the indices of each unique value in x\n\njulia> using AllocationOpt\njulia> x = [1, 2, 1, 3, 2, 3]\njulia> AllocationOpt.groupunique(x)\nDict{Vector{Int64}, Vector{Int64}} with 3 entries:\n [3] => [4, 6]\n [1] => [1, 3]\n [2] => [2, 5]\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.id-Tuple{Val{:allocation}, Any}","page":"API Reference","title":"AllocationOpt.id","text":"id(::Val{:allocation}, x)\n\nGet the allocation id for each allocation in x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"id\" => \"0x1\"\n ),\n])\njulia> AllocationOpt.id(Val(:allocation), x)\n1-element view(lazystack(::Vector{Vector{String}}), 1, :) with eltype String:\n \"0x1\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.indexingreward-NTuple{5, Real}","page":"API Reference","title":"AllocationOpt.indexingreward","text":"indexingreward(x::Real, Ω::Real, ψ::Real, Φ::Real, Ψ::Real)\n\nThe indexing rewards for the allocation scalar x given signals ψ, the existing allocation on subgraphs Ω, token issuance Φ, and total signal Ψ.\n\njulia> using AllocationOpt\njulia> ψ = 0.0\njulia> Ω = 1.0\njulia> Φ = 1.0\njulia> Ψ = 2.0\njulia> x = 1.0\njulia> AllocationOpt.indexingreward(x, Ω, ψ, Φ, Ψ)\n0.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.indexingreward-Union{Tuple{I}, Tuple{T}, Tuple{AbstractArray{I}, AbstractVector{T}, AbstractVector{T}, AbstractVector{T}, Real, Real}} where {T<:Real, I<:Integer}","page":"API Reference","title":"AllocationOpt.indexingreward","text":"indexingreward(\n ixs::AbstractArray{Integer},\n x::AbstractVector{Real},\n Ω::AbstractVector{Real},\n ψ::AbstractVector{Real},\n Φ::Real,\n Ψ::Real\n)\n\nThe indexing rewards for the allocation vector x given signals ψ, the existing allocations on subgraphs Ω, token issuance Φ, and total signal Ψ. Here ixs is a vector of indices Ω, and ψ. x will be filtered by SemioticOpt, so we don't do this here.\n\njulia julia> using AllocationOpt julia> ixs = Int32[2] julia> ψ = [0.0, 1.0] julia> Ω = [1.0, 1.0] julia> Φ = 1.0 julia> Ψ = 2.0 julia> x = [0.0, 1.0] julia> AllocationOpt.indexingreward(ixs, x, Ω, ψ, Φ, Ψ) 0.25`\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.indexingreward-Union{Tuple{T}, Tuple{AbstractVector{T}, AbstractVector{T}, AbstractVector{T}, Real, Real}} where T<:Real","page":"API Reference","title":"AllocationOpt.indexingreward","text":"indexingreward(\n x::AbstractVector{Real},\n Ω::AbstractVector{Real},\n ψ::AbstractVector{Real},\n Φ::Real,\n Ψ::Real\n)\n\nThe indexing rewards for the allocation vector x given signals ψ, the existing allocations on subgraphs Ω, token issuance Φ, and total signal Ψ.\n\njulia> using AllocationOpt\njulia> ψ = [0.0, 1.0]\njulia> Ω = [1.0, 1.0]\njulia> Φ = 1.0\njulia> Ψ = 2.0\njulia> x = [0.0, 1.0]\njulia> AllocationOpt.indexingreward(x, Ω, ψ, Φ, Ψ)\n0.25\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.ipfshash-Tuple{Val{:allocation}, Any}","page":"API Reference","title":"AllocationOpt.ipfshash","text":"ipfshash(::Val{:allocation}, x)\n\nGet the ipfs hash of x when x is part of the allocation table.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"subgraphDeployment.ipfsHash\" => \"Qma\",\n ),\n])\njulia> AllocationOpt.ipfshash(Val(:allocation), x)\n1-element view(lazystack(::Vector{Vector{String}}), 1, :) with eltype String:\n \"Qma\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.ipfshash-Tuple{Val{:subgraph}, Any}","page":"API Reference","title":"AllocationOpt.ipfshash","text":"ipfshash(::Val{:subgraph}, x)\n\nGet the ipfs hash of x when x is part of the allocation table.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"ipfsHash\" => \"Qma\",\n ),\n])\njulia> AllocationOpt.ipfshash(Val(:subgraph), x)\n1-element view(lazystack(::Vector{Vector{String}}), 1, :) with eltype String:\n \"Qma\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.iquery-Tuple{AbstractString}","page":"API Reference","title":"AllocationOpt.iquery","text":"iquery(id::AbstractString)\n\nReturn the components of a GraphQL query for the stake of indexer id.\n\nFor use with the TheGraphData.jl package.\n\njulia> using AllocationOpt\njulia> id = \"0xa\"\njulia> value, args, fields = AllocationOpt.iquery(id)\n(\"indexer\", Dict{String, Union{Int64, Dict{String, String}, String}}(\"id\" => \"0xa\"), [\"delegatedTokens\", \"stakedTokens\", \"lockedTokens\"])\n\nExtended Help\n\nYou can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.lipschitzconstant-Tuple{Any, Any}","page":"API Reference","title":"AllocationOpt.lipschitzconstant","text":"lipschitzconstant(ψ, Ω)\n\nThe Lipschitz constant of the indexing reward function given signals ψ and allocations Ω.\n\njulia> using AllocationOpt\njulia> ψ = [0.0, 1.0]\njulia> Ω = [1.0, 1.0]\njulia> AllocationOpt.lipschitzconstant(ψ, Ω)\n2.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.locked-Tuple{Val{:indexer}, Any}","page":"API Reference","title":"AllocationOpt.locked","text":"locked(::Val{:indexer}, x)\n\nThe locked tokens of the indexer in table x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"lockedTokens\" => 10,\n ),\n])\njulia> AllocationOpt.locked(Val(:indexer), x)\n10\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.newtokenissuance-Tuple{TypedTables.FlexTable, Dict}","page":"API Reference","title":"AllocationOpt.newtokenissuance","text":"newtokenissuance(n::FlexTable, config::Dict)\n\nHow many new tokens are issued over the allocation lifetime given network parameters n.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> n = flextable([\n Dict(\n \"id\" => 1,\n \"totalSupply\" => 1,\n \"networkGRTIssuance\" => 2,\n \"epochLength\" => 1,\n \"totalTokensSignalled\" => 2,\n \"currentEpoch\" => 1,\n )\n ])\njulia> config = Dict(\"allocation_lifetime\" => 1)\njulia> AllocationOpt.newtokenissuance(n, config)\n1.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.nonzero-Tuple{AbstractVector}","page":"API Reference","title":"AllocationOpt.nonzero","text":"nonzero(v::AbstractVector)\n\nGet the non-zero elements of vector v.\n\njulia> using AllocationOpt\njulia> v = [0.0, 1.0]\njulia> AllocationOpt.nonzero(v)\n1-element view(::Vector{Float64}, [2]) with eltype Float64:\n 1.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.nquery-Tuple{}","page":"API Reference","title":"AllocationOpt.nquery","text":"nquery()\n\nReturn the components of a GraphQL query for network parameters.\n\nFor use with the TheGraphData.jl package.\n\njulia> using AllocationOpt\njulia> value, args, fields = AllocationOpt.nquery()\n(\"graphNetwork\", Dict(\"id\" => 1), [\"id\", \"totalSupply\", \"networkGRTIssuance\", \"epochLength\", \"totalTokensSignalled\", \"currentEpoch\"])\n\nExtended Help\n\nYou can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.optimize-Tuple{Any, Any, Any, Any, Any, Any, Any, Any, AbstractDict}","page":"API Reference","title":"AllocationOpt.optimize","text":"optimize(Ω, ψ, σ, K, Φ, Ψ, g, rixs, config::AbstractDict)\n\nFind the optimal solution vector given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas in grt g. rixs are the indices of subgraphs that are eligible to receive indexing rewards.\n\nDispatches to optimize with the opt_mode key.\n\nIf opt_mode is fast, then run projected gradient descent with GSSP and Halpern. If opt_mode is optimal, then run Pairwise Greedy Optimisation.\n\njulia> using AllocationOpt\njulia> config = Dict(\"opt_mode\" => \"fast\")\njulia> rixs = [1, 2]\njulia> Ω = [1.0, 1.0]\njulia> ψ = [10.0, 10.0]\njulia> σ = 5.0\njulia> K = 2\njulia> Φ = 1.0\njulia> Ψ = 20.0\njulia> g = 0.01\njulia> xs, nonzeros, profits = AllocationOpt.optimize(Ω, ψ, σ, K, Φ, Ψ, g, rixs, config)\n([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.optimize-Tuple{Val{:fast}, Any, Any, Any, Any, Any, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.optimize","text":"optimize(::Val{:fast}, Ω, ψ, σ, K, Φ, Ψ, g, rixs)\n\nFind the optimal vectors for k ∈ [1,K] given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas in grt g. rixs are the indices of subgraphs that are eligible to receive indexing rewards.\n\njulia> using AllocationOpt\njulia> rixs = [1, 2]\njulia> Ω = [1.0, 1.0]\njulia> ψ = [10.0, 10.0]\njulia> σ = 5.0\njulia> K = 2\njulia> Φ = 1.0\njulia> Ψ = 20.0\njulia> g = 0.01\njulia> xs, nonzeros, profits = AllocationOpt.optimize(Val(:fast), Ω, ψ, σ, K, Φ, Ψ, g, rixs)\n([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.optimize-Tuple{Val{:optimal}, Any, Any, Any, Any, Any, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.optimize","text":"optimize(::Val{:optimal}, Ω, ψ, σ, K, Φ, Ψ, g, rixs)\n\nFind the optimal solution vector given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas in grt g. rixs are the indices of subgraphs that are eligible to receive indexing rewards.\n\nExample\n\njulia> using AllocationOpt\njulia> rixs = [1, 2]\njulia> Ω = [1.0, 1.0]\njulia> ψ = [10.0, 10.0]\njulia> σ = 5.0\njulia> K = 2\njulia> Φ = 1.0\njulia> Ψ = 20.0\njulia> g = 0.01\njulia> xs, nonzeros, profits = AllocationOpt.optimize(\n Val(:optimal), Ω, ψ, σ, K, Φ, Ψ, g, rixs\n )\n([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.optimizeanalytic-Tuple{Any, Any, Any}","page":"API Reference","title":"AllocationOpt.optimizeanalytic","text":"optimizeanalytic(Ω, ψ, σ)\n\nOptimise analytically over existing allocation vector Ω, signals ψ, and stake σ.\n\njulia> using AllocationOpt\njulia> Ω = [1.0, 7.0]\njulia> ψ = [10.0, 5.0]\njulia> σ = 5.0\njulia> AllocationOpt.optimizeanalytic(Ω, ψ, σ)\n2-element Vector{Float64}:\n 3.5283092056122474\n 1.4716907943877526\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.optimizek-Tuple{Val{:fast}, Any, Any, Any, Any, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.optimizek","text":"optimizek(::Val{:fast}, x₀, Ω, ψ, σ, k, Φ, Ψ)\n\nFind the optimal k sparse vector given initial value x₀, allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, and total signal Ψ.\n\njulia> using AllocationOpt\njulia> x₀ = [2.5, 2.5]\njulia> Ω = [1.0, 1.0]\njulia> ψ = [10.0, 10.0]\njulia> σ = 5.0\njulia> k = 1\njulia> Φ = 1.0\njulia> Ψ = 20.0\njulia> AllocationOpt.optimizek(Val(:fast), x₀, Ω, ψ, σ, k, Φ, Ψ)\n2-element Vector{Float64}:\n 5.0\n 0.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.optimizek-Tuple{Val{:optimal}, Any, Any, Any, Any, Any, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.optimizek","text":"optimizek(::Val{:optimal}, x₀, Ω, ψ, σ, k, Φ, Ψ, g)\n\nFind the optimal k sparse vector given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas g.\n\nExample\n\njulia> using AllocationOpt\njulia> Ω = [1.0, 1.0]\njulia> ψ = [10.0, 10.0]\njulia> σ = 5.0\njulia> k = 1\njulia> Φ = 1.0\njulia> Ψ = 20.0\njulia> g = 0.01\njulia> x₀ = zeros(length(Ω))\njulia> x = AllocationOpt.optimizek(Val(:optimal), x₀, Ω, ψ, σ, k, Φ, Ψ, g)\n2-element Vector{Float64}:\n 5.0\n 0.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.pinned-Tuple{TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.pinned","text":"pinned(config::AbstractDict)\n\nThe pinned vector of the indexer.\n\njulia> using AllocationOpt\njulia> s = flextable([\n Dict(\"ipfsHash\" => \"Qma\", \"signalledTokens\" => 5.0),\n Dict(\"ipfsHash\" => \"Qmb\", \"signalledTokens\" => 10.0),\n Dict(\"ipfsHash\" => \"Qmc\", \"signalledTokens\" => 15.0),\n])\njulia> config = Dict(\"pinnedlist\" => [\"Qma\", \"Qmb\"])\njulia> AllocationOpt.pinned(s, config)\n3-element Vector{Float64}:\n 0.1\n 0.1\n 0.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.primal-Tuple{Any, Any, Any}","page":"API Reference","title":"AllocationOpt.primal","text":"primal(Ω, ψ, ν)\n\nAnalytic solution of the primal form of the optimisation problem given signals ψ, allocations Ω, and a dual solution vector ν.\n\nnote: Note\nYou should probably not use this function directly. Use optimizeanalytic instead.\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.profit-Tuple{Real, Real}","page":"API Reference","title":"AllocationOpt.profit","text":"profit(r::Real, g::Real)\n\nCompute the profit for one allocation with reward r and gas cost g.\n\njulia> using AllocationOpt\njulia> r = 10\njulia> g = 1\njulia> AllocationOpt.profit(r, g)\n9\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.read-Tuple{AbstractDict{String, Any}}","page":"API Reference","title":"AllocationOpt.read","text":"read(config::AbstractDict)\n\nGiven a config, read the data in as flextables.\n\nIf you have specified a \"readdir\" in the config, this will read from CSV files in that directory. Otherwise, this will query the specified \"network_subgraph_endpoint\"\n\njulia> using AllocationOpt\njulia> config = Dict(\"verbose\" => false, \"readdir\" => \"mydatadir\")\njulia> i, a, s, n = AllocationOpt.read(config) # Read data from CSVs\n\njulia> using AllocationOpt\njulia> config = Dict(\n \"verbose\" => false,\n \"network_subgraph_endpoint\" => \"https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet\",\n \"readdir\" => nothing,\n)\njulia> i, a, s, n = AllocationOpt.read(config) # Query GQL endpoint\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.read-Tuple{AbstractString, AbstractDict}","page":"API Reference","title":"AllocationOpt.read","text":"read(f::AbstractString, config::AbstractDict)\n\nRead the CSV files from f and return the tables from those files.\n\njulia> using AllocationOpt\njulia> i, a, s, n = AllocationOpt.read(\"myreaddir\", Dict(\"verbose\" => true))\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.read-Tuple{Nothing, AbstractDict{String, Any}}","page":"API Reference","title":"AllocationOpt.read","text":"read(::Nothing, config::AbstractDict)\n\nQuery the required data from the provided endpoint in the config.\n\njulia> using AllocationOpt\njulia> config = Dict(\n \"verbose\" => true,\n \"network_subgraph_endpoint\" => \"https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet\",\n )\njulia> i, a, s, n = AllocationOpt.read(nothing, config)\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.readconfig-Tuple{AbstractString}","page":"API Reference","title":"AllocationOpt.readconfig","text":"readconfig(p::AbstractString)\n\nRead the config file from path p. The config file must be specifed as a TOML.\n\nSee configuredefaults! to see which fields you should specify in the config.\n\njulia> using AllocationOpt\njulia> path = \"myconfig.toml\"\njulia> config = AllocationOpt.readconfig(path)\nDict{String, Any} with 13 entries:\n \"execution_mode\" => \"none\"\n \"writedir\" => \"data\"\n \"num_reported_options\" => 2\n \"id\" => \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\n \"pinnedlist\" => Union{}[]\n \"gas\" => 100\n \"allocation_lifetime\" => 28\n \"blacklist\" => Union{}[]\n \"verbose\" => true\n \"min_signal\" => 1000\n \"whitelist\" => Union{}[]\n \"max_allocations\" => 5\n \"frozenlist\" => Union{}[]\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.reallocate_action-Tuple{Val{:actionqueue}, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.reallocate_action","text":"reallocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)\n\nCreate and push reallocate actions to the action queue.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> t = flextable([\n Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"),\n Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"),\n])\njulia> config = Dict(\"indexer_url\" => \"http://localhost:18000\")\njulia> TheGraphData.client!(config[\"indexer_url\"])\njulia> AllocationOpt.reallocate_action(Val(:actionqueue), a, t, config)\n1-element Vector{Dict{String, Any}}:\n Dict(\"amount\" => \"1\", \"priority\" => 0, \"status\" => AllocationOpt.queued, \"allocationID\" => \"0xa\", \"source\" => \"AllocationOpt\", \"reason\" => \"Expected profit: 0\", \"type\" => AllocationOpt.reallocate, \"deploymentID\" => \"Qma\")\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.reallocate_action-Tuple{Val{:none}, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.reallocate_action","text":"reallocate_action(::Val{:none}, a, t, config)\n\nDo nothing.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\") ]) julia> t = flextable([ Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"), Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"), ]) julia> AllocationOpt.reallocate_action(Val(:none), a, t, Dict())\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.reallocate_action-Tuple{Val{:rules}, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.reallocate_action","text":"reallocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)\n\nPrint a rule that reallocates the old allocation with a new allocation amount\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> t = flextable([\n Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"),\n Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"),\n])\njulia> AllocationOpt.reallocate_action(Val(:rules), a, t, Dict())\ngraph indexer rules stop Qma\nCheck allocation status being closed before submitting: graph indexer rules set Qma decisionBasis always allocationAmount 1\n1-element Vector{String}:\n \"\u001b[0mgraph indexer rules stop Qm\" ⋯ 122 bytes ⋯ \"asis always allocationAmount 1\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.reportingtable-Union{Tuple{T}, Tuple{TypedTables.FlexTable, AbstractMatrix{T}, AbstractMatrix{T}, Integer}} where T<:Real","page":"API Reference","title":"AllocationOpt.reportingtable","text":"reportingtable(\n s::FlexTable, xs::AbstractMatrix{Real}, ps::AbstractMatrix{Real}, i::Integer\n)\n\nConstruct a table for the strategy mapping the ipfshash, allocation amount, and profit\n\njulia> using AllocationOpt\njulia> s = flextable([\n Dict(\"stakedTokens\" => \"1\", \"signalledTokens\" => \"2\", \"ipfsHash\" => \"Qma\"),\n Dict(\"stakedTokens\" => \"2\", \"signalledTokens\" => \"1\", \"ipfsHash\" => \"Qmb\"),\n ])\njulia> xs = [[2.5 5.0]; [2.5 0.0]]\njulia> ps = [[3.0 5.0]; [3.0 0.0]]\njulia> i = 1\njulia> AllocationOpt.reportingtable(s, xs, ps, i)\nFlexTable with 3 columns and 2 rows:\n ipfshash amount profit\n ┌─────────────────────────\n 1 │ Qma 2.5 3.0\n 2 │ Qmb 2.5 3.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.savenames-Tuple{AbstractString}","page":"API Reference","title":"AllocationOpt.savenames","text":"savenames(p::AbstractString)\n\nReturn a generator of the generic names of the CSV files containing the data with the path specified by p.\n\njulia> using AllocationOpt\njulia> path = \"mypath\"\njulia> paths = AllocationOpt.savenames(path)\nBase.Generator{NTuple{4, String}, AllocationOpt.var\"#1#2\"{String}}(AllocationOpt.var\"#1#2\"{String}(\"mypath\"), (\"indexer.csv\", \"allocation.csv\", \"subgraph.csv\", \"network.csv\"))\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.signal-Tuple{Val{:network}, Any}","page":"API Reference","title":"AllocationOpt.signal","text":"signal(::Val{:network}, x)\n\nThe total signal in the network\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( \"id\" => 1, \"totalSupply\" => 1, \"networkGRTIssuance\" => 1, \"epochLength\" => 28, \"totalTokensSignalled\" => 2, \"currentEpoch\" => 1, ) ]) julia> AllocationOpt.signal(Val(:network), n) 2\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.signal-Tuple{Val{:subgraph}, Any}","page":"API Reference","title":"AllocationOpt.signal","text":"signal(::Val{:subgraph}, x)\n\nThe tokens signalled on the subgraphs in table x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\"signalledTokens\" => 10,),\n Dict(\"signalledTokens\" => 5,),\n])\njulia> AllocationOpt.signal(Val(:subgraph), x)\n2-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:\n 10\n 5\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.sortprofits!-Union{Tuple{AbstractVector{N}}, Tuple{N}} where N<:NamedTuple","page":"API Reference","title":"AllocationOpt.sortprofits!","text":"sortprofits!(NamedTuple{Tuple{Float64, Int64}})\n\nSort the nonzero best profits from highest to lowest\n\njulia> using AllocationOpt\njulia> popts = [\n (; :profit => 5.0, :index => 2),\n (; :profit => 6.0, :index => 1)\n ]\njulia> popts = AllocationOpt.sortprofits!(popts)\n2-element Vector{NamedTuple{(:profit, :index), Tuple{Float64, Int64}}}:\n (profit = 6.0, index = 1)\n (profit = 5.0, index = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.squery-Tuple{}","page":"API Reference","title":"AllocationOpt.squery","text":"squery()\n\nReturn the components of a GraphQL query for subgraphs.\n\nFor use with the TheGraphData.jl package.\n\njulia> using AllocationOpt\njulia> value, args, fields = AllocationOpt.squery()\n(\"subgraphDeployments\", Dict{String, Union{Dict{String, String}, String}}(), [\"ipfsHash\", \"signalledTokens\", \"stakedTokens\"])\n\nExtended Help\n\nYou can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.stake-Tuple{Val{:allocation}, Any}","page":"API Reference","title":"AllocationOpt.stake","text":"stake(::Val{:allocation}, x)\n\nGet the allocated tokens for each allocation in x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"allocatedTokens\" => 1,\n ),\n])\njulia> AllocationOpt.stake(Val(:allocation), x)\n1-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:\n 1\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.stake-Tuple{Val{:indexer}, Any}","page":"API Reference","title":"AllocationOpt.stake","text":"stake(::Val{:indexer}, x)\n\nThe tokens staked by the indexer in table x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"stakedTokens\" => 10,\n ),\n])\njulia> AllocationOpt.stake(Val(:indexer), x)\n10\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.stake-Tuple{Val{:subgraph}, Any}","page":"API Reference","title":"AllocationOpt.stake","text":"stake(::Val{:subgraph}, x)\n\nThe tokens staked on the subgraphs in table x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\"stakedTokens\" => 10,),\n Dict(\"stakedTokens\" => 5,),\n])\njulia> AllocationOpt.stake(Val(:subgraph), x)\n2-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:\n 10\n 5\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.strategydict-Union{Tuple{I}, Tuple{T}, Tuple{NamedTuple, AbstractMatrix{T}, AbstractVector{I}, TypedTables.FlexTable, AbstractMatrix{T}}} where {T<:Real, I<:Integer}","page":"API Reference","title":"AllocationOpt.strategydict","text":"strategydict(\n p::NamedTuple,\n xs::AbstractMatrix{Real},\n nonzeros::AbstractVector{Integer},\n fs::FlexTable,\n profitmatrix::AbstractMatrix{Real}\n)\n\nFor a profit, index pair p, generate the nested dictionary representing the data to convert to a JSON string. xs is the allocation strategy matrix, nonzeros are the number of nonzeros in each allocation strategy, fs is a table containing subgraph ipfshashes, and the profitmatrix is a matrix containing profit for each allocation in xs\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> popts = [\n (; :profit => 6.0, :index => 1),\n (; :profit => 5.0, :index => 2)\n ]\njulia> xs = [[2.5 5.0]; [2.5 0.0]]\njulia> profits = [[3.0 5.0]; [3.0 0.0]]\njulia> nonzeros = [2, 1]\njulia> fs = flextable([\n Dict(\"stakedTokens\" => \"1\", \"signalledTokens\" => \"0\", \"ipfsHash\" => \"Qma\"),\n Dict(\"stakedTokens\" => \"2\", \"signalledTokens\" => \"0\", \"ipfsHash\" => \"Qmb\"),\n ])\njulia> AllocationOpt.strategydict.(popts, Ref(xs), Ref(nonzeros), Ref(fs), Ref(profits))\n2-element Vector{Dict{String, Any}}:\n Dict(\"num_allocations\" => 2, \"profit\" => 6.0, \"allocations\" => Dict{String, Any}[Dict(\"allocationAmount\" => \"2.5\", \"profit\" => 3.0, \"deploymentID\" => \"Qma\"), Dict(\"allocationAmount\" => \"2.5\", \"profit\" => 3.0, \"deploymentID\" => \"Qmb\")])\n Dict(\"num_allocations\" => 1, \"profit\" => 5.0, \"allocations\" => Dict{String, Any}[Dict(\"allocationAmount\" => \"5\", \"profit\" => 5.0, \"deploymentID\" => \"Qma\")])\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.subtractindexer!-Tuple{TypedTables.FlexTable, TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.subtractindexer!","text":"subtractindexer!(a::FlexTable, s::FlexTable)\n\nSubtract the indexer's allocated tokens from the total allocated tokens on each subgraph.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> s = flextable([\n Dict(\"ipfsHash\" => \"Qmb\", \"stakedTokens\" => 20),\n Dict(\"ipfsHash\" => \"Qma\", \"stakedTokens\" => 10),\n Dict(\"ipfsHash\" => \"Qmc\", \"stakedTokens\" => 5),\n ])\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"allocatedTokens\" => 5, \"id\" => \"0xa\"),\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qmb\", \"allocatedTokens\" => 10, \"id\" => \"0xb\"),\n ])\njulia> a, s = AllocationOpt.subtractindexer!(a, s)\n(NamedTuple[(var\"subgraphDeployment.ipfsHash\" = \"Qma\", allocatedTokens = 5, id = \"0xa\"), (var\"subgraphDeployment.ipfsHash\" = \"Qmb\", allocatedTokens = 10, id = \"0xb\")], NamedTuple[(stakedTokens = 5.0, ipfsHash = \"Qma\"), (stakedTokens = 10, ipfsHash = \"Qmb\"), (stakedTokens = 5, ipfsHash = \"Qmc\")])\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.togrt-Tuple{AbstractString}","page":"API Reference","title":"AllocationOpt.togrt","text":"togrt(x::AbstractString)\n\nConvert x to GRT.\n\nnote: Note\nThis function is meant to be used with freshly queried data, so it operates on strings.\n\njulia> using AllocationOpt\njulia> AllocationOpt.togrt(\"1\")\n1.0e-18\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.totalsupply-Tuple{Val{:network}, Any}","page":"API Reference","title":"AllocationOpt.totalsupply","text":"totalsupply(::Val{:network}, x)\n\nThe total GRT supply.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( \"id\" => 1, \"totalSupply\" => 1, \"networkGRTIssuance\" => 1, \"epochLength\" => 28, \"totalTokensSignalled\" => 2, \"currentEpoch\" => 1, ) ]) julia> AllocationOpt.totalsupply(Val(:network), n) 1\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.unallocate_action-Tuple{Val{:actionqueue}, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.unallocate_action","text":"unallocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)\n\nCreate and push the unallocate actions to the action queue.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\") ]) julia> t = flextable([ Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"), ]) julia> config = Dict( \"frozenlist\" => [], \"indexerurl\" => \"http://localhost:18000\" ) julia> TheGraphData.client!(config[\"indexerurl\"]) julia> AllocationOpt.unallocate_action(Val(:actionqueue), a, t, config) 1-element Vector{Dict{String, Any}}: Dict(\"priority\" => 0, \"status\" => AllocationOpt.queued, \"allocationID\" => \"0xa\", \"source\" => \"AllocationOpt\", \"reason\" => \"AllocationOpt\", \"type\" => AllocationOpt.unallocate, \"deploymentID\" => \"Qma\")\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.unallocate_action-Tuple{Val{:none}, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.unallocate_action","text":"unallocate_action(::Val{:none}, a, t, config)\n\nDo nothing.\n\njulia> using AllocationOpt\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> t = flextable([\n Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"),\n Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"),\n ])\njulia> AllocationOpt.unallocate_action(Val(:none), a, t, Dict())\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.unallocate_action-Tuple{Val{:rules}, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.unallocate_action","text":"unallocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)\n\nPrint a rule that stops old allocations that the optimiser has not chosen and that aren't frozen.\n\njulia> using AllocationOpt\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> t = flextable([\n Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"),\n ])\njulia> AllocationOpt.unallocate_action(Val(:rules), a, t, Dict(\"frozenlist\" => []))\ngraph indexer rules stop Qma\n1-element Vector{String}:\n \"\u001b[0mgraph indexer rules stop Qma\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.write-Tuple{TypedTables.FlexTable, TypedTables.FlexTable, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.write","text":"write(i::FlexTable, a::FlexTable, s::FlexTable, n::FlexTable, config::AbstractDict)\n\nWrite the tables to the writedir specified in the config.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> config = Dict(\"verbose\" => true, \"writedir\" => \"datadir\")\njulia> t = flextable([\n Dict(\"ipfsHash\" => \"Qma\", \"signalledTokens\" => \"1\"),\n Dict(\"ipfsHash\" => \"Qmb\", \"signalledTokens\" => \"2\"),\n ])\njulia> i, a, s, n = repeat([t,], 4)\njuila> AllocationOpt.write(i, a, s, n, config)\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.writejson-Tuple{AbstractString, AbstractDict}","page":"API Reference","title":"AllocationOpt.writejson","text":"function writejson(results::AbstractString, config::AbstractDict)\n\nWrite the optimized results to the writedir specified in the config.\n\njulia> Using AllocationOpt\njulia> results = \"{\"strategies\":[{\"num_allocations\":2,\"profit\":6.0,\"allocations\":[{\"allocationAmount\":2.5,\"profit\":3.0,\"deploymentID\":\"Qma\"},{\"allocationAmount\":2.5,\"profit\":3.0,\"deploymentID\":\"Qmb\"}]},{\"num_allocations\":1,\"profit\":5.0,\"allocations\":[{\"allocationAmount\":5.0,\"profit\":5.0,\"deploymentID\":\"Qma\"}]}]}\"\njulia> config = Dict{\"writedir\" => \".\"}\njulia> AllocationOpt.writejson(results, config)\n\n\n\n\n\n","category":"method"},{"location":"api/#SemioticOpt.iteration-Tuple{Function, AllocationOpt.AnalyticOpt}","page":"API Reference","title":"SemioticOpt.iteration","text":"iteration(f::Function, a::AnalyticOpt)\n\nPerform the analytic optimisation.\n\n\n\n\n\n","category":"method"},{"location":"api/#SemioticOpt.x!-Tuple{AllocationOpt.AnalyticOpt, Any}","page":"API Reference","title":"SemioticOpt.x!","text":"x!(a::AnalyticOpt, v)\n\nIn-place setting of a.x to v\n\nSee SemioticOpt.x.\n\n\n\n\n\n","category":"method"},{"location":"api/#SemioticOpt.x-Tuple{AllocationOpt.AnalyticOpt}","page":"API Reference","title":"SemioticOpt.x","text":"x(a::AnalyticOpt)\n\nReturn the current best guess for the solution.\n\n\n\n\n\n","category":"method"},{"location":"output/#Understanding-The-Output","page":"Understanding The Output","title":"Understanding The Output","text":"","category":"section"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"After a successful run, the Allocation Optimizer will produce a JSON output in your writedir under the name report.json. Let's walk through how to read this file.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"This report contains the various strategies that the Allocation Optimizer recommends based on the network state and your config file. The num_reported_options field in your config will determine the maximum number of outputs in the report.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"Let's break down the following example report.json","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"{\n \"strategies\": [\n {\n \"num_allocations\":2,\n \"profit\":229779.02830650925,\n \"allocations\": [\n {\n \"allocationAmount\":\"13539706.9\",\n \"profit\":169430.57951963632,\n \"deploymentID\":\"QmT2Y7SHXGRt7EKXzFPYMjnrgX64PQr86EjbsHoDLNzwLy\"\n },\n {\n \"allocationAmount\":\"9194401.2\",\n \"profit\":60348.44878687295,\n \"deploymentID\":\"QmXT4PhR9pwAUqkxg6tgqR8xWUsTYN7V8UgmqhrrimcqXf\"\n }\n ]\n },\n {\n \"num_allocations\":1,\n \"profit\":190114.2718246217,\n \"allocations\": [\n {\n \"allocationAmount\":\"22734108.1\",\n \"profit\":190114.2718246217,\n \"deploymentID\":\"QmT2Y7SHXGRt7EKXzFPYMjnrgX64PQr86EjbsHoDLNzwLy\"\n }\n ]\n }\n ]\n}","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"which the Optimizer generated from the following config.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nreaddir = \"data\"\nmax_allocations = 2\nwhitelist = []\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = true\nnum_reported_options = 2\nexecution_mode = \"rules\"","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"note: Note\nIf you use this same config, you could get a slightly different report depending on the network state.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"The JSON has two strategies. They are sorted by the one with the highest expected profit appearing first. In the first one here, we have two allocations, which you could see from the num_allocations field, or by counting the number of entries under the allocations field. At the top level of each strategy, profit describes the total expected profit in GRT for all allocations.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"warning: Warning\nNotice in the config file that our allocation lifetime was 28 epochs. The profit is over that lifetime. However, it is impossible for us to know how the network state will evolve in the future. All results from the Optimizer assume that the network state will remain static. As a result, you should take these numbers with a grain of salt and use your knowledge as an indexer to determine whether the Optimizer's strategy could be tweaked in your favour.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"Then, we go into the allocations. Each entry in this list contains the amount of GRT the strategy wants you to stake, the expected profit of this allocation, and the subgraph deployment ID onto which you should make this allocation.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"In addition to the report.json, since we specified execution_mode as \"rules\" in the config, the Optimizer will print out indexer rules that you can run to execute the best strategy. In our case,","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"graph indexer rules stop QmNoe4VQFSKAC3uiq48UQASg4QeqFVSKYYGwnxNjNi6GYX\ngraph indexer rules stop QmRDGLp6BHwiH9HAE2NYEE3f7LrKuRqziHBv76trT4etgU\ngraph indexer rules stop QmUVskWrz1ZiQZ76AtyhcfFDEH1ELnRpoyEhVL8p6NFTbR\ngraph indexer rules stop QmXZiV6S13ha6QXq4dmaM3TB4CHcDxBMvGexSNu9Kc28EH\ngraph indexer rules stop QmYN4ofRb5CUg1WdpLhhNTVCuiiAt29hBKGjTnnxYh9zYt\ngraph indexer rules stop Qmaz1R8vcv9v3gUfksqiS9JUz7K9G8S5By3JYn8kTiiP5K\ngraph indexer rules stop QmcBSr5R3K2M5tk8qeHFaX8pxAhdViYhcKD8ZegYuTcUhC\ngraph indexer rules set QmT2Y7SHXGRt7EKXzFPYMjnrgX64PQr86EjbsHoDLNzwLy decisionBasis always allocationAmount 13539706.9\ngraph indexer rules set QmXT4PhR9pwAUqkxg6tgqR8xWUsTYN7V8UgmqhrrimcqXf decisionBasis always allocationAmount 9194401.2","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"If instead you use \"actionqueue\" as the execution_mode, the Optimizer will populate your instance of the action queue.","category":"page"},{"location":"provided-binary/#Using-The-Provided-Binary","page":"Using The Provided Binary","title":"Using The Provided Binary","text":"","category":"section"},{"location":"provided-binary/","page":"Using The Provided Binary","title":"Using The Provided Binary","text":"Using the provided binary has the advantage of being that only method that doesn't require that you use the Julia runtime. If you want to get running as quickly as possible, this is the path for you.","category":"page"},{"location":"provided-binary/","page":"Using The Provided Binary","title":"Using The Provided Binary","text":"note: Note\nWe only release binaries for x86 Linux.","category":"page"},{"location":"provided-binary/","page":"Using The Provided Binary","title":"Using The Provided Binary","text":"All you have to do is download the binary for the platform and release you want to use, unzip it, set up your configuration (Configuration) file, and run the binary from your terminal.","category":"page"},{"location":"provided-binary/","page":"Using The Provided Binary","title":"Using The Provided Binary","text":"./path/to/unzipped/folder/bin/AllocationOpt /path/to/your_config.toml","category":"page"},{"location":"calling-another/#Calling-From-Another-Language","page":"Calling From Another Language","title":"Calling From Another Language","text":"","category":"section"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"It's possible to call the Allocation Optimizer from another language. There are already some solutions out there that do this. In general, if you're going to take this approach, we assume that you know what you're doing. We won't hold your hand through the process as we don't want to officially support a multitude of different languages. Instead, we'll point you to resources you can use for various languages.","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"warning: Warning\nWe don't recommend you use this approach, as you may have to delay integrating bugfixes and new features while you are figuring out how to integrate the new code. People using the mainline routes will always be able to more quickly access the updates we push. We especially don't recommend this route if you're not a developer. We will not support bugs that arise from integrating the tool into third-party scripts.","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"C/C++\nPython\nRust","category":"page"},{"location":"calling-another/#Under-The-Hood","page":"Calling From Another Language","title":"Under The Hood","text":"","category":"section"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"Before we let you go, we'll explain at a high-level the main function. Roughly speaking, we can break down this problem into the following steps.","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"Read the data, where from the network subgraph or from local CSVs. The currency used is GRT.\nFilter the data based on the whitelist, blacklist, pinnedlist, and frozenlist\nGet the values we care about for the indexing rewards","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"σ - The indexer's stake\nΩ - A vector of floats containing the sum of the allocations of all other indexers on each subgraph in our data\nψ - A vector of floats representing the signal on each subgraph in our data.\nΨ - A float representing the total signal in the network\nK - The maximum number of new allocations\ng - The gas cost in GRT","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"Get the optimal allocation vectors for each k ∈ 1,...,K\nSort these by their profit\nReport information about the most profitable vectors.","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"The full code for the main function with comments follows.","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"function main(config::Dict)\n # Read data\n i, a, s, n = AllocationOpt.read(config)\n\n # Write the data if it was queried rather than read from file\n isnothing(config[\"readdir\"]) && write(i, a, s, n, config)\n\n # Get the subgraphs on which we can allocate\n fs = allocatablesubgraphs(s, config)\n\n # Get the indexer stake\n pinnedvec = pinned(fs, config)\n σpinned = pinnedvec |> sum\n σ = availablestake(Val(:indexer), i) - frozen(a, config) - σpinned\n @assert σ > 0 \"No stake available to allocate with the configured frozenlist and pinnedlist\"\n\n # Allocated tokens on filtered subgraphs\n Ω = stake(Val(:subgraph), fs) .+ fudgefactor\n\n # Signal on filtered subgraphs\n ψ = signal(Val(:subgraph), fs)\n\n # Signal on all subgraphs\n Ψ = signal(Val(:network), n)\n\n # New tokens issued over allocation lifetime\n Φ = newtokenissuance(n, config)\n\n # Get max number of allocations\n K = min(config[\"max_allocations\"], length(fs))\n\n # Get gas cost in GRT\n g = config[\"gas\"]\n\n # Get optimal values\n config[\"verbose\"] && @info \"Optimizing\"\n xs, nonzeros, profitmatrix = optimize(Ω, ψ, σ, K, Φ, Ψ, g)\n\n # Add the pinned stake back in\n xs .= xs .+ pinnedvec\n\n # Ensure that the indexer stake is not exceeded\n σmax = σ + σpinned\n for x in sum(xs; dims=1)\n x ≤ σmax || error(\"Tried to allocate more stake than is available\")\n end\n\n # Write the result values\n # Group by unique number of nonzeros\n groupixs = groupunique(nonzeros)\n groupixs = Dict(keys(groupixs) .=> values(groupixs))\n\n config[\"verbose\"] && @info \"Writing results report\"\n # For each set of nonzeros, find max profit (should be the same other than rounding)\n popts = bestprofitpernz.(values(groupixs), Ref(profitmatrix)) |> sortprofits!\n nreport = min(config[\"num_reported_options\"], length(popts))\n\n # Create JSON string\n strategies =\n strategydict.(popts[1:nreport], Ref(xs), Ref(nonzeros), Ref(fs), Ref(profitmatrix))\n reportdata = JSON.json(Dict(\"strategies\" => strategies))\n\n # Write JSON string to file\n writejson(reportdata, config)\n\n config[\"verbose\"] && @info \"Executing best strategy\"\n # Use config for using actionqueue or rules with the top profit batch\n ix = first(popts)[:index]\n execute(a, ix, fs, xs, profitmatrix, config)\n\n return nothing\nend","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"For details on any of the specific functions called, look at the API Reference.","category":"page"},{"location":"contributing/#Contributing","page":"Contributing","title":"Contributing","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"We're excited you are interested in contributing! Please follow the standards put forth in ColPrac to contribute to the Allocation Optimizer.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Most importantly, we'd like to emphasise a few points.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"PRs should do a single thing.\nWe'd prefer that you submit ten small PRs that are easy to understand as compared with one massive PR that requires a full day of review.\nPRs should add tests which cover the new or fixed functionality.\nPRs introducing breaking changes should make this clear when opening the PR.","category":"page"},{"location":"build-a-binary/#Build-Your-Own-Binary","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"","category":"section"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Compiling the binary yourself is an excellent way to use the Allocation Optimizer. You should use this route if a couple of reasons speak to you.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"You'd prefer not to trust a random binary off the internet.\nYou have added your own features to the Allocation Optimizer, but would prefer the large, one-time cost of AOT compilation as opposed the small, every-time cost of JIT compilation.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"In this documentation, we'll take you through the process of generating an app binary.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"note: Note\nYou can instead compile to a sysimage or to a library, but we don't natively support those ourselves. Look through the PackageCompiler documentation for steps if you would prefer one of those options..","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Install Julia! We prefer to use juliaup. You can install this via:","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"curl -fsSL https://install.julialang.org | sh","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"note: Note\nAs of writing this documentation, the latest version of Julia is v1.8. This the version the Allocation Optimizer currently uses, and the version juliaup will install by default. If juliaup begins to use v1.9, then you may need to use juliaup to manually install v1.8 via juliaup add 1.8. Then, you can either set the default to be v1.8 using juliaup default 1.8, or you can replace every time you see julia with julia +1.8 below.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Clone this repository and cd into it.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"git clone https://github.com/graphprotocol/allocation-optimizer.git\ncd allocation-optimizer","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Start Julia.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"julia --project","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Install the dependencies","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"julia> ]\npkg> instantiate","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Install a C-compiler such as GCC or Clang.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"From the Julia REPL (the TUI that comes up when you use julia --project), compile your app.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"julia> using PackageCompiler\njulia> create_app(\".\", \"app\")","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"note: Note\nIf you are still in Pkg mode, pkg>, hitting backspace will bring you back into the REPL.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Set up your configuration file. See Configuration for details.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Run the binary pointing at the configuration TOML that you would like to use.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"./app/bin/AllocationOpt /path/to/your_config.toml","category":"page"},{"location":"call-julia/#Calling-From-Julia","page":"Calling From Julia","title":"Calling From Julia","text":"","category":"section"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"If you're okay with having the Julia runtime on your computer, and you don't mind the precompilation time, this is the preferred way to run the Allocation Optimizer. In part, this is because access the to Julia runtime will enable you to add your own features if you'd like. You can even (hopefully) even submit some PRs with features to help other indexers! Compiling on your machine also allows Julia to specialise on idiosyncrasies of your hardware. For example, if your CPU supports AVX-512, Julia will use those instructions to speed up your code beyond what the generic binary might give you. Again, the trade-off here is that you'll have to eat the precompilation time the first time you run the code after you start a new Julia session.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"That said, here's how to install and use the Allocation Optimizer from Julia.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"Install Julia! We prefer to use juliaup. You can install this via:","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"curl -fsSL https://install.julialang.org | sh","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"note: Note\nAs of writing this documentation, the latest version of Julia is v1.8. This the version the Allocation Optimizer currently uses, and the version juliaup will install by default. If juliaup begins to use v1.9, then you may need to use juliaup to manually install v1.8 via juliaup add 1.8. Then, you can either set the default to be v1.8 using juliaup default 1.8, or you can replace every time you see julia with julia +1.8 below.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"Clone this repository and cd into it.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"git clone https://github.com/graphprotocol/allocation-optimizer.git\ncd allocation-optimizer","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"Start Julia.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"julia --project","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"Install the dependencies","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"julia> ]\npkg> instantiate","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"Set up your configuration file. See Configuration for details.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"From the Julia REPL (the TUI that comes up when you use julia --project), run the main function with the path to your config.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"julia> using AllocationOpt\njulia> path = \"config.toml\" # path to your config file\njulia> AllocationOpt.main(path)","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"note: Note\nIf you are still in Pkg mode, pkg>, hitting backspace will bring you back into the REPL.","category":"page"},{"location":"configuration/#Configuration","page":"Configuration","title":"Configuration","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"When using the optimiser, you change it's behaviour via a configuration file specified as a TOML. The configuration file serves two purposes. Firstly, it makes it easier for you to track various settings and their impacts. Secondly, if something breaks, it makes it easier for us to reproduce what went wrong.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"An example configuration TOML file might look as below.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nreaddir = \"data\"\nmax_allocations = 10\nwhitelist = []\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = true\nnum_reported_options = 2\nexecution_mode = \"none\"\nopt_mode = \"fast\"","category":"page"},{"location":"configuration/#Detailed-Field-Descriptions","page":"Configuration","title":"Detailed Field Descriptions","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id::String: The ID of the indexer for whom we're optimising. No default value.\nnetwork_subgraph_endpoint::String: The network subgraph endpoint to query. The optimizer support any network (such as mainnet, goerli, arbitrum-one, arbitrum-goerli) as long as the provided API serves the query requests. If unspecified, \"https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet\"\nwritedir::String: The directory to which to write the results of optimisation. If don't specify readdir, writedir also specifies the path to which to save the input data tables. If unspecified, \".\"\nreaddir::Union{String, Nothing}: The directory from which to read saved data tables. This speeds up the process as we won't have to query the network subgraph for the relevant data. If you don't specify readdir, we will query your specified network_subgraph_endpoint for the data and write it to CSV files in writedir. This way, you can use your previous writedir as your readdir in future runs. If unspecified, nothing\nwhitelist::Vector{String}: A list of subgraph IPFS hashes that you want to consider as candidates to which to allocate. If you leave this empty, we'll assume all subgraphs are in the whitelist. If unspecified, String[]\nblacklist::Vector{String}: A list of subgraph IPFS hashes that you do not want to consider allocating to. For example, this list could include broken subgraphs or subgraphs that you don't want to index. If unspecified, String[]\nfrozenlist::Vector{String}: If you have open allocations that you don't want to change, add the corresponding subgraph IPFS hashes to this list. If unspecified, String[]\npinnedlist::Vector{String}: If you have subgraphs that you absolutely want to be allocated to, even if only with a negligible amount of GRT, add it to this list. If unspecified, String[]\nallocation_lifetime::Integer: The number of epochs for which you expect the allocations the optimiser finds to be open. If unspecified, 28\ngas::Real: The estimated gas cost in GRT to open/close allocations. If unspecified, 100\nmin_signal::Real: The minimum amount of signal in GRT that must be on a subgraph in order for you to consider allocating to it. If unspecified, 1000\nmax_allocations::Integer: The maximum number of new allocations you'd like the optimiser to consider opening. If unspecified, 10\nnum_reported_options::Integer: The number of proposed allocation strategies to report. For example, if you select 10 we'd report best 10 allocation strategies ranked by profit. Options are reported to a report.json in your writedir. If unspecified, 1\nverbose::Bool: If true, the optimiser will print details about what it is doing to stdout. If unspecified, false\nexecution_mode::String: How the optimiser should execute the allocation strategies it finds. Options are \"none\", which won't do anything, \"actionqueue\", which will push actions to the action queue, and \"rules\", which will generate indexing rules. If unspecified, \"none\"\nindexer_url::Union{String, Nothing}: The URL of the indexer management server you want to execute the allocation strategies on. If you specify \"actionqueue\", you must also specify indexer_url. If unspecified, nothing\nopt_mode::String: We support two optimisation modes. One is \"fast\". This mode is fast, but may not find the optimal allocation. This mode is also used to the top num_reported_options allocation strategies. The other mode is \"optimal\". This mode is slower, but will find the optimal allocation. In general, we recommend exploring config options using \"fast\" mode first, and then using \"optimal\" mode to find the optimal allocation. By default, \"fast\"","category":"page"},{"location":"configuration/#Example-Configurations","page":"Configuration","title":"Example Configurations","text":"","category":"section"},{"location":"configuration/#ActionQueue","page":"Configuration","title":"ActionQueue","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Set execution_mode to \"actionqueue\" and provide an indexer_url.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nreaddir = \"data\"\nmax_allocations = 10\nwhitelist = []\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = true\nnum_reported_options = 2\nexecution_mode = \"actionqueue\"\nindexer_url = \"https://localhost:8000\"","category":"page"},{"location":"configuration/#Indexer-Rules","page":"Configuration","title":"Indexer Rules","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Change execution_mode to \"rules\".","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nreaddir = \"data\"\nmax_allocations = 10\nwhitelist = []\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = true\nnum_reported_options = 2\nexecution_mode = \"rules\"","category":"page"},{"location":"configuration/#Query-data-Instead-of-Reading-Local-CSVs","page":"Configuration","title":"Query data Instead of Reading Local CSVs","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Just don't specify the readdir.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nmax_allocations = 10\nwhitelist = []\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = true\nnum_reported_options = 2\nexecution_mode = \"none\"","category":"page"},{"location":"configuration/#Query-data-for-specified-networks","page":"Configuration","title":"Query data for specified networks","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Specify the network subgraph endpoint for networks other than The Graph network on Ethereum mainnet. Here we use the endpoint to goerli network subgraph.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xE9a1CABd57700B17945Fd81feeFba82340D9568F\"\nnetwork_subgraph_endpoint = \"https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-goerli\"","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Other available endpoints examples are","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Mainnet (default): https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet\nArbitrum-One: https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-arbitrum\nArbitrum-Goerli: https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-arbitrum-goerli","category":"page"},{"location":"configuration/#Quiet-Mode","page":"Configuration","title":"Quiet Mode","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"We set verbose to false here to surpress info messages.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nreaddir = \"data\"\nmax_allocations = 10\nwhitelist = []\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = false\nnum_reported_options = 2\nexecution_mode = \"none\"","category":"page"},{"location":"configuration/#Whitelisting-Subgraphs","page":"Configuration","title":"Whitelisting Subgraphs","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Add some subgraph deployment IDs to the whitelist. If, in addition or instead you want to use blacklist, frozenlist, or pinnedlist, you can similarly add subgraph deployment IDs to those lists. Notice that we did not change max_allocations here. If max_allocations exceeds the number of available subgraphs (2 in this case), the code will treat the number of available subgraphs as max_allocations.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nreaddir = \"data\"\nmax_allocations = 10\nwhitelist = [\n \"QmUVskWrz1ZiQZ76AtyhcfFDEH1ELnRpoyEhVL8p6NFTbR\",\n \"QmcBSr5R3K2M5tk8qeHFaX8pxAhdViYhcKD8ZegYuTcUhC\"\n]\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = false\nnum_reported_options = 2\nexecution_mode = \"none\"","category":"page"}] +[{"location":"","page":"Home","title":"Home","text":"CurrentModule = AllocationOpt","category":"page"},{"location":"#The-Allocation-Optimizer","page":"Home","title":"The Allocation Optimizer","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"This repository contains the code for the Indexer Allocation Optimizer. The goal of this project is to enable indexers to quickly determine how to allocate so as to maximise their indexing rewards.","category":"page"},{"location":"","page":"Home","title":"Home","text":"warning: Warning\nWe do not optimise for query fees directly, as we expect signal on a subgraph to be proportional to the query fees, as was the intention behind curation. Query fee information is also not public. It is local to each gateway. As a result, we will never be able to optimise with respect to query fees unless this changes.","category":"page"},{"location":"","page":"Home","title":"Home","text":"note: Note\nBy default, opt_mode=\"fast\". Fast-mode is not guaranteed to converge to a global optimum. If you get strange results, you should try opt_mode=\"optimal\". This mode is still experimental, and will take longer to run, but you may get more reasonable results with it.","category":"page"},{"location":"","page":"Home","title":"Home","text":"We will focus on usage of the code in this documentation. We refer you to these blog posts for more technical details. We also plan to post a yellowpaper at some point diving into our approach in even more detail. Stay tuned for that! If interested in how the code works, take a peek Under The Hood!","category":"page"},{"location":"","page":"Home","title":"Home","text":"There are a few different ways you can run the allocation optimizer.","category":"page"},{"location":"","page":"Home","title":"Home","text":"Using The Provided Binary\nCalling From Julia\nBuild Your Own Binary\nCalling From Another Language","category":"page"},{"location":"bugs/#Reporting-Bugs","page":"Reporting Bugs","title":"Reporting Bugs","text":"","category":"section"},{"location":"bugs/","page":"Reporting Bugs","title":"Reporting Bugs","text":"If something breaks, we hope you'll submit a bug report! There are a few things we'll need from you to reproduce the failure mode you're experiencing.","category":"page"},{"location":"bugs/","page":"Reporting Bugs","title":"Reporting Bugs","text":"Your config file\nThe CSVs (if any) that the Optimizer saved.\nThe stacktrace displaying the error message.\nThe version of the Allocation Optimizer you are running.","category":"page"},{"location":"bugs/","page":"Reporting Bugs","title":"Reporting Bugs","text":"These are a good place to start. We may ask you for more information as we investigate the bug.","category":"page"},{"location":"api/#API-Reference","page":"API Reference","title":"API Reference","text":"","category":"section"},{"location":"api/","page":"API Reference","title":"API Reference","text":"Modules = [AllocationOpt]","category":"page"},{"location":"api/#AllocationOpt.AnalyticOpt","page":"API Reference","title":"AllocationOpt.AnalyticOpt","text":"AnalyticOpt{\n T<:Real,\n V<:AbstractArray{T},\n U<:AbstractArray{T},\n A<:AbstractArray{T},\n S<:AbstractVector{<:Hook},\n} <: SemioticOpt.OptAlgorithm\n\nOptimise the indexing reward analytically.\n\nFields\n\nx::V is the current best guess for the solution. Typically zeros.\nΩ::U is the allocation vector of other indexers.\nψ::A is the signal vector.\nσ::T is the stake.\nhooks::S are the hooks\n\nExample\n\njulia> using AllocationOpt\njulia> using SemioticOpt\njulia> x = zeros(2)\njulia> Ω = [1.0, 1.0]\njulia> ψ = [10.0, 10.0]\njulia> σ = 5.0\njulia> alg = AllocationOpt.AnalyticOpt(;\n x=x, Ω=Ω, ψ=ψ, σ=σ, hooks=[StopWhen((a; kws...) -> kws[:i] > 1)]\n )\njulia> f = x -> x # This doesn't matter. `f` isn't used by the algorithm.\njulia> alg = minimize!(f, alg)\njulia> SemioticOpt.x(alg)\n2-element Vector{Float64}:\n 2.5\n 2.5\n\n\n\n\n\n","category":"type"},{"location":"api/#AllocationOpt.allocatablesubgraphs-Tuple{TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.allocatablesubgraphs","text":" allocatablesubgraphs(s::FlexTable, config::AbstractDict)\n\nFor the subgraphs s return a view of the subgraphs on which we can allocate.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> s = flextable([\n Dict(\"ipfsHash\" => \"Qma\", \"signalledTokens\" => 10,),\n Dict(\"ipfsHash\" => \"Qmb\", \"signalledTokens\" => 20),\n Dict(\"ipfsHash\" => \"Qmc\", \"signalledTokens\" => 5),\n ])\njulia> config = Dict(\n \"whitelist\" => String[\"Qmb\", \"Qmc\"],\n \"blacklist\" => String[],\n \"frozenlist\" => String[],\n \"pinnedlist\" => String[],\n \"min_signal\" => 0.0\n)\njulia> fs = AllocationOpt.allocatablesubgraphs(s, config)\nFlexTable with 2 columns and 2 rows:\n signalledTokens ipfsHash\n ┌──────────────────────────\n 1 │ 20 Qmb\n 2 │ 5 Qmc\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.allocate_action-Tuple{Val{:actionqueue}, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.allocate_action","text":"allocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)\n\nCreate and push allocate actions to the action queue.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> t = flextable([\n Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"),\n Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"),\n])\njulia> config = Dict(\n \"indexer_url\" => \"http://localhost:18000\"\n)\njulia> TheGraphData.client!(config[\"indexer_url\"])\njulia> AllocationOpt.allocate_action(Val(:actionqueue), a, t, Dict())\n1-element Vector{Dict{String, Any}}:\n Dict(\"amount\" => \"2\", \"priority\" => 0, \"status\" => AllocationOpt.queued, \"source\" => \"AllocationOpt\", \"reason\" => \"Expected profit: 0\", \"type\" => AllocationOpt.allocate, \"deploymentID\" => \"Qmb\")\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.allocate_action-Tuple{Val{:none}, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.allocate_action","text":"allocate_action(::Val{:none}, a, t, config)\n\nDo nothing.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> t = flextable([\n Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"),\n Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"),\n ])\njulia> AllocationOpt.allocate_action(Val(:none), a, t, Dict())\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.allocate_action-Tuple{Val{:rules}, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.allocate_action","text":"allocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)\n\nPrint the rules that allocates to new subgraphs.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\") ]) julia> t = flextable([ Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"), Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"), ]) julia> AllocationOpt.allocate_action(Val(:rules), a, t, Dict()) graph indexer rules set Qmb decisionBasis always allocationAmount 2 1-element Vector{String}: \"\u001b[0mgraph indexer rules set Qmb decisionBasis always allocationAmount 2\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.aquery-Tuple{AbstractString}","page":"API Reference","title":"AllocationOpt.aquery","text":"aquery(id::AbstractString)\n\nReturn the components of a GraphQL query for active allocations of indexer id.\n\nFor use with the TheGraphData.jl package.\n\njulia> using AllocationOpt\njulia> id = \"0xa\"\njulia> value, args, fields = AllocationOpt.aquery(id)\n(\"allocations\", Dict{String, Union{Dict{String, String}, String}}(\"where\" => Dict(\"status\" => \"Active\", \"indexer\" => \"0xa\")), [\"allocatedTokens\", \"id\", \"subgraphDeployment{ipfsHash}\"])\n\nExtended Help\n\nYou can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.availablestake-Tuple{Val{:indexer}, Any}","page":"API Reference","title":"AllocationOpt.availablestake","text":"available(::Val{:indexer}, x)\n\nThe tokens available for the indexer to allocate in table x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"stakedTokens\" => 10,\n \"delegatedTokens\" => 20,\n \"lockedTokens\" => 5,\n ),\n])\njulia> AllocationOpt.availablestake(Val(:indexer), x)\n25.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.bestprofitpernz-Union{Tuple{S}, Tuple{T}, Tuple{AbstractVector{T}, AbstractMatrix{S}}} where {T<:Integer, S<:Real}","page":"API Reference","title":"AllocationOpt.bestprofitpernz","text":"bestprofitpernz(ixs::AbstractVector{Integer}, profitmatrix::AbstractMatrix{Real})\n\nCompute the best profit amongst the given ixs given profit matrix p\n\njulia> using AllocationOpt\njulia> ixs = Dict([1] => [1], [2] => [2])\njulia> profitmatrix = [[2.5 5.0]; [2.5 1.0]]\njulia> AllocationOpt.bestprofitpernz.(values(ixs), Ref(profitmatrix))\n2-element Vector{NamedTuple{(:profit, :index), Tuple{Float64, Int64}}}:\n (profit = 5.0, index = 1)\n (profit = 6.0, index = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.blockissuance-Tuple{Val{:network}, Any}","page":"API Reference","title":"AllocationOpt.blockissuance","text":"blockissuance(::Val{:network}, x)\n\nThe tokens issued per block.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( \"id\" => 1, \"totalSupply\" => 1, \"networkGRTIssuance\" => 1, \"epochLength\" => 28, \"totalTokensSignalled\" => 2, \"currentEpoch\" => 1, ) ]) julia> AllocationOpt.blockissuance(Val(:network), n) 1\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.blocksperepoch-Tuple{Val{:network}, Any}","page":"API Reference","title":"AllocationOpt.blocksperepoch","text":"blocksperepoch(::Val{:network}, x)\n\nThe number of blocks in each epoch.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( \"id\" => 1, \"totalSupply\" => 1, \"networkGRTIssuance\" => 1, \"epochLength\" => 28, \"totalTokensSignalled\" => 2, \"currentEpoch\" => 1, ) ]) julia> AllocationOpt.blocksperepoch(Val(:network), n) 28\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.closeipfs-Tuple{Any, Any, Any}","page":"API Reference","title":"AllocationOpt.closeipfs","text":"closeipfs(existingipfs, proposedipfs, frozenlist)\n\nGet the list of the ipfs hashes of allocations to close.\n\njulia> using AllocationOpt\njulia> AllocationOpt.closeipfs([\"Qma\"], [\"Qmb\"], String[])\n1-element Vector{String}:\n \"Qma\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.configuredefaults!-Tuple{AbstractDict}","page":"API Reference","title":"AllocationOpt.configuredefaults!","text":"configuredefaults!(config::AbstractDict)\n\nSet default values for the config dictionary if the value was not specified in the config file.\n\nConfig Specification\n\nid::String: The ID of the indexer for whom we're optimising. No default value.\nnetwork_subgraph_endpoint::String: The network subgraph endpoint to query. By default, \"https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet\"\nwritedir::String: The directory to which to write the results of optimisation. If don't specify readdir, writedir also specifies the path to which to save the input data tables. By default, \".\"\nreaddir::Union{String, Nothing}: The directory from which to read saved data tables. This speeds up the process as we won't have to query the network subgraph for the relevant data. If you don't specify readdir, we will query your specified network_subgraph_endpoint for the data and write it to CSV files in writedir. This way, you can use your previous writedir as your readdir in future runs. By default, nothing\nwhitelist::Vector{String}: A list of subgraph IPFS hashes that you want to consider as candidates to which to allocate. If you leave this empty, we'll assume all subgraphs are in the whitelist. By default, String[]\nblacklist::Vector{String}: A list of subgraph IPFS hashes that you do not want to consider allocating to. For example, this list could include broken subgraphs or subgraphs that you don't want to index. By default, String[]\nfrozenlist::Vector{String}: If you have open allocations that you don't want to change, add the corresponding subgraph IPFS hashes to this list. By default, String[]\npinnedlist::Vector{String}: If you have subgraphs that you absolutely want to be allocated to, even if only with a negligible amount of GRT, add it to this list. By default, String[]\nallocation_lifetime::Integer: The number of epochs for which you expect the allocations the optimiser finds to be open. By default, 28\ngas::Real: The estimated gas cost in GRT to open/close allocations. By default, 100\nmin_signal::Real: The minimum amount of signal in GRT that must be on a subgraph in order for you to consider allocating to it. By default, 1000\nmax_allocations::Integer: The maximum number of new allocations you'd like the optimiser to consider opening. By default, 10\nnum_reported_options::Integer: The number of proposed allocation strategies to report. For example, if you select 10 we'd report best 10 allocation strategies ranked by profit. By default, 1\nverbose::Bool: If true, the optimiser will print details about what it is doing to stdout. By default, false\nexecution_mode::String: How the optimiser should execute the allocation strategies it finds. Options are \"none\", which won't do anything, \"actionqueue\", which will push actions to the action queue, and \"rules\", which will generate indexing rules. By default, \"none\"\nindexer_url::Union{String, Nothing}: The URL of the indexer management server you want to execute the allocation strategies on. If you specify \"actionqueue\", you must also specify indexer_url. By default, nothing\nopt_mode::String: We support two optimisation modes. One is \"fast\". This mode is fast, but may not find the optimal strategy. This mode is also used to the top num_reported_options allocation strategies. The other mode is \"optimal\". This mode is slower, but it satisfy stronger optimality conditions. It will find strategies at least as good as \"fast\", but not guaranteed to be better. In general, we recommend exploring config options using \"fast\" mode first, and then using \"optimal\" mode to find the optimal allocation. By default, \"optimal\"\n\njulia> using AllocationOpt\njulia> config = Dict{String, Any}(\"id\" => \"0xa\")\njulia> config = AllocationOpt.configuredefaults!(config)\nDict{String, Any} with 16 entries:\n \"execution_mode\" => \"none\"\n \"readdir\" => nothing\n \"writedir\" => \".\"\n \"num_reported_options\" => 1\n \"id\" => \"0xa\"\n \"pinnedlist\" => String[]\n \"indexer_url\" => nothing\n \"gas\" => 100\n \"allocation_lifetime\" => 28\n \"blacklist\" => String[]\n \"verbose\" => false\n \"min_signal\" => 1000\n \"network_subgraph_endpoint\" => \"https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet\"\n \"whitelist\" => String[]\n ⋮ => ⋮\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.correcttypes!-NTuple{4, TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.correcttypes!","text":"correcttypes!(i::FlexTable, a::FlexTable, s::FlexTable, n::FlexTable)\n\nConvert all tables to be in GRT.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> i = flextable([\n Dict(\n \"stakedTokens\" => \"1\",\n \"delegatedTokens\" => \"0\",\n \"id\" => \"0xa\",\n \"lockedTokens\" => \"0\",\n ),\n])\njulia> s = flextable([\n Dict(\n \"stakedTokens\" => \"1\",\n \"signalledTokens\" => \"0\",\n \"ipfsHash\" => \"Qma\",\n ),\n])\njulia> a = flextable([\n Dict(\n \"allocatedTokens\" => \"1\",\n \"subgraphDeployment.ipfsHash\" => \"Qma\",\n ),\n])\njulia> n = flextable([\n Dict(\n \"id\" => 1,\n \"totalSupply\" => \"1\",\n \"networkGRTIssuance\" => \"1\",\n \"epochLength\" => 28,\n \"totalTokensSignalled\" => \"2\",\n \"currentEpoch\" => 1,\n )\n])\njulia> i, a, s, n = AllocationOpt.correcttypes!(i, a, s, n)\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.correcttypes!-Tuple{Val{:allocation}, TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.correcttypes!","text":"correcttypes!(::Val{:allocation}, a::FlexTable)\n\nConvert the string currency fields in the allocation table to be in GRT.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\n \"allocatedTokens\" => \"1\",\n \"subgraphDeployment.ipfsHash\" => \"Qma\",\n ),\n])\njulia> AllocationOpt.correcttypes!(Val(:allocation), a)\nFlexTable with 2 columns and 1 row:\n subgraphDeployment.ipfsHash allocatedTokens\n ┌─────────────────────────────────────────────\n 1 │ Qma 1.0e-18\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.correcttypes!-Tuple{Val{:indexer}, TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.correcttypes!","text":"correcttypes!(::Val{:indexer}, i::FlexTable)\n\nConvert the string currency fields in the indexer table to be in GRT.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> i = flextable([\n Dict(\n \"stakedTokens\" => \"1\",\n \"delegatedTokens\" => \"0\",\n \"id\" => \"0xa\",\n \"lockedTokens\" => \"0\",\n ),\n])\njulia> AllocationOpt.correcttypes!(Val(:indexer), i)\nFlexTable with 4 columns and 1 row:\n stakedTokens delegatedTokens id lockedTokens\n ┌─────────────────────────────────────────────────\n 1 │ 1.0e-18 0.0 0xa 0.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.correcttypes!-Tuple{Val{:network}, TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.correcttypes!","text":"correcttypes!(::Val{:network}, n::FlexTable)\n\nConvert the string currency fields in the network table to be in GRT.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> n = flextable([\n Dict(\n \"id\" => 1,\n \"totalSupply\" => \"1\",\n \"networkGRTIssuance\" => \"1\",\n \"epochLength\" => 28,\n \"totalTokensSignalled\" => \"2\",\n \"currentEpoch\" => 1,\n )\n])\njulia> AllocationOpt.correcttypes!(Val(:network), n)\nFlexTable with 6 columns and 1 row:\n totalTokensSignalled currentEpoch totalSupply id networkGRTIssuance epochLength\n ┌─────────────────────────────────────────────────────────────────────────────────────\n 1 │ 2.0e-18 1 1.0e-18 1 1.0e-18 28\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.correcttypes!-Tuple{Val{:subgraph}, TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.correcttypes!","text":"correcttypes!(::Val{:subgraph}, s::FlexTable)\n\nConvert the string currency fields in the subgraph table to be in GRT.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> s = flextable([\n Dict(\n \"stakedTokens\" => \"1\",\n \"signalledTokens\" => \"0\",\n \"ipfsHash\" => \"Qma\",\n \"deniedAt\" => 0,\n ),\n])\njulia> AllocationOpt.correcttypes!(Val(:subgraph), s)\nFlexTable with 4 columns and 1 row:\n deniedAt stakedTokens signalledTokens ipfsHash\n ┌──────────────────────────────────────────────────\n 1 │ 0 1.0e-18 0.0 Qma\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.currentepoch-Tuple{Val{:network}, Any}","page":"API Reference","title":"AllocationOpt.currentepoch","text":"currentepoch(::Val{:network}, x)\n\nThe current epoch.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( \"id\" => 1, \"totalSupply\" => 1, \"networkGRTIssuance\" => 1, \"epochLength\" => 28, \"totalTokensSignalled\" => 2, \"currentEpoch\" => 1, ) ]) julia> AllocationOpt.currentepoch(Val(:network), n) 1\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.delegation-Tuple{Val{:indexer}, Any}","page":"API Reference","title":"AllocationOpt.delegation","text":"delegation(::Val{:indexer}, x)\n\nThe tokens delegated to the indexer in table x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"delegatedTokens\" => 10,\n ),\n])\njulia> AllocationOpt.delegation(Val(:indexer), x)\n10\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.deniedat-Tuple{Val{:subgraph}, Any}","page":"API Reference","title":"AllocationOpt.deniedat","text":"deniedat(::Val{:subgraph}, x)\n\nIf this value is non-zero, the subgraph doesn't receive indexing rewards.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\"deniedAt\" => 10,),\n Dict(\"deniedAt\" => 0,),\n])\njulia> AllocationOpt.deniedat(Val(:subgraph), x)\n2-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:\n 10\n 0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.deniedzeroixs-Tuple{TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.deniedzeroixs","text":"deniedzeroixs(s::FlexTable)\n\nFind the indices of subgraphs that have \"deniedAt\" equal to zero.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> s = flextable([\n Dict(\"ipfsHash\" => \"Qma\", \"signalledTokens\" => 5.0, \"deniedAt\" => 0),\n Dict(\"ipfsHash\" => \"Qmb\", \"signalledTokens\" => 10.0, \"deniedAt\" => 10),\n Dict(\"ipfsHash\" => \"Qmc\", \"signalledTokens\" => 15.0, \"deniedAt\" => 0),\n ])\njulia> AllocationOpt.deniedzeroixs(s)\n2-element Vector{Int64}:\n 1\n 3\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.dual-Tuple{Any, Any, Any}","page":"API Reference","title":"AllocationOpt.dual","text":"dual(Ω, ψ, σ)\n\nAnalytic solution of the dual form of the optimisation problem given signals ψ, allocation vector Ω, and stake σ.\n\nnote: Note\nYou should probably not use this function directly. Use optimizeanalytic instead.\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.execute-Union{Tuple{T}, Tuple{TypedTables.FlexTable, Integer, TypedTables.FlexTable, AbstractMatrix{T}, AbstractMatrix{T}, AbstractDict}} where T<:Real","page":"API Reference","title":"AllocationOpt.execute","text":"execute(\n a::FlexTable,\n ix::Integer,\n s::FlexTable,\n xs::AbstractMatrix{T},\n ps::AbstractMatrix{T},\n config::AbstractDict\n) where {T<:Real}\n\nExecute the actions picked by the optimiser.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> xs = [[2.5 5.0]; [2.5 0.0]]\njulia> ps = [[3.0 5.0]; [3.0 0.0]]\njulia> s = flextable([\n Dict(\"stakedTokens\" => \"1\", \"signalledTokens\" => \"0\", \"ipfsHash\" => \"Qma\"),\n Dict(\"stakedTokens\" => \"2\", \"signalledTokens\" => \"0\", \"ipfsHash\" => \"Qmb\"),\n ])\njulia> config = Dict(\"execution_mode\" => \"none\")\njulia> ix = 1\njulia> AllocationOpt.execute(a, ix, s, xs, ps, config)\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.formatconfig!-Tuple{AbstractDict}","page":"API Reference","title":"AllocationOpt.formatconfig!","text":"formatconfig!(config::AbstractDict)\n\nGiven a config, reformat values that need to be standardised.\n\njulia> using AllocationOpt\njulia> config = Dict(\"id\" => \"0xA\")\njulia> AllocationOpt.formatconfig!(config)\nDict{String, String} with 1 entry:\n \"id\" => \"0xa\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.frozen-Tuple{TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.frozen","text":"frozen(a::FlexTable, config::AbstractDict)\n\nThe frozen stake of the indexer with allocations a.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"allocatedTokens\" => 5),\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qmb\", \"allocatedTokens\" => 10),\n ])\njulia> config = Dict(\"frozenlist\" => [\"Qma\", \"Qmb\"])\njulia> AllocationOpt.frozen(a, config)\n15.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.groupunique-Tuple{AbstractVector}","page":"API Reference","title":"AllocationOpt.groupunique","text":"groupunique(x::AbstractVector)\n\nFind the indices of each unique value in x\n\njulia> using AllocationOpt\njulia> x = [1, 2, 1, 3, 2, 3]\njulia> AllocationOpt.groupunique(x)\nDict{Vector{Int64}, Vector{Int64}} with 3 entries:\n [3] => [4, 6]\n [1] => [1, 3]\n [2] => [2, 5]\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.id-Tuple{Val{:allocation}, Any}","page":"API Reference","title":"AllocationOpt.id","text":"id(::Val{:allocation}, x)\n\nGet the allocation id for each allocation in x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"id\" => \"0x1\"\n ),\n])\njulia> AllocationOpt.id(Val(:allocation), x)\n1-element view(lazystack(::Vector{Vector{String}}), 1, :) with eltype String:\n \"0x1\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.indexingreward-NTuple{5, Real}","page":"API Reference","title":"AllocationOpt.indexingreward","text":"indexingreward(x::Real, Ω::Real, ψ::Real, Φ::Real, Ψ::Real)\n\nThe indexing rewards for the allocation scalar x given signals ψ, the existing allocation on subgraphs Ω, token issuance Φ, and total signal Ψ.\n\njulia> using AllocationOpt\njulia> ψ = 0.0\njulia> Ω = 1.0\njulia> Φ = 1.0\njulia> Ψ = 2.0\njulia> x = 1.0\njulia> AllocationOpt.indexingreward(x, Ω, ψ, Φ, Ψ)\n0.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.indexingreward-Union{Tuple{I}, Tuple{T}, Tuple{AbstractArray{I}, AbstractVector{T}, AbstractVector{T}, AbstractVector{T}, Real, Real}} where {T<:Real, I<:Integer}","page":"API Reference","title":"AllocationOpt.indexingreward","text":"indexingreward(\n ixs::AbstractArray{Integer},\n x::AbstractVector{Real},\n Ω::AbstractVector{Real},\n ψ::AbstractVector{Real},\n Φ::Real,\n Ψ::Real\n)\n\nThe indexing rewards for the allocation vector x given signals ψ, the existing allocations on subgraphs Ω, token issuance Φ, and total signal Ψ. Here ixs is a vector of indices Ω, and ψ. x will be filtered by SemioticOpt, so we don't do this here.\n\njulia julia> using AllocationOpt julia> ixs = Int32[2] julia> ψ = [0.0, 1.0] julia> Ω = [1.0, 1.0] julia> Φ = 1.0 julia> Ψ = 2.0 julia> x = [0.0, 1.0] julia> AllocationOpt.indexingreward(ixs, x, Ω, ψ, Φ, Ψ) 0.25`\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.indexingreward-Union{Tuple{T}, Tuple{AbstractVector{T}, AbstractVector{T}, AbstractVector{T}, Real, Real}} where T<:Real","page":"API Reference","title":"AllocationOpt.indexingreward","text":"indexingreward(\n x::AbstractVector{Real},\n Ω::AbstractVector{Real},\n ψ::AbstractVector{Real},\n Φ::Real,\n Ψ::Real\n)\n\nThe indexing rewards for the allocation vector x given signals ψ, the existing allocations on subgraphs Ω, token issuance Φ, and total signal Ψ.\n\njulia> using AllocationOpt\njulia> ψ = [0.0, 1.0]\njulia> Ω = [1.0, 1.0]\njulia> Φ = 1.0\njulia> Ψ = 2.0\njulia> x = [0.0, 1.0]\njulia> AllocationOpt.indexingreward(x, Ω, ψ, Φ, Ψ)\n0.25\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.ipfshash-Tuple{Val{:allocation}, Any}","page":"API Reference","title":"AllocationOpt.ipfshash","text":"ipfshash(::Val{:allocation}, x)\n\nGet the ipfs hash of x when x is part of the allocation table.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"subgraphDeployment.ipfsHash\" => \"Qma\",\n ),\n])\njulia> AllocationOpt.ipfshash(Val(:allocation), x)\n1-element view(lazystack(::Vector{Vector{String}}), 1, :) with eltype String:\n \"Qma\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.ipfshash-Tuple{Val{:subgraph}, Any}","page":"API Reference","title":"AllocationOpt.ipfshash","text":"ipfshash(::Val{:subgraph}, x)\n\nGet the ipfs hash of x when x is part of the allocation table.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"ipfsHash\" => \"Qma\",\n ),\n])\njulia> AllocationOpt.ipfshash(Val(:subgraph), x)\n1-element view(lazystack(::Vector{Vector{String}}), 1, :) with eltype String:\n \"Qma\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.iquery-Tuple{AbstractString}","page":"API Reference","title":"AllocationOpt.iquery","text":"iquery(id::AbstractString)\n\nReturn the components of a GraphQL query for the stake of indexer id.\n\nFor use with the TheGraphData.jl package.\n\njulia> using AllocationOpt\njulia> id = \"0xa\"\njulia> value, args, fields = AllocationOpt.iquery(id)\n(\"indexer\", Dict{String, Union{Int64, Dict{String, String}, String}}(\"id\" => \"0xa\"), [\"delegatedTokens\", \"stakedTokens\", \"lockedTokens\"])\n\nExtended Help\n\nYou can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.lipschitzconstant-Tuple{Any, Any}","page":"API Reference","title":"AllocationOpt.lipschitzconstant","text":"lipschitzconstant(ψ, Ω)\n\nThe Lipschitz constant of the indexing reward function given signals ψ and allocations Ω.\n\njulia> using AllocationOpt\njulia> ψ = [0.0, 1.0]\njulia> Ω = [1.0, 1.0]\njulia> AllocationOpt.lipschitzconstant(ψ, Ω)\n2.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.locked-Tuple{Val{:indexer}, Any}","page":"API Reference","title":"AllocationOpt.locked","text":"locked(::Val{:indexer}, x)\n\nThe locked tokens of the indexer in table x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"lockedTokens\" => 10,\n ),\n])\njulia> AllocationOpt.locked(Val(:indexer), x)\n10\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.newtokenissuance-Tuple{TypedTables.FlexTable, Dict}","page":"API Reference","title":"AllocationOpt.newtokenissuance","text":"newtokenissuance(n::FlexTable, config::Dict)\n\nHow many new tokens are issued over the allocation lifetime given network parameters n.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> n = flextable([\n Dict(\n \"id\" => 1,\n \"totalSupply\" => 1,\n \"networkGRTIssuance\" => 2,\n \"epochLength\" => 1,\n \"totalTokensSignalled\" => 2,\n \"currentEpoch\" => 1,\n )\n ])\njulia> config = Dict(\"allocation_lifetime\" => 1)\njulia> AllocationOpt.newtokenissuance(n, config)\n1.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.nonzero-Tuple{AbstractVector}","page":"API Reference","title":"AllocationOpt.nonzero","text":"nonzero(v::AbstractVector)\n\nGet the non-zero elements of vector v.\n\njulia> using AllocationOpt\njulia> v = [0.0, 1.0]\njulia> AllocationOpt.nonzero(v)\n1-element view(::Vector{Float64}, [2]) with eltype Float64:\n 1.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.nquery-Tuple{}","page":"API Reference","title":"AllocationOpt.nquery","text":"nquery()\n\nReturn the components of a GraphQL query for network parameters.\n\nFor use with the TheGraphData.jl package.\n\njulia> using AllocationOpt\njulia> value, args, fields = AllocationOpt.nquery()\n(\"graphNetwork\", Dict(\"id\" => 1), [\"id\", \"totalSupply\", \"networkGRTIssuance\", \"epochLength\", \"totalTokensSignalled\", \"currentEpoch\"])\n\nExtended Help\n\nYou can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.optimize-Tuple{Any, Any, Any, Any, Any, Any, Any, Any, AbstractDict}","page":"API Reference","title":"AllocationOpt.optimize","text":"optimize(Ω, ψ, σ, K, Φ, Ψ, g, rixs, config::AbstractDict)\n\nFind the optimal solution vector given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas in grt g. rixs are the indices of subgraphs that are eligible to receive indexing rewards.\n\nDispatches to optimize with the opt_mode key.\n\nIf opt_mode is fast, then run projected gradient descent with GSSP and Halpern. If opt_mode is optimal, then run Pairwise Greedy Optimisation.\n\njulia> using AllocationOpt\njulia> config = Dict(\"opt_mode\" => \"fast\")\njulia> rixs = [1, 2]\njulia> Ω = [1.0, 1.0]\njulia> ψ = [10.0, 10.0]\njulia> σ = 5.0\njulia> K = 2\njulia> Φ = 1.0\njulia> Ψ = 20.0\njulia> g = 0.01\njulia> xs, nonzeros, profits = AllocationOpt.optimize(Ω, ψ, σ, K, Φ, Ψ, g, rixs, config)\n([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.optimize-Tuple{Val{:fast}, Any, Any, Any, Any, Any, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.optimize","text":"optimize(::Val{:fast}, Ω, ψ, σ, K, Φ, Ψ, g, rixs)\n\nFind the optimal vectors for k ∈ [1,K] given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas in grt g. rixs are the indices of subgraphs that are eligible to receive indexing rewards.\n\njulia> using AllocationOpt\njulia> rixs = [1, 2]\njulia> Ω = [1.0, 1.0]\njulia> ψ = [10.0, 10.0]\njulia> σ = 5.0\njulia> K = 2\njulia> Φ = 1.0\njulia> Ψ = 20.0\njulia> g = 0.01\njulia> xs, nonzeros, profits = AllocationOpt.optimize(Val(:fast), Ω, ψ, σ, K, Φ, Ψ, g, rixs)\n([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.optimize-Tuple{Val{:optimal}, Any, Any, Any, Any, Any, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.optimize","text":"optimize(::Val{:optimal}, Ω, ψ, σ, K, Φ, Ψ, g, rixs)\n\nFind the optimal solution vector given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas in grt g. rixs are the indices of subgraphs that are eligible to receive indexing rewards.\n\nExample\n\njulia> using AllocationOpt\njulia> rixs = [1, 2]\njulia> Ω = [1.0, 1.0]\njulia> ψ = [10.0, 10.0]\njulia> σ = 5.0\njulia> K = 2\njulia> Φ = 1.0\njulia> Ψ = 20.0\njulia> g = 0.01\njulia> xs, nonzeros, profits = AllocationOpt.optimize(\n Val(:optimal), Ω, ψ, σ, K, Φ, Ψ, g, rixs\n )\n([5.0 2.5; 0.0 2.5], Int32[1, 2], [0.4066666666666667 0.34714285714285714; 0.0 0.34714285714285714])\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.optimizeanalytic-Tuple{Any, Any, Any}","page":"API Reference","title":"AllocationOpt.optimizeanalytic","text":"optimizeanalytic(Ω, ψ, σ)\n\nOptimise analytically over existing allocation vector Ω, signals ψ, and stake σ.\n\njulia> using AllocationOpt\njulia> Ω = [1.0, 7.0]\njulia> ψ = [10.0, 5.0]\njulia> σ = 5.0\njulia> AllocationOpt.optimizeanalytic(Ω, ψ, σ)\n2-element Vector{Float64}:\n 3.5283092056122474\n 1.4716907943877526\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.optimizek-Tuple{Val{:fast}, Any, Any, Any, Any, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.optimizek","text":"optimizek(::Val{:fast}, x₀, Ω, ψ, σ, k, Φ, Ψ)\n\nFind the optimal k sparse vector given initial value x₀, allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, and total signal Ψ.\n\njulia> using AllocationOpt\njulia> x₀ = [2.5, 2.5]\njulia> Ω = [1.0, 1.0]\njulia> ψ = [10.0, 10.0]\njulia> σ = 5.0\njulia> k = 1\njulia> Φ = 1.0\njulia> Ψ = 20.0\njulia> AllocationOpt.optimizek(Val(:fast), x₀, Ω, ψ, σ, k, Φ, Ψ)\n2-element Vector{Float64}:\n 5.0\n 0.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.optimizek-Tuple{Val{:optimal}, Any, Any, Any, Any, Any, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.optimizek","text":"optimizek(::Val{:optimal}, x₀, Ω, ψ, σ, k, Φ, Ψ, g)\n\nFind the optimal k sparse vector given allocations of other indexers Ω, signals ψ, available stake σ, new tokens issued Φ, total signal Ψ, and gas g.\n\nExample\n\njulia> using AllocationOpt\njulia> Ω = [1.0, 1.0]\njulia> ψ = [10.0, 10.0]\njulia> σ = 5.0\njulia> k = 1\njulia> Φ = 1.0\njulia> Ψ = 20.0\njulia> g = 0.01\njulia> x₀ = zeros(length(Ω))\njulia> x = AllocationOpt.optimizek(Val(:optimal), x₀, Ω, ψ, σ, k, Φ, Ψ, g)\n2-element Vector{Float64}:\n 5.0\n 0.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.pinned-Tuple{TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.pinned","text":"pinned(config::AbstractDict)\n\nThe pinned vector of the indexer.\n\njulia> using AllocationOpt\njulia> s = flextable([\n Dict(\"ipfsHash\" => \"Qma\", \"signalledTokens\" => 5.0),\n Dict(\"ipfsHash\" => \"Qmb\", \"signalledTokens\" => 10.0),\n Dict(\"ipfsHash\" => \"Qmc\", \"signalledTokens\" => 15.0),\n])\njulia> config = Dict(\"pinnedlist\" => [\"Qma\", \"Qmb\"])\njulia> AllocationOpt.pinned(s, config)\n3-element Vector{Float64}:\n 0.1\n 0.1\n 0.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.primal-Tuple{Any, Any, Any}","page":"API Reference","title":"AllocationOpt.primal","text":"primal(Ω, ψ, ν)\n\nAnalytic solution of the primal form of the optimisation problem given signals ψ, allocations Ω, and a dual solution vector ν.\n\nnote: Note\nYou should probably not use this function directly. Use optimizeanalytic instead.\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.profit-Tuple{Real, Real}","page":"API Reference","title":"AllocationOpt.profit","text":"profit(r::Real, g::Real)\n\nCompute the profit for one allocation with reward r and gas cost g.\n\njulia> using AllocationOpt\njulia> r = 10\njulia> g = 1\njulia> AllocationOpt.profit(r, g)\n9\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.read-Tuple{AbstractDict{String, Any}}","page":"API Reference","title":"AllocationOpt.read","text":"read(config::AbstractDict)\n\nGiven a config, read the data in as flextables.\n\nIf you have specified a \"readdir\" in the config, this will read from CSV files in that directory. Otherwise, this will query the specified \"network_subgraph_endpoint\"\n\njulia> using AllocationOpt\njulia> config = Dict(\"verbose\" => false, \"readdir\" => \"mydatadir\")\njulia> i, a, s, n = AllocationOpt.read(config) # Read data from CSVs\n\njulia> using AllocationOpt\njulia> config = Dict(\n \"verbose\" => false,\n \"network_subgraph_endpoint\" => \"https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet\",\n \"readdir\" => nothing,\n)\njulia> i, a, s, n = AllocationOpt.read(config) # Query GQL endpoint\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.read-Tuple{AbstractString, AbstractDict}","page":"API Reference","title":"AllocationOpt.read","text":"read(f::AbstractString, config::AbstractDict)\n\nRead the CSV files from f and return the tables from those files.\n\njulia> using AllocationOpt\njulia> i, a, s, n = AllocationOpt.read(\"myreaddir\", Dict(\"verbose\" => true))\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.read-Tuple{Nothing, AbstractDict{String, Any}}","page":"API Reference","title":"AllocationOpt.read","text":"read(::Nothing, config::AbstractDict)\n\nQuery the required data from the provided endpoint in the config.\n\njulia> using AllocationOpt\njulia> config = Dict(\n \"verbose\" => true,\n \"network_subgraph_endpoint\" => \"https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet\",\n )\njulia> i, a, s, n = AllocationOpt.read(nothing, config)\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.readconfig-Tuple{AbstractString}","page":"API Reference","title":"AllocationOpt.readconfig","text":"readconfig(p::AbstractString)\n\nRead the config file from path p. The config file must be specifed as a TOML.\n\nSee configuredefaults! to see which fields you should specify in the config.\n\njulia> using AllocationOpt\njulia> path = \"myconfig.toml\"\njulia> config = AllocationOpt.readconfig(path)\nDict{String, Any} with 13 entries:\n \"execution_mode\" => \"none\"\n \"writedir\" => \"data\"\n \"num_reported_options\" => 2\n \"id\" => \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\n \"pinnedlist\" => Union{}[]\n \"gas\" => 100\n \"allocation_lifetime\" => 28\n \"blacklist\" => Union{}[]\n \"verbose\" => true\n \"min_signal\" => 1000\n \"whitelist\" => Union{}[]\n \"max_allocations\" => 5\n \"frozenlist\" => Union{}[]\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.reallocate_action-Tuple{Val{:actionqueue}, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.reallocate_action","text":"reallocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)\n\nCreate and push reallocate actions to the action queue.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> t = flextable([\n Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"),\n Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"),\n])\njulia> config = Dict(\"indexer_url\" => \"http://localhost:18000\")\njulia> TheGraphData.client!(config[\"indexer_url\"])\njulia> AllocationOpt.reallocate_action(Val(:actionqueue), a, t, config)\n1-element Vector{Dict{String, Any}}:\n Dict(\"amount\" => \"1\", \"priority\" => 0, \"status\" => AllocationOpt.queued, \"allocationID\" => \"0xa\", \"source\" => \"AllocationOpt\", \"reason\" => \"Expected profit: 0\", \"type\" => AllocationOpt.reallocate, \"deploymentID\" => \"Qma\")\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.reallocate_action-Tuple{Val{:none}, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.reallocate_action","text":"reallocate_action(::Val{:none}, a, t, config)\n\nDo nothing.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\") ]) julia> t = flextable([ Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"), Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"), ]) julia> AllocationOpt.reallocate_action(Val(:none), a, t, Dict())\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.reallocate_action-Tuple{Val{:rules}, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.reallocate_action","text":"reallocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)\n\nPrint a rule that reallocates the old allocation with a new allocation amount\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> t = flextable([\n Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"),\n Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"),\n])\njulia> AllocationOpt.reallocate_action(Val(:rules), a, t, Dict())\ngraph indexer rules stop Qma\nCheck allocation status being closed before submitting: graph indexer rules set Qma decisionBasis always allocationAmount 1\n1-element Vector{String}:\n \"\u001b[0mgraph indexer rules stop Qm\" ⋯ 122 bytes ⋯ \"asis always allocationAmount 1\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.reportingtable-Union{Tuple{T}, Tuple{TypedTables.FlexTable, AbstractMatrix{T}, AbstractMatrix{T}, Integer}} where T<:Real","page":"API Reference","title":"AllocationOpt.reportingtable","text":"reportingtable(\n s::FlexTable, xs::AbstractMatrix{Real}, ps::AbstractMatrix{Real}, i::Integer\n)\n\nConstruct a table for the strategy mapping the ipfshash, allocation amount, and profit\n\njulia> using AllocationOpt\njulia> s = flextable([\n Dict(\"stakedTokens\" => \"1\", \"signalledTokens\" => \"2\", \"ipfsHash\" => \"Qma\"),\n Dict(\"stakedTokens\" => \"2\", \"signalledTokens\" => \"1\", \"ipfsHash\" => \"Qmb\"),\n ])\njulia> xs = [[2.5 5.0]; [2.5 0.0]]\njulia> ps = [[3.0 5.0]; [3.0 0.0]]\njulia> i = 1\njulia> AllocationOpt.reportingtable(s, xs, ps, i)\nFlexTable with 3 columns and 2 rows:\n ipfshash amount profit\n ┌─────────────────────────\n 1 │ Qma 2.5 3.0\n 2 │ Qmb 2.5 3.0\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.savenames-Tuple{AbstractString}","page":"API Reference","title":"AllocationOpt.savenames","text":"savenames(p::AbstractString)\n\nReturn a generator of the generic names of the CSV files containing the data with the path specified by p.\n\njulia> using AllocationOpt\njulia> path = \"mypath\"\njulia> paths = AllocationOpt.savenames(path)\nBase.Generator{NTuple{4, String}, AllocationOpt.var\"#1#2\"{String}}(AllocationOpt.var\"#1#2\"{String}(\"mypath\"), (\"indexer.csv\", \"allocation.csv\", \"subgraph.csv\", \"network.csv\"))\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.signal-Tuple{Val{:network}, Any}","page":"API Reference","title":"AllocationOpt.signal","text":"signal(::Val{:network}, x)\n\nThe total signal in the network\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( \"id\" => 1, \"totalSupply\" => 1, \"networkGRTIssuance\" => 1, \"epochLength\" => 28, \"totalTokensSignalled\" => 2, \"currentEpoch\" => 1, ) ]) julia> AllocationOpt.signal(Val(:network), n) 2\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.signal-Tuple{Val{:subgraph}, Any}","page":"API Reference","title":"AllocationOpt.signal","text":"signal(::Val{:subgraph}, x)\n\nThe tokens signalled on the subgraphs in table x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\"signalledTokens\" => 10,),\n Dict(\"signalledTokens\" => 5,),\n])\njulia> AllocationOpt.signal(Val(:subgraph), x)\n2-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:\n 10\n 5\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.sortprofits!-Union{Tuple{AbstractVector{N}}, Tuple{N}} where N<:NamedTuple","page":"API Reference","title":"AllocationOpt.sortprofits!","text":"sortprofits!(NamedTuple{Tuple{Float64, Int64}})\n\nSort the nonzero best profits from highest to lowest\n\njulia> using AllocationOpt\njulia> popts = [\n (; :profit => 5.0, :index => 2),\n (; :profit => 6.0, :index => 1)\n ]\njulia> popts = AllocationOpt.sortprofits!(popts)\n2-element Vector{NamedTuple{(:profit, :index), Tuple{Float64, Int64}}}:\n (profit = 6.0, index = 1)\n (profit = 5.0, index = 2)\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.squery-Tuple{}","page":"API Reference","title":"AllocationOpt.squery","text":"squery()\n\nReturn the components of a GraphQL query for subgraphs.\n\nFor use with the TheGraphData.jl package.\n\njulia> using AllocationOpt\njulia> value, args, fields = AllocationOpt.squery()\n(\"subgraphDeployments\", Dict{String, Union{Dict{String, String}, String}}(), [\"ipfsHash\", \"signalledTokens\", \"stakedTokens\"])\n\nExtended Help\n\nYou can find TheGraphData.jl at https://github.com/semiotic-ai/TheGraphData.jl\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.stake-Tuple{Val{:allocation}, Any}","page":"API Reference","title":"AllocationOpt.stake","text":"stake(::Val{:allocation}, x)\n\nGet the allocated tokens for each allocation in x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"allocatedTokens\" => 1,\n ),\n])\njulia> AllocationOpt.stake(Val(:allocation), x)\n1-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:\n 1\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.stake-Tuple{Val{:indexer}, Any}","page":"API Reference","title":"AllocationOpt.stake","text":"stake(::Val{:indexer}, x)\n\nThe tokens staked by the indexer in table x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\n \"stakedTokens\" => 10,\n ),\n])\njulia> AllocationOpt.stake(Val(:indexer), x)\n10\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.stake-Tuple{Val{:subgraph}, Any}","page":"API Reference","title":"AllocationOpt.stake","text":"stake(::Val{:subgraph}, x)\n\nThe tokens staked on the subgraphs in table x.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> x = flextable([\n Dict(\"stakedTokens\" => 10,),\n Dict(\"stakedTokens\" => 5,),\n])\njulia> AllocationOpt.stake(Val(:subgraph), x)\n2-element view(transpose(lazystack(::Vector{Vector{Int64}})), :, 1) with eltype Int64:\n 10\n 5\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.strategydict-Union{Tuple{I}, Tuple{T}, Tuple{NamedTuple, AbstractMatrix{T}, AbstractVector{I}, TypedTables.FlexTable, AbstractMatrix{T}}} where {T<:Real, I<:Integer}","page":"API Reference","title":"AllocationOpt.strategydict","text":"strategydict(\n p::NamedTuple,\n xs::AbstractMatrix{Real},\n nonzeros::AbstractVector{Integer},\n fs::FlexTable,\n profitmatrix::AbstractMatrix{Real}\n)\n\nFor a profit, index pair p, generate the nested dictionary representing the data to convert to a JSON string. xs is the allocation strategy matrix, nonzeros are the number of nonzeros in each allocation strategy, fs is a table containing subgraph ipfshashes, and the profitmatrix is a matrix containing profit for each allocation in xs\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> popts = [\n (; :profit => 6.0, :index => 1),\n (; :profit => 5.0, :index => 2)\n ]\njulia> xs = [[2.5 5.0]; [2.5 0.0]]\njulia> profits = [[3.0 5.0]; [3.0 0.0]]\njulia> nonzeros = [2, 1]\njulia> fs = flextable([\n Dict(\"stakedTokens\" => \"1\", \"signalledTokens\" => \"0\", \"ipfsHash\" => \"Qma\"),\n Dict(\"stakedTokens\" => \"2\", \"signalledTokens\" => \"0\", \"ipfsHash\" => \"Qmb\"),\n ])\njulia> AllocationOpt.strategydict.(popts, Ref(xs), Ref(nonzeros), Ref(fs), Ref(profits))\n2-element Vector{Dict{String, Any}}:\n Dict(\"num_allocations\" => 2, \"profit\" => 6.0, \"allocations\" => Dict{String, Any}[Dict(\"allocationAmount\" => \"2.5\", \"profit\" => 3.0, \"deploymentID\" => \"Qma\"), Dict(\"allocationAmount\" => \"2.5\", \"profit\" => 3.0, \"deploymentID\" => \"Qmb\")])\n Dict(\"num_allocations\" => 1, \"profit\" => 5.0, \"allocations\" => Dict{String, Any}[Dict(\"allocationAmount\" => \"5\", \"profit\" => 5.0, \"deploymentID\" => \"Qma\")])\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.subtractindexer!-Tuple{TypedTables.FlexTable, TypedTables.FlexTable}","page":"API Reference","title":"AllocationOpt.subtractindexer!","text":"subtractindexer!(a::FlexTable, s::FlexTable)\n\nSubtract the indexer's allocated tokens from the total allocated tokens on each subgraph.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> s = flextable([\n Dict(\"ipfsHash\" => \"Qmb\", \"stakedTokens\" => 20),\n Dict(\"ipfsHash\" => \"Qma\", \"stakedTokens\" => 10),\n Dict(\"ipfsHash\" => \"Qmc\", \"stakedTokens\" => 5),\n ])\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"allocatedTokens\" => 5, \"id\" => \"0xa\"),\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qmb\", \"allocatedTokens\" => 10, \"id\" => \"0xb\"),\n ])\njulia> a, s = AllocationOpt.subtractindexer!(a, s)\n(NamedTuple[(var\"subgraphDeployment.ipfsHash\" = \"Qma\", allocatedTokens = 5, id = \"0xa\"), (var\"subgraphDeployment.ipfsHash\" = \"Qmb\", allocatedTokens = 10, id = \"0xb\")], NamedTuple[(stakedTokens = 5.0, ipfsHash = \"Qma\"), (stakedTokens = 10, ipfsHash = \"Qmb\"), (stakedTokens = 5, ipfsHash = \"Qmc\")])\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.togrt-Tuple{AbstractString}","page":"API Reference","title":"AllocationOpt.togrt","text":"togrt(x::AbstractString)\n\nConvert x to GRT.\n\nnote: Note\nThis function is meant to be used with freshly queried data, so it operates on strings.\n\njulia> using AllocationOpt\njulia> AllocationOpt.togrt(\"1\")\n1.0e-18\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.totalsupply-Tuple{Val{:network}, Any}","page":"API Reference","title":"AllocationOpt.totalsupply","text":"totalsupply(::Val{:network}, x)\n\nThe total GRT supply.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> n = flextable([ Dict( \"id\" => 1, \"totalSupply\" => 1, \"networkGRTIssuance\" => 1, \"epochLength\" => 28, \"totalTokensSignalled\" => 2, \"currentEpoch\" => 1, ) ]) julia> AllocationOpt.totalsupply(Val(:network), n) 1\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.unallocate_action-Tuple{Val{:actionqueue}, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.unallocate_action","text":"unallocate_action(::Val{:actionqueue}, a::FlexTable, t::FlexTable, config::AbstractDict)\n\nCreate and push the unallocate actions to the action queue.\n\n```julia julia> using AllocationOpt julia> using TheGraphData julia> a = flextable([ Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\") ]) julia> t = flextable([ Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"), ]) julia> config = Dict( \"frozenlist\" => [], \"indexerurl\" => \"http://localhost:18000\" ) julia> TheGraphData.client!(config[\"indexerurl\"]) julia> AllocationOpt.unallocate_action(Val(:actionqueue), a, t, config) 1-element Vector{Dict{String, Any}}: Dict(\"priority\" => 0, \"status\" => AllocationOpt.queued, \"allocationID\" => \"0xa\", \"source\" => \"AllocationOpt\", \"reason\" => \"AllocationOpt\", \"type\" => AllocationOpt.unallocate, \"deploymentID\" => \"Qma\")\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.unallocate_action-Tuple{Val{:none}, Any, Any, Any}","page":"API Reference","title":"AllocationOpt.unallocate_action","text":"unallocate_action(::Val{:none}, a, t, config)\n\nDo nothing.\n\njulia> using AllocationOpt\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> t = flextable([\n Dict(\"amount\" => \"1\", \"profit\" => \"0\", \"ipfshash\" => \"Qma\"),\n Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"),\n ])\njulia> AllocationOpt.unallocate_action(Val(:none), a, t, Dict())\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.unallocate_action-Tuple{Val{:rules}, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.unallocate_action","text":"unallocate_action(::Val{:rules}, a::FlexTable, t::FlexTable, config::AbstractDict)\n\nPrint a rule that stops old allocations that the optimiser has not chosen and that aren't frozen.\n\njulia> using AllocationOpt\njulia> a = flextable([\n Dict(\"subgraphDeployment.ipfsHash\" => \"Qma\", \"id\" => \"0xa\")\n ])\njulia> t = flextable([\n Dict(\"amount\" => \"2\", \"profit\" => \"0\", \"ipfshash\" => \"Qmb\"),\n ])\njulia> AllocationOpt.unallocate_action(Val(:rules), a, t, Dict(\"frozenlist\" => []))\ngraph indexer rules stop Qma\n1-element Vector{String}:\n \"\u001b[0mgraph indexer rules stop Qma\"\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.write-Tuple{TypedTables.FlexTable, TypedTables.FlexTable, TypedTables.FlexTable, TypedTables.FlexTable, AbstractDict}","page":"API Reference","title":"AllocationOpt.write","text":"write(i::FlexTable, a::FlexTable, s::FlexTable, n::FlexTable, config::AbstractDict)\n\nWrite the tables to the writedir specified in the config.\n\njulia> using AllocationOpt\njulia> using TheGraphData\njulia> config = Dict(\"verbose\" => true, \"writedir\" => \"datadir\")\njulia> t = flextable([\n Dict(\"ipfsHash\" => \"Qma\", \"signalledTokens\" => \"1\"),\n Dict(\"ipfsHash\" => \"Qmb\", \"signalledTokens\" => \"2\"),\n ])\njulia> i, a, s, n = repeat([t,], 4)\njuila> AllocationOpt.write(i, a, s, n, config)\n\n\n\n\n\n","category":"method"},{"location":"api/#AllocationOpt.writejson-Tuple{AbstractString, AbstractDict}","page":"API Reference","title":"AllocationOpt.writejson","text":"function writejson(results::AbstractString, config::AbstractDict)\n\nWrite the optimized results to the writedir specified in the config.\n\njulia> Using AllocationOpt\njulia> results = \"{\"strategies\":[{\"num_allocations\":2,\"profit\":6.0,\"allocations\":[{\"allocationAmount\":2.5,\"profit\":3.0,\"deploymentID\":\"Qma\"},{\"allocationAmount\":2.5,\"profit\":3.0,\"deploymentID\":\"Qmb\"}]},{\"num_allocations\":1,\"profit\":5.0,\"allocations\":[{\"allocationAmount\":5.0,\"profit\":5.0,\"deploymentID\":\"Qma\"}]}]}\"\njulia> config = Dict{\"writedir\" => \".\"}\njulia> AllocationOpt.writejson(results, config)\n\n\n\n\n\n","category":"method"},{"location":"api/#SemioticOpt.iteration-Tuple{Function, AllocationOpt.AnalyticOpt}","page":"API Reference","title":"SemioticOpt.iteration","text":"iteration(f::Function, a::AnalyticOpt)\n\nPerform the analytic optimisation.\n\n\n\n\n\n","category":"method"},{"location":"api/#SemioticOpt.x!-Tuple{AllocationOpt.AnalyticOpt, Any}","page":"API Reference","title":"SemioticOpt.x!","text":"x!(a::AnalyticOpt, v)\n\nIn-place setting of a.x to v\n\nSee SemioticOpt.x.\n\n\n\n\n\n","category":"method"},{"location":"api/#SemioticOpt.x-Tuple{AllocationOpt.AnalyticOpt}","page":"API Reference","title":"SemioticOpt.x","text":"x(a::AnalyticOpt)\n\nReturn the current best guess for the solution.\n\n\n\n\n\n","category":"method"},{"location":"output/#Understanding-The-Output","page":"Understanding The Output","title":"Understanding The Output","text":"","category":"section"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"After a successful run, the Allocation Optimizer will produce a JSON output in your writedir under the name report.json. Let's walk through how to read this file.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"This report contains the various strategies that the Allocation Optimizer recommends based on the network state and your config file. The num_reported_options field in your config will determine the maximum number of outputs in the report.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"Let's break down the following example report.json","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"{\n \"strategies\": [\n {\n \"num_allocations\":2,\n \"profit\":229779.02830650925,\n \"allocations\": [\n {\n \"allocationAmount\":\"13539706.9\",\n \"profit\":169430.57951963632,\n \"deploymentID\":\"QmT2Y7SHXGRt7EKXzFPYMjnrgX64PQr86EjbsHoDLNzwLy\"\n },\n {\n \"allocationAmount\":\"9194401.2\",\n \"profit\":60348.44878687295,\n \"deploymentID\":\"QmXT4PhR9pwAUqkxg6tgqR8xWUsTYN7V8UgmqhrrimcqXf\"\n }\n ]\n },\n {\n \"num_allocations\":1,\n \"profit\":190114.2718246217,\n \"allocations\": [\n {\n \"allocationAmount\":\"22734108.1\",\n \"profit\":190114.2718246217,\n \"deploymentID\":\"QmT2Y7SHXGRt7EKXzFPYMjnrgX64PQr86EjbsHoDLNzwLy\"\n }\n ]\n }\n ]\n}","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"which the Optimizer generated from the following config.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nreaddir = \"data\"\nmax_allocations = 2\nwhitelist = []\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = true\nnum_reported_options = 2\nexecution_mode = \"rules\"","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"note: Note\nIf you use this same config, you could get a slightly different report depending on the network state.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"The JSON has two strategies. They are sorted by the one with the highest expected profit appearing first. In the first one here, we have two allocations, which you could see from the num_allocations field, or by counting the number of entries under the allocations field. At the top level of each strategy, profit describes the total expected profit in GRT for all allocations.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"warning: Warning\nNotice in the config file that our allocation lifetime was 28 epochs. The profit is over that lifetime. However, it is impossible for us to know how the network state will evolve in the future. All results from the Optimizer assume that the network state will remain static. As a result, you should take these numbers with a grain of salt and use your knowledge as an indexer to determine whether the Optimizer's strategy could be tweaked in your favour.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"Then, we go into the allocations. Each entry in this list contains the amount of GRT the strategy wants you to stake, the expected profit of this allocation, and the subgraph deployment ID onto which you should make this allocation.","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"In addition to the report.json, since we specified execution_mode as \"rules\" in the config, the Optimizer will print out indexer rules that you can run to execute the best strategy. In our case,","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"graph indexer rules stop QmNoe4VQFSKAC3uiq48UQASg4QeqFVSKYYGwnxNjNi6GYX\ngraph indexer rules stop QmRDGLp6BHwiH9HAE2NYEE3f7LrKuRqziHBv76trT4etgU\ngraph indexer rules stop QmUVskWrz1ZiQZ76AtyhcfFDEH1ELnRpoyEhVL8p6NFTbR\ngraph indexer rules stop QmXZiV6S13ha6QXq4dmaM3TB4CHcDxBMvGexSNu9Kc28EH\ngraph indexer rules stop QmYN4ofRb5CUg1WdpLhhNTVCuiiAt29hBKGjTnnxYh9zYt\ngraph indexer rules stop Qmaz1R8vcv9v3gUfksqiS9JUz7K9G8S5By3JYn8kTiiP5K\ngraph indexer rules stop QmcBSr5R3K2M5tk8qeHFaX8pxAhdViYhcKD8ZegYuTcUhC\ngraph indexer rules set QmT2Y7SHXGRt7EKXzFPYMjnrgX64PQr86EjbsHoDLNzwLy decisionBasis always allocationAmount 13539706.9\ngraph indexer rules set QmXT4PhR9pwAUqkxg6tgqR8xWUsTYN7V8UgmqhrrimcqXf decisionBasis always allocationAmount 9194401.2","category":"page"},{"location":"output/","page":"Understanding The Output","title":"Understanding The Output","text":"If instead you use \"actionqueue\" as the execution_mode, the Optimizer will populate your instance of the action queue.","category":"page"},{"location":"provided-binary/#Using-The-Provided-Binary","page":"Using The Provided Binary","title":"Using The Provided Binary","text":"","category":"section"},{"location":"provided-binary/","page":"Using The Provided Binary","title":"Using The Provided Binary","text":"Using the provided binary has the advantage of being that only method that doesn't require that you use the Julia runtime. If you want to get running as quickly as possible, this is the path for you.","category":"page"},{"location":"provided-binary/","page":"Using The Provided Binary","title":"Using The Provided Binary","text":"note: Note\nWe only release binaries for x86 Linux.","category":"page"},{"location":"provided-binary/","page":"Using The Provided Binary","title":"Using The Provided Binary","text":"All you have to do is download the binary for the platform and release you want to use, unzip it, set up your configuration (Configuration) file, and run the binary from your terminal.","category":"page"},{"location":"provided-binary/","page":"Using The Provided Binary","title":"Using The Provided Binary","text":"./path/to/unzipped/folder/bin/AllocationOpt /path/to/your_config.toml","category":"page"},{"location":"calling-another/#Calling-From-Another-Language","page":"Calling From Another Language","title":"Calling From Another Language","text":"","category":"section"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"It's possible to call the Allocation Optimizer from another language. There are already some solutions out there that do this. In general, if you're going to take this approach, we assume that you know what you're doing. We won't hold your hand through the process as we don't want to officially support a multitude of different languages. Instead, we'll point you to resources you can use for various languages.","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"warning: Warning\nWe don't recommend you use this approach, as you may have to delay integrating bugfixes and new features while you are figuring out how to integrate the new code. People using the mainline routes will always be able to more quickly access the updates we push. We especially don't recommend this route if you're not a developer. We will not support bugs that arise from integrating the tool into third-party scripts.","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"C/C++\nPython\nRust","category":"page"},{"location":"calling-another/#Under-The-Hood","page":"Calling From Another Language","title":"Under The Hood","text":"","category":"section"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"Before we let you go, we'll explain at a high-level the main function. Roughly speaking, we can break down this problem into the following steps.","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"Read the data, where from the network subgraph or from local CSVs. The currency used is GRT.\nFilter the data based on the whitelist, blacklist, pinnedlist, and frozenlist\nGet the values we care about for the indexing rewards","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"σ - The indexer's stake\nΩ - A vector of floats containing the sum of the allocations of all other indexers on each subgraph in our data\nψ - A vector of floats representing the signal on each subgraph in our data.\nΨ - A float representing the total signal in the network\nK - The maximum number of new allocations\ng - The gas cost in GRT","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"Get the optimal allocation vectors for each k ∈ 1,...,K\nSort these by their profit\nReport information about the most profitable vectors.","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"The full code for the main function with comments follows.","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"function main(config::Dict)\n # Read data\n i, a, s, n = AllocationOpt.read(config)\n\n # Write the data if it was queried rather than read from file\n isnothing(config[\"readdir\"]) && write(i, a, s, n, config)\n\n # Get the subgraphs on which we can allocate\n fs = allocatablesubgraphs(s, config)\n\n # Get the indexer stake\n pinnedvec = pinned(fs, config)\n σpinned = pinnedvec |> sum\n σ = availablestake(Val(:indexer), i) - frozen(a, config) - σpinned\n @assert σ > 0 \"No stake available to allocate with the configured frozenlist and pinnedlist\"\n\n # Allocated tokens on filtered subgraphs\n Ω = stake(Val(:subgraph), fs) .+ fudgefactor\n\n # Signal on filtered subgraphs\n ψ = signal(Val(:subgraph), fs)\n\n # Signal on all subgraphs\n Ψ = signal(Val(:network), n)\n\n # New tokens issued over allocation lifetime\n Φ = newtokenissuance(n, config)\n\n # Get max number of allocations\n K = min(config[\"max_allocations\"], length(fs))\n\n # Get gas cost in GRT\n g = config[\"gas\"]\n\n # Get optimal values\n config[\"verbose\"] && @info \"Optimizing\"\n xs, nonzeros, profitmatrix = optimize(Ω, ψ, σ, K, Φ, Ψ, g)\n\n # Add the pinned stake back in\n xs .= xs .+ pinnedvec\n\n # Ensure that the indexer stake is not exceeded\n σmax = σ + σpinned\n for x in sum(xs; dims=1)\n x ≤ σmax || error(\"Tried to allocate more stake than is available\")\n end\n\n # Write the result values\n # Group by unique number of nonzeros\n groupixs = groupunique(nonzeros)\n groupixs = Dict(keys(groupixs) .=> values(groupixs))\n\n config[\"verbose\"] && @info \"Writing results report\"\n # For each set of nonzeros, find max profit (should be the same other than rounding)\n popts = bestprofitpernz.(values(groupixs), Ref(profitmatrix)) |> sortprofits!\n nreport = min(config[\"num_reported_options\"], length(popts))\n\n # Create JSON string\n strategies =\n strategydict.(popts[1:nreport], Ref(xs), Ref(nonzeros), Ref(fs), Ref(profitmatrix))\n reportdata = JSON.json(Dict(\"strategies\" => strategies))\n\n # Write JSON string to file\n writejson(reportdata, config)\n\n config[\"verbose\"] && @info \"Executing best strategy\"\n # Use config for using actionqueue or rules with the top profit batch\n ix = first(popts)[:index]\n execute(a, ix, fs, xs, profitmatrix, config)\n\n return nothing\nend","category":"page"},{"location":"calling-another/","page":"Calling From Another Language","title":"Calling From Another Language","text":"For details on any of the specific functions called, look at the API Reference.","category":"page"},{"location":"contributing/#Contributing","page":"Contributing","title":"Contributing","text":"","category":"section"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"We're excited you are interested in contributing! Please follow the standards put forth in ColPrac to contribute to the Allocation Optimizer.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"Most importantly, we'd like to emphasise a few points.","category":"page"},{"location":"contributing/","page":"Contributing","title":"Contributing","text":"PRs should do a single thing.\nWe'd prefer that you submit ten small PRs that are easy to understand as compared with one massive PR that requires a full day of review.\nPRs should add tests which cover the new or fixed functionality.\nPRs introducing breaking changes should make this clear when opening the PR.","category":"page"},{"location":"build-a-binary/#Build-Your-Own-Binary","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"","category":"section"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Compiling the binary yourself is an excellent way to use the Allocation Optimizer. You should use this route if a couple of reasons speak to you.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"You'd prefer not to trust a random binary off the internet.\nYou have added your own features to the Allocation Optimizer, but would prefer the large, one-time cost of AOT compilation as opposed the small, every-time cost of JIT compilation.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"In this documentation, we'll take you through the process of generating an app binary.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"note: Note\nYou can instead compile to a sysimage or to a library, but we don't natively support those ourselves. Look through the PackageCompiler documentation for steps if you would prefer one of those options..","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Install Julia! We prefer to use juliaup. You can install this via:","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"curl -fsSL https://install.julialang.org | sh","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"note: Note\nAs of writing this documentation, the latest version of Julia is v1.8. This the version the Allocation Optimizer currently uses, and the version juliaup will install by default. If juliaup begins to use v1.9, then you may need to use juliaup to manually install v1.8 via juliaup add 1.8. Then, you can either set the default to be v1.8 using juliaup default 1.8, or you can replace every time you see julia with julia +1.8 below.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Clone this repository and cd into it.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"git clone https://github.com/graphprotocol/allocation-optimizer.git\ncd allocation-optimizer","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Start Julia.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"julia --project","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Install the dependencies","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"julia> ]\npkg> instantiate","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Install a C-compiler such as GCC or Clang.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"From the Julia REPL (the TUI that comes up when you use julia --project), compile your app.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"julia> using PackageCompiler\njulia> create_app(\".\", \"app\")","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"note: Note\nIf you are still in Pkg mode, pkg>, hitting backspace will bring you back into the REPL.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Set up your configuration file. See Configuration for details.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"Run the binary pointing at the configuration TOML that you would like to use.","category":"page"},{"location":"build-a-binary/","page":"Build Your Own Binary","title":"Build Your Own Binary","text":"./app/bin/AllocationOpt /path/to/your_config.toml","category":"page"},{"location":"call-julia/#Calling-From-Julia","page":"Calling From Julia","title":"Calling From Julia","text":"","category":"section"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"If you're okay with having the Julia runtime on your computer, and you don't mind the precompilation time, this is the preferred way to run the Allocation Optimizer. In part, this is because access the to Julia runtime will enable you to add your own features if you'd like. You can even (hopefully) even submit some PRs with features to help other indexers! Compiling on your machine also allows Julia to specialise on idiosyncrasies of your hardware. For example, if your CPU supports AVX-512, Julia will use those instructions to speed up your code beyond what the generic binary might give you. Again, the trade-off here is that you'll have to eat the precompilation time the first time you run the code after you start a new Julia session.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"That said, here's how to install and use the Allocation Optimizer from Julia.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"Install Julia! We prefer to use juliaup. You can install this via:","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"curl -fsSL https://install.julialang.org | sh","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"note: Note\nAs of writing this documentation, the latest version of Julia is v1.8. This the version the Allocation Optimizer currently uses, and the version juliaup will install by default. If juliaup begins to use v1.9, then you may need to use juliaup to manually install v1.8 via juliaup add 1.8. Then, you can either set the default to be v1.8 using juliaup default 1.8, or you can replace every time you see julia with julia +1.8 below.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"Clone this repository and cd into it.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"git clone https://github.com/graphprotocol/allocation-optimizer.git\ncd allocation-optimizer","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"Start Julia.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"julia --project","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"Install the dependencies","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"julia> ]\npkg> instantiate","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"Set up your configuration file. See Configuration for details.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"From the Julia REPL (the TUI that comes up when you use julia --project), run the main function with the path to your config.","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"julia> using AllocationOpt\njulia> path = \"config.toml\" # path to your config file\njulia> AllocationOpt.main(path)","category":"page"},{"location":"call-julia/","page":"Calling From Julia","title":"Calling From Julia","text":"note: Note\nIf you are still in Pkg mode, pkg>, hitting backspace will bring you back into the REPL.","category":"page"},{"location":"configuration/#Configuration","page":"Configuration","title":"Configuration","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"When using the optimiser, you change it's behaviour via a configuration file specified as a TOML. The configuration file serves two purposes. Firstly, it makes it easier for you to track various settings and their impacts. Secondly, if something breaks, it makes it easier for us to reproduce what went wrong.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"An example configuration TOML file might look as below.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nreaddir = \"data\"\nmax_allocations = 10\nwhitelist = []\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = true\nnum_reported_options = 2\nexecution_mode = \"none\"\nopt_mode = \"fast\"","category":"page"},{"location":"configuration/#Detailed-Field-Descriptions","page":"Configuration","title":"Detailed Field Descriptions","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id::String: The ID of the indexer for whom we're optimising. No default value.\nnetwork_subgraph_endpoint::String: The network subgraph endpoint to query. The optimizer support any network (such as mainnet, goerli, arbitrum-one, arbitrum-goerli) as long as the provided API serves the query requests. If unspecified, \"https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet\"\nwritedir::String: The directory to which to write the results of optimisation. If don't specify readdir, writedir also specifies the path to which to save the input data tables. If unspecified, \".\"\nreaddir::Union{String, Nothing}: The directory from which to read saved data tables. This speeds up the process as we won't have to query the network subgraph for the relevant data. If you don't specify readdir, we will query your specified network_subgraph_endpoint for the data and write it to CSV files in writedir. This way, you can use your previous writedir as your readdir in future runs. If unspecified, nothing\nwhitelist::Vector{String}: A list of subgraph IPFS hashes that you want to consider as candidates to which to allocate. If you leave this empty, we'll assume all subgraphs are in the whitelist. If unspecified, String[]\nblacklist::Vector{String}: A list of subgraph IPFS hashes that you do not want to consider allocating to. For example, this list could include broken subgraphs or subgraphs that you don't want to index. If unspecified, String[]\nfrozenlist::Vector{String}: If you have open allocations that you don't want to change, add the corresponding subgraph IPFS hashes to this list. If unspecified, String[]\npinnedlist::Vector{String}: If you have subgraphs that you absolutely want to be allocated to, even if only with a negligible amount of GRT, add it to this list. If unspecified, String[]\nallocation_lifetime::Integer: The number of epochs for which you expect the allocations the optimiser finds to be open. If unspecified, 28\ngas::Real: The estimated gas cost in GRT to open/close allocations. If unspecified, 100\nmin_signal::Real: The minimum amount of signal in GRT that must be on a subgraph in order for you to consider allocating to it. If unspecified, 1000\nmax_allocations::Integer: The maximum number of new allocations you'd like the optimiser to consider opening. If unspecified, 10\nnum_reported_options::Integer: The number of proposed allocation strategies to report. For example, if you select 10 we'd report best 10 allocation strategies ranked by profit. Options are reported to a report.json in your writedir. If unspecified, 1\nverbose::Bool: If true, the optimiser will print details about what it is doing to stdout. If unspecified, false\nexecution_mode::String: How the optimiser should execute the allocation strategies it finds. Options are \"none\", which won't do anything, \"actionqueue\", which will push actions to the action queue, and \"rules\", which will generate indexing rules. If unspecified, \"none\"\nindexer_url::Union{String, Nothing}: The URL of the indexer management server you want to execute the allocation strategies on. If you specify \"actionqueue\", you must also specify indexer_url. If unspecified, nothing\nopt_mode::String: We support two optimisation modes. One is \"fast\". This mode is fast, but may not find the optimal strategy. This mode is also used to the top num_reported_options allocation strategies. The other mode is \"optimal\". This mode is slower, but it satisfy stronger optimality conditions. It will find strategies at least as good as \"fast\", but not guaranteed to be better. In general, we recommend exploring config options using \"fast\" mode first, and then using \"optimal\" mode to find the optimal allocation. By default, \"optimal\"","category":"page"},{"location":"configuration/#Example-Configurations","page":"Configuration","title":"Example Configurations","text":"","category":"section"},{"location":"configuration/#ActionQueue","page":"Configuration","title":"ActionQueue","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Set execution_mode to \"actionqueue\" and provide an indexer_url.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nreaddir = \"data\"\nmax_allocations = 10\nwhitelist = []\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = true\nnum_reported_options = 2\nexecution_mode = \"actionqueue\"\nindexer_url = \"https://localhost:8000\"","category":"page"},{"location":"configuration/#Indexer-Rules","page":"Configuration","title":"Indexer Rules","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Change execution_mode to \"rules\".","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nreaddir = \"data\"\nmax_allocations = 10\nwhitelist = []\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = true\nnum_reported_options = 2\nexecution_mode = \"rules\"","category":"page"},{"location":"configuration/#Query-data-Instead-of-Reading-Local-CSVs","page":"Configuration","title":"Query data Instead of Reading Local CSVs","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Just don't specify the readdir.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nmax_allocations = 10\nwhitelist = []\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = true\nnum_reported_options = 2\nexecution_mode = \"none\"","category":"page"},{"location":"configuration/#Query-data-for-specified-networks","page":"Configuration","title":"Query data for specified networks","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Specify the network subgraph endpoint for networks other than The Graph network on Ethereum mainnet. Here we use the endpoint to goerli network subgraph.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xE9a1CABd57700B17945Fd81feeFba82340D9568F\"\nnetwork_subgraph_endpoint = \"https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-goerli\"","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Other available endpoints examples are","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Mainnet (default): https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-mainnet\nArbitrum-One: https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-arbitrum\nArbitrum-Goerli: https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-arbitrum-goerli","category":"page"},{"location":"configuration/#Quiet-Mode","page":"Configuration","title":"Quiet Mode","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"We set verbose to false here to surpress info messages.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nreaddir = \"data\"\nmax_allocations = 10\nwhitelist = []\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = false\nnum_reported_options = 2\nexecution_mode = \"none\"","category":"page"},{"location":"configuration/#Whitelisting-Subgraphs","page":"Configuration","title":"Whitelisting Subgraphs","text":"","category":"section"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"Add some subgraph deployment IDs to the whitelist. If, in addition or instead you want to use blacklist, frozenlist, or pinnedlist, you can similarly add subgraph deployment IDs to those lists. Notice that we did not change max_allocations here. If max_allocations exceeds the number of available subgraphs (2 in this case), the code will treat the number of available subgraphs as max_allocations.","category":"page"},{"location":"configuration/","page":"Configuration","title":"Configuration","text":"id = \"0xd75c4dbcb215a6cf9097cfbcc70aab2596b96a9c\"\nwritedir = \"data\"\nreaddir = \"data\"\nmax_allocations = 10\nwhitelist = [\n \"QmUVskWrz1ZiQZ76AtyhcfFDEH1ELnRpoyEhVL8p6NFTbR\",\n \"QmcBSr5R3K2M5tk8qeHFaX8pxAhdViYhcKD8ZegYuTcUhC\"\n]\nblacklist = []\nfrozenlist = []\npinnedlist = []\nallocation_lifetime = 28\ngas = 100\nmin_signal = 1000\nverbose = false\nnum_reported_options = 2\nexecution_mode = \"none\"","category":"page"}] }