From 31d9f38ac65d449028973d1621f98253d4ffe570 Mon Sep 17 00:00:00 2001 From: Aki Wu Date: Tue, 22 Aug 2023 16:44:46 +0800 Subject: [PATCH] add staking data --- Rakefile | 188 ++++++++++++++++++++++++++------------------- docker-compose.yml | 7 ++ src/server.rb | 14 ++++ src/supplies.rb | 48 ++++++------ src/supply/kton.rb | 66 ++++------------ src/supply/ring.rb | 135 ++++++++++++++++++-------------- 6 files changed, 243 insertions(+), 215 deletions(-) diff --git a/Rakefile b/Rakefile index 537a0b8..dd50d39 100644 --- a/Rakefile +++ b/Rakefile @@ -6,6 +6,8 @@ require './src/track-goerli' require './src/track-pangolin' require './src/storage' require './src/account' +require './src/supply/ring' +require './src/supply/kton' require './config/config' config = get_config @@ -38,6 +40,15 @@ task :update_nominees_loop do end end +task :update_staking_data_loop do + loop_do do + Rake::Task['gen_staking_data'].reenable + Rake::Task['gen_staking_data'].invoke('darwinia') + Rake::Task['gen_staking_data'].reenable + Rake::Task['gen_staking_data'].invoke('crab') + end +end + ########################################## # Darwinia ########################################## @@ -73,92 +84,109 @@ task :update_pangolin_metadata do end ########################################## -# Goerli <> pangolin +# Multi networks ########################################## -task :update_goerli_pangolin_messages do - track_goerli -end - -task :update_pangolin_goerli_messages do - track_pangolin -end - require 'logger' task :update_nominees, [:network_name] do |_t, args| logger = Logger.new($stdout) logger.level = Logger::DEBUG - network_name = args[:network_name] - logger.debug "updating #{network_name} nominees..." - - rpc = config["#{network_name}_rpc".to_sym] - metadata = JSON.parse(File.read(config[:metadata][network_name.to_sym])) - - ring_pool = get_storage(rpc, metadata, 'darwinia_staking', 'ring_pool', nil, nil) - kton_pool = get_storage(rpc, metadata, 'darwinia_staking', 'kton_pool', nil, nil) - nominee_commissions = get_nominee_commissions(rpc, metadata) - collators = get_collators(rpc, metadata) - - # 1. Get all nominators with their nominees - # --------------------------------------- - # { nominator: nominee } - nominators = - get_storage( - rpc, - metadata, - 'darwinia_staking', - 'nominators', - nil, - nil - ) - - nominator_nominee_mapping = - nominators.map do |item| - nominator_address = "0x#{item[:storage_key][-40..]}" - nominee_address = item[:storage].to_hex - [nominator_address, nominee_address] + timed do + network_name = args[:network_name] + logger.debug "updating #{network_name} nominees..." + + rpc = config["#{network_name}_rpc".to_sym] + metadata = JSON.parse(File.read(config[:metadata][network_name.to_sym])) + + ring_pool = get_storage(rpc, metadata, 'darwinia_staking', 'ring_pool', nil, nil) + kton_pool = get_storage(rpc, metadata, 'darwinia_staking', 'kton_pool', nil, nil) + nominee_commissions = get_nominee_commissions(rpc, metadata) + collators = get_collators(rpc, metadata) + + # 1. Get all nominators with their nominees + # --------------------------------------- + # { nominator: nominee } + nominators = + get_storage( + rpc, + metadata, + 'darwinia_staking', + 'nominators', + nil, + nil + ) + + nominator_nominee_mapping = + nominators.map do |item| + nominator_address = "0x#{item[:storage_key][-40..]}" + nominee_address = item[:storage].to_hex + [nominator_address, nominee_address] + end.to_h + + # 2. Get all nominators' staking info + # --------------------------------------- + # { + # "nominator" => {:staked_ring=>10000000000000000000, :staked_kton=>0}, + # } + nominator_addresses = nominator_nominee_mapping.keys + nominator_staking_infos = get_accounts_staking_info(rpc, metadata, nominator_addresses) + + # 3. Sum up nominators' staking info of each nominee + # --------------------------------------- + # { + # "nominee" => {:staked_ring=>total, :staked_kton=>total}, + # } + result = + nominator_addresses.each_with_object({}) do |nominator_address, acc| + nominator_staking_info = nominator_staking_infos[nominator_address] + nominee_address = nominator_nominee_mapping[nominator_address] + acc[nominee_address] = + { + staked_ring: (acc[nominee_address]&.[](:staked_ring) || 0) + nominator_staking_info[:staked_ring], + staked_kton: (acc[nominee_address]&.[](:staked_kton) || 0) + nominator_staking_info[:staked_kton] + } + end + + # 4. Calculate power of each nominee + # --------------------------------------- + nominee_powers = result.map do |nominee_address, staking_info| + power = calc_power(staking_info[:staked_ring], staking_info[:staked_kton], ring_pool, kton_pool) + [nominee_address, power] + end.to_h + + # 5. Set the collators committee + # --------------------------------------- + result = nominee_powers.keys.map do |key| + [key, { power: nominee_powers[key], commission: nominee_commissions[key], is_collator: collators.include?(key) }] end.to_h + # logger.debug JSON.pretty_generate(result) - # 2. Get all nominators' staking info - # --------------------------------------- - # { - # "nominator" => {:staked_ring=>10000000000000000000, :staked_kton=>0}, - # } - nominator_addresses = nominator_nominee_mapping.keys - nominator_staking_infos = get_accounts_staking_info(rpc, metadata, nominator_addresses) - - # 3. Sum up nominators' staking info of each nominee - # --------------------------------------- - # { - # "nominee" => {:staked_ring=>total, :staked_kton=>total}, - # } - result = - nominator_addresses.each_with_object({}) do |nominator_address, acc| - nominator_staking_info = nominator_staking_infos[nominator_address] - nominee_address = nominator_nominee_mapping[nominator_address] - acc[nominee_address] = - { - staked_ring: (acc[nominee_address]&.[](:staked_ring) || 0) + nominator_staking_info[:staked_ring], - staked_kton: (acc[nominee_address]&.[](:staked_kton) || 0) + nominator_staking_info[:staked_kton] - } - end - - # 4. Calculate power of each nominee - # --------------------------------------- - nominee_powers = result.map do |nominee_address, staking_info| - power = calc_power(staking_info[:staked_ring], staking_info[:staked_kton], ring_pool, kton_pool) - [nominee_address, power] - end.to_h - - # 5. Set the collators committee - # --------------------------------------- - result = nominee_powers.keys.map do |key| - [key, { power: nominee_powers[key], commission: nominee_commissions[key], is_collator: collators.include?(key) }] - end.to_h - logger.debug JSON.pretty_generate(result) - - # 6. write to file - # --------------------------------------- - logger.debug "writing #{network_name} nominees to file..." - write_data_to_file(result, "#{network_name}-nominees.json") + # 6. write to file + # --------------------------------------- + logger.debug "writing #{network_name} nominees to file..." + write_data_to_file(result, "#{network_name}-nominees.json") + end +end + +task :gen_staking_data, [:network_name] do |_t, args| + timed do + network_name = args[:network_name] + puts "generate #{network_name} staking data..." + + rpc = config["#{network_name}_rpc".to_sym] + metadata = JSON.parse(File.read(config[:metadata][network_name.to_sym])) + + result = { + ring: { + staking: get_all_staking_ring(rpc, metadata), + unmigrated: get_all_staking_ring_unmigrated(rpc, metadata) + }, + kton: { + staking: get_staking_kton(rpc, metadata), + unmigrated: get_staking_kton_unmigrated(rpc, metadata) + } + } + + write_data_to_file(result, "#{network_name}-staking.json") + end end diff --git a/docker-compose.yml b/docker-compose.yml index 755f7ab..8c8d7c9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,6 +19,13 @@ services: command: rake update_nominees_loop volumes: - ./data:/usr/src/app/data + update_staking: + build: . + env_file: + - .env + command: rake update_staking_data_loop + volumes: + - ./data:/usr/src/app/data server: build: . env_file: diff --git a/src/server.rb b/src/server.rb index 7d18fa8..327c99c 100644 --- a/src/server.rb +++ b/src/server.rb @@ -240,6 +240,20 @@ ############################################################################## # General ############################################################################## +get '/:network/staking' do + network = params[:network].downcase + unless %w[darwinia crab pangolin].include?(network) + raise_with 404, + "network #{network} not found, only `darwinia`, `crab` and `pangolin` are supported" + end + + result = File.read("./data/#{network}-staking.json") + result = JSON.parse(result) + + content_type :json + { code: 0, data: result }.to_json +end + get '/:network/nominees' do network = params[:network].downcase unless %w[darwinia crab pangolin].include?(network) diff --git a/src/supplies.rb b/src/supplies.rb index e0dea04..d01b344 100644 --- a/src/supplies.rb +++ b/src/supplies.rb @@ -1,47 +1,47 @@ -require "scale_rb" -require "eth" -require "json" +require 'scale_rb' +require 'eth' +require 'json' include Eth -require_relative "supply/ring" -require_relative "supply/kton" -require_relative "./utils" -require_relative "account" +require_relative 'supply/ring' +require_relative 'supply/kton' +require_relative './utils' +require_relative 'account' def calc_ring_supply(ethereum_rpc, darwinia_rpc, metadata) total_issuance = get_total_insurance(darwinia_rpc, metadata) darwinia_client = Eth::Client::Http.new(darwinia_rpc) ethereum_client = Eth::Client::Http.new(ethereum_rpc) - + # Reserve on Darwinia Chain - reserve = get_account_info(darwinia_rpc, metadata, "0x081cbab52e2dBCd52F441c7ae9ad2a3BE42e2284")[:ring].to_i + reserve = get_account_info(darwinia_rpc, metadata, '0x081cbab52e2dBCd52F441c7ae9ad2a3BE42e2284')[:ring].to_i puts "reserve: #{reserve}" # Ecosystem Development Fund - token_contract = "0x9469D013805bFfB7D3DEBe5E7839237e535ec483" + token_contract = '0x9469D013805bFfB7D3DEBe5E7839237e535ec483' # Financing - financing_address = "0xfa4fe04f69f87859fcb31df3b9469f4e6447921c" + financing_address = '0xfa4fe04f69f87859fcb31df3b9469f4e6447921c' data = "0x70a08231000000000000000000000000#{financing_address[2..]}" financing = - ethereum_client.eth_call({ to: token_contract, data: data })["result"].to_i( - 16, + ethereum_client.eth_call({ to: token_contract, data: })['result'].to_i( + 16 ).to_f / 10**18 # BD & Marketing - bd_marketing_address = "0x5FD8bCC6180eCd977813465bDd0A76A5a9F88B47" + bd_marketing_address = '0x5FD8bCC6180eCd977813465bDd0A76A5a9F88B47' data = "0x70a08231000000000000000000000000#{bd_marketing_address[2..]}" bd_marketing = - ethereum_client.eth_call({ to: token_contract, data: data })["result"].to_i( - 16, - ).to_f / 10**18 + ethereum_client.eth_call({ to: token_contract, data: })['result'].to_i( + 16 + ).to_f / 10**18 puts "financing: #{financing}, bd_marketing: #{bd_marketing}" ecosystem_development_fund = financing + bd_marketing # Treasury - treasury_address = "0x6d6f646c64612f74727372790000000000000000" + treasury_address = '0x6d6f646c64612f74727372790000000000000000' treasury = - darwinia_client.eth_get_balance(treasury_address)["result"].to_i(16).to_f / 10**18 + darwinia_client.eth_get_balance(treasury_address)['result'].to_i(16).to_f / 10**18 puts "treasury: #{treasury}" circulating_supply = total_issuance - (reserve + ecosystem_development_fund + treasury).to_i @@ -50,7 +50,7 @@ def calc_ring_supply(ethereum_rpc, darwinia_rpc, metadata) { totalSupply: total_issuance, circulatingSupply: circulating_supply, - maxSupply: 10_000_000_000, + maxSupply: 10_000_000_000 } end @@ -60,25 +60,25 @@ def calc_kton_supply(rpc, metadata) { totalSupply: total_issuance, circulatingSupply: total_issuance, - maxSupply: total_issuance, + maxSupply: total_issuance } end def calc_supply(ethereum_rpc, darwinia_rpc, metadata) { ringSupplies: calc_ring_supply(ethereum_rpc, darwinia_rpc, metadata), - ktonSupplies: calc_kton_supply(darwinia_rpc, metadata), + ktonSupplies: calc_kton_supply(darwinia_rpc, metadata) } end def generate_supplies(network_name, ethereum_rpc, darwinia_rpc, metadata) puts "generating #{network_name} supplies data..." timed do - data_dir = "./data" + data_dir = './data' FileUtils.mkdir_p(data_dir) unless File.directory?(data_dir) File.write( File.join(data_dir, "#{network_name}-supplies.json"), - calc_supply(ethereum_rpc, darwinia_rpc, metadata).to_json, + calc_supply(ethereum_rpc, darwinia_rpc, metadata).to_json ) end end diff --git a/src/supply/kton.rb b/src/supply/kton.rb index d0ed490..10d7a45 100644 --- a/src/supply/kton.rb +++ b/src/supply/kton.rb @@ -1,34 +1,23 @@ #################################################### # unmigrated accounts #################################################### -def get_unmigrated_staked_and_unstaking_kton(rpc, metadata) - ledgers = - ScaleRb::HttpClient.get_storage2( - rpc, - 'AccountMigration', - 'Ledgers', - nil, - metadata - ) - staking = ledgers.reduce(0) do |sum, ledger| +def get_staking_kton_unmigrated(rpc, metadata) + ledgers = get_storage(rpc, metadata, 'account_migration', 'ledgers', nil, nil) + ledgers.reduce(0) do |sum, ledger| sum + ledger[:storage][:staked_kton] - end / 10**18 - - unstaking = ledgers.reduce(0) do |sum, ledger| - sum + - ledger[:storage][:unstaking_kton].reduce(0) do |sum, item| - sum + item[0] # item[0] is the amount, item[1] is the block number - end - end / 10**18 - - puts "staked kton(unmigrated): #{staking}" - puts "unstaking kton(unmigrated): #{unstaking}" - staking + unstaking + end end #################################################### # migrated accounts #################################################### +def get_staking_kton(rpc, metadata) + ledgers = get_storage(rpc, metadata, 'darwinia_staking', 'ledgers', nil, nil) + ledgers.reduce(0) do |sum, ledger| + sum + ledger[:storage][:staked_kton] + end +end + def get_kton_total_insurance(rpc, metadata) ScaleRb::HttpClient .get_storage2(rpc, 'Assets', 'Asset', nil, metadata) @@ -39,41 +28,14 @@ def get_kton_total_insurance(rpc, metadata) .dig(:storage, :supply) / 10**18 end -def get_staked_and_unstaking_kton(rpc, metadata) - ledgers = - ScaleRb::HttpClient.get_storage2( - rpc, - 'DarwiniaStaking', - 'Ledgers', - nil, - metadata - ) - staking = ledgers.reduce(0) do |sum, ledger| - sum + ledger[:storage][:staked_kton] - end / 10**18 - - unstaking = ledgers.reduce(0) do |sum, ledger| - sum + - ledger[:storage][:unstaking_kton].reduce(0) do |sum, item| - sum + item[0] # item[0] is the amount, item[1] is the block number - end - end / 10**18 - - puts "staked kton: #{staking}" - puts "unstaking kton: #{unstaking}" - staking + unstaking -end - # require 'json' # require 'scale_rb' +# require_relative '../storage' # # require_relative '../../config/config' # config = get_config # metadata = JSON.parse(File.read(config[:metadata][:darwinia])) # rpc = config[:darwinia_rpc] # -# total = get_staked_and_unstaking_kton(rpc, metadata) -# puts "total staking kton: #{total}" -# -# untotal = get_unmigrated_staked_and_unstaking_kton(rpc, metadata) -# puts "total staking kton(unmigrated): #{untotal}" +# puts get_staking_kton_unmigrated(rpc, metadata) +# puts get_staking_kton(rpc, metadata) diff --git a/src/supply/ring.rb b/src/supply/ring.rb index 9dfc4c4..ba4d1c3 100644 --- a/src/supply/ring.rb +++ b/src/supply/ring.rb @@ -1,79 +1,84 @@ +def calc_staking_ring(ledgers) + ledgers.reduce(0) do |sum, ledger| + sum + ledger[:storage][:staked_ring] + end +end + +def calc_staking_ring_in_deposits(ledgers, all_deposits_in_use) + staking_deposit_ids = ledgers.reduce([]) do |acc, ledger| + acc + ledger[:storage][:staked_deposits] + end + + staking_deposit_ids.reduce(0) do |sum, deposit_id| + all_deposits_in_use.key?(deposit_id) ? sum + all_deposits_in_use[deposit_id][:value] : sum + end +end + +def handle_deposits_storages(storages) + storages.each_with_object({}) do |storage, acc| + # { + # :storage_key=>"0x1fb3231abc71c5a12c573bc57e9d12d174a614db8021c6bd0a028aafdf29dd080091926c50a7544a24728ea18e183845ce11f8d5737b5f0783c072fa15e38f64e338f844d4135bd0c311e1ea95513f25", + # :storage=>[ + # {:id=>0, :value=>100000000000000000000000, :start_time=>1605600300003, :expired_time=>1667808300003, :in_use=>true} + # ] + # } + address = "0x#{storage[:storage_key][-40..]}" + items = storage[:storage] + items.each do |item| + acc[address] = item if item[:in_use] + end + end +end + #################################################### # unmigrated accounts #################################################### -# staked and unstaking, but without the ring staked as deposit -def get_unmigrated_staked_and_unstaking_ring(rpc, metadata) - ledgers = - ScaleRb::HttpClient.get_storage2( - rpc, - "AccountMigration", - "Ledgers", - nil, - metadata, - ) - ledgers.reduce(0) do |sum, ledger| - sum + ledger[:storage][:staked_ring] + - ledger[:storage][:unstaking_ring].reduce(0) do |sum, item| - sum + item[0] # item[0] is the amount, item[1] is the block number - end - end / 10**18 -end +def get_all_staking_ring_unmigrated(rpc, metadata) + ledgers = get_storage(rpc, metadata, 'account_migration', 'ledgers', nil, nil) + calc_staking_ring(ledgers) -def get_unmigrated_ring_in_deposit(rpc, metadata) - deposits = - ScaleRb::HttpClient.get_storage2( - rpc, - "AccountMigration", - "Deposits", - nil, - metadata, - ) - deposits.reduce(0) do |sum, deposit| - deposit[:storage].reduce(sum) { |sum, item| sum + item[:value] } - end / 10**18 + # all_deposits_in_use = handle_deposits_storages( + # get_storage(rpc, metadata, 'account_migration', 'deposits', nil, nil) + # ) + # staked_ring_in_deposits = calc_staking_ring_in_deposits(ledgers, all_deposits_in_use) + + # { + # staking_ring:, staked_ring_in_deposits: + # } end #################################################### # migrated accounts #################################################### +def get_all_staking_ring(rpc, metadata) + ledgers = get_storage(rpc, metadata, 'darwinia_staking', 'ledgers', nil, nil) + calc_staking_ring(ledgers) + + # all_deposits_in_use = handle_deposits_storages( + # get_storage(rpc, metadata, 'deposit', 'deposits', nil, nil) + # ) + # + # staked_ring_in_deposits = calc_staking_ring_in_deposits(ledgers, all_deposits_in_use) + # + # { + # staking_ring:, staked_ring_in_deposits: + # } +end + +########################################## def get_total_insurance(rpc, metadata) ScaleRb::HttpClient.get_storage2( rpc, - "Balances", - "TotalIssuance", + 'Balances', + 'TotalIssuance', nil, - metadata, + metadata ) / 10**18 end -def get_staked_and_unstaking_ring(rpc, metadata) - ledgers = - ScaleRb::HttpClient.get_storage2( - rpc, - "DarwiniaStaking", - "Ledgers", - nil, - metadata, - ) - ledgers.reduce(0) do |sum, ledger| - sum + ledger[:storage][:staked_ring] + - ledger[:storage][:unstaking_ring].reduce(0) do |sum, item| - sum + item[0] # item[0] is the amount, item[1] is the block number - end - end / 10**18 -end - -def get_ring_in_deposits(rpc, metadata) - deposits = - ScaleRb::HttpClient.get_storage2(rpc, "Deposit", "Deposits", nil, metadata) - deposits.reduce(0) do |sum, deposit| - deposit[:storage].reduce(sum) { |sum, item| sum + item[:value] } - end / 10**18 -end - def get_reserved_ring(rpc, metadata) accounts = - ScaleRb::HttpClient.get_storage2(rpc, "System", "Account", nil, metadata) + ScaleRb::HttpClient.get_storage2(rpc, 'System', 'Account', nil, metadata) accounts.reduce(0) do |sum, account| sum + account[:storage][:data][:reserved] end / 10**18 @@ -82,8 +87,20 @@ def get_reserved_ring(rpc, metadata) def get_locked_ring(rpc, metadata) # LOCKED locks = - ScaleRb::HttpClient.get_storage2(rpc, "Balances", "Locks", nil, metadata) + ScaleRb::HttpClient.get_storage2(rpc, 'Balances', 'Locks', nil, metadata) locks.reduce(0) do |sum, lock| lock[:storage].reduce(sum) { |sum, item| sum + item[:amount] } end / 10**18 end + +# require 'json' +# require 'scale_rb' +# require_relative '../storage' +# +# require_relative '../../config/config' +# config = get_config +# metadata = JSON.parse(File.read(config[:metadata][:darwinia])) +# rpc = config[:darwinia_rpc] +# +# puts get_all_staking_ring_unmigrated(rpc, metadata) +# puts get_all_staking_ring(rpc, metadata)