Skip to content

Commit

Permalink
Issue 508 (#1557)
Browse files Browse the repository at this point in the history
* feat: parse omiga inscription info cell data

Signed-off-by: Miles Zhang <[email protected]>

* feat: create omiga_inscription_info model

Signed-off-by: Miles Zhang <[email protected]>

* feat: save omiga inscription info and udt in sync process

Signed-off-by: Miles Zhang <[email protected]>

* feat: add omiga_inscription api

Signed-off-by: Miles Zhang <[email protected]>

* test: fix test

Signed-off-by: Miles Zhang <[email protected]>

---------

Signed-off-by: Miles Zhang <[email protected]>
  • Loading branch information
zmcNotafraid authored Jan 9, 2024
1 parent 789be08 commit 161b02d
Show file tree
Hide file tree
Showing 23 changed files with 760 additions and 118 deletions.
67 changes: 67 additions & 0 deletions app/controllers/api/v1/omiga_inscriptions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
module Api
module V1
class OmigaInscriptionsController < ApplicationController
before_action :validate_query_params, only: :show
before_action :validate_pagination_params, :pagination_params,
only: :index

def index
udts = Udt.omiga_inscription

if stale?(udts)
udts = sort_udts(udts).page(@page).per(@page_size).fast_page
options = FastJsonapi::PaginationMetaGenerator.new(
request:,
records: udts,
page: @page,
page_size: @page_size,
).call

render json: UdtSerializer.new(udts, options)
end
end

def show
udt = Udt.find_by!(type_hash: params[:id])
render json: UdtSerializer.new(udt)
rescue ActiveRecord::RecordNotFound
raise Api::V1::Exceptions::UdtNotFoundError
end

private

def validate_query_params
validator = Validations::Udt.new(params)

if validator.invalid?
errors = validator.error_object[:errors]
status = validator.error_object[:status]

render json: errors, status:
end
end

def pagination_params
@page = params[:page] || 1
@page_size = params[:page_size] || Udt.default_per_page
end

def sort_udts(records)
sort, order = params.fetch(:sort, "id.desc").split(".", 2)
sort =
case sort
when "created_time" then "block_timestamp"
when "transactions" then "h24_ckb_transactions_count"
when "addresses_count" then "addresses_count"
else "id"
end

if order.nil? || !order.match?(/^(asc|desc)$/i)
order = "asc"
end

records.order("#{sort} #{order}")
end
end
end
end
16 changes: 10 additions & 6 deletions app/models/cell_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ class CellInput < ApplicationRecord
belongs_to :previous_cell_output, class_name: "CellOutput", optional: true
belongs_to :block, optional: true

delegate :lock_script, :type_script, to: :previous_cell_output, allow_nil: true
delegate :lock_script, :type_script, to: :previous_cell_output,
allow_nil: true

enum cell_type: {
normal: 0, nervos_dao_deposit: 1, nervos_dao_withdrawing: 2, udt: 3, m_nft_issuer: 4,
m_nft_class: 5, m_nft_token: 6, nrc_721_token: 7, nrc_721_factory: 8, cota_registry: 9,
cota_regular: 10, spore_cluster: 11, spore_cell: 12 }
cota_regular: 10, spore_cluster: 11, spore_cell: 12, omiga_inscription_info: 13, omiga_inscription: 14,
xudt: 15
}

def output
previous_cell_output
end
Expand All @@ -24,17 +28,17 @@ def to_raw
{
previous_output: {
index: "0x#{(previous_index || previous_cell_output.cell_index).to_s(16)}",
tx_hash: previous_tx_hash || previous_cell_output.tx_hash
tx_hash: previous_tx_hash || previous_cell_output.tx_hash,
},
since: hex_since
since: hex_since,
}
else
{
previous_output: {
index: "0xffffffff",
tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
tx_hash: "0x0000000000000000000000000000000000000000000000000000000000000000",
},
since: hex_since
since: hex_since,
}
end
end
Expand Down
93 changes: 59 additions & 34 deletions app/models/cell_output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ class CellOutput < ApplicationRecord
cota_registry: 9,
cota_regular: 10,
spore_cluster: 11,
spore_cell: 12
spore_cell: 12,
omiga_inscription_info: 13,
omiga_inscription: 14,
xudt: 15
}

belongs_to :ckb_transaction
Expand All @@ -35,10 +38,12 @@ class CellOutput < ApplicationRecord
belongs_to :lock_script
belongs_to :type_script, optional: true

has_many :cell_dependencies, foreign_key: :contract_cell_id, dependent: :delete_all
has_many :cell_dependencies, foreign_key: :contract_cell_id,
dependent: :delete_all
has_one :cell_datum, class_name: "CellDatum", dependent: :destroy_async
accepts_nested_attributes_for :cell_datum
validates :capacity, presence: true, numericality: { greater_than_or_equal_to: 0 }
validates :capacity, presence: true,
numericality: { greater_than_or_equal_to: 0 }

# on-chain cell outputs must be included in certain block
validates :block, presence: true, if: -> { live? or dead? }
Expand All @@ -50,7 +55,8 @@ class CellOutput < ApplicationRecord
validates :consumed_by, presence: true, if: :dead?

# cell output must not have consumed_by_id set when it's live
validates :consumed_by_id, :consumed_block_timestamp, must_be_nil: true, if: :live?
validates :consumed_by_id, :consumed_block_timestamp, must_be_nil: true,
if: :live?

# consumed timestamp must be always greater than committed timestamp
validates :consumed_block_timestamp, numericality: { greater_than_or_equal_to: :block_timestamp },
Expand All @@ -60,22 +66,32 @@ class CellOutput < ApplicationRecord

attr_accessor :raw_address

scope :consumed_after, ->(block_timestamp) { where("consumed_block_timestamp >= ?", block_timestamp) }
scope :consumed_before, ->(block_timestamp) { where("consumed_block_timestamp <= ?", block_timestamp) }
scope :consumed_after, ->(block_timestamp) {
where("consumed_block_timestamp >= ?", block_timestamp)
}
scope :consumed_before, ->(block_timestamp) {
where("consumed_block_timestamp <= ?", block_timestamp)
}
scope :consumed_between, ->(start_timestamp, end_timestamp) {
consumed_after(start_timestamp).consumed_before(end_timestamp)
}
scope :unconsumed_at, ->(block_timestamp) {
where("consumed_block_timestamp > ? or consumed_block_timestamp = 0 or consumed_block_timestamp is null", block_timestamp)
}
scope :generated_after, ->(block_timestamp) { where("block_timestamp >= ?", block_timestamp) }
scope :generated_before, ->(block_timestamp) { where("block_timestamp <= ?", block_timestamp) }
scope :generated_after, ->(block_timestamp) {
where("block_timestamp >= ?", block_timestamp)
}
scope :generated_before, ->(block_timestamp) {
where("block_timestamp <= ?", block_timestamp)
}
scope :generated_between, ->(start_timestamp, end_timestamp) {
generated_after(start_timestamp).generated_before(end_timestamp)
}
scope :inner_block, ->(block_id) { where("block_id = ?", block_id) }
scope :free, -> { where(type_hash: nil, data_hash: nil) }
scope :occupied, -> { where.not(type_hash: nil).or(where.not(data_hash: nil)) }
scope :occupied, -> {
where.not(type_hash: nil).or(where.not(data_hash: nil))
}

before_create :setup_address

Expand All @@ -102,7 +118,10 @@ def binary_data
end

def setup_address
self.address = Address.find_or_create_by_address_hash(raw_address, block_timestamp) if raw_address
if raw_address
self.address = Address.find_or_create_by_address_hash(raw_address,
block_timestamp)
end
end

# @return [Boolean]
Expand Down Expand Up @@ -133,20 +152,24 @@ def self.find_by_pointer(tx_hash, index)
expires_in: 1.day) do
tx_id = CkbTransaction.tx_committed.find_by_tx_hash(tx_hash)&.id
Rails.logger.info("find_by_pointer: tx_hash: #{tx_hash}, index: #{index}, tx_id: #{tx_id}")
find_by(ckb_transaction_id: tx_id, cell_index: index.is_a?(String) ? index.hex : index) if tx_id
if tx_id
find_by(ckb_transaction_id: tx_id,
cell_index: index.is_a?(String) ? index.hex : index)
end
end
end

def node_output
lock = CKB::Types::Script.new(**lock_script.to_node)
type = type_script.present? ? CKB::Types::Script.new(**type_script.to_node) : nil
CKB::Types::Output.new(capacity: capacity.to_i, lock: lock, type: type)
CKB::Types::Output.new(capacity: capacity.to_i, lock:, type:)
end

# calculate the actual size of the cell output on chain
# @return [Integer]
def calculate_bytesize
[8, binary_data&.bytesize || 0, lock_script.calculate_bytesize, type_script&.calculate_bytesize || 0].sum
[8, binary_data&.bytesize || 0, lock_script.calculate_bytesize,
type_script&.calculate_bytesize || 0].sum
end

def calculate_min_capacity
Expand All @@ -157,22 +180,22 @@ def to_raw
{
capacity: "0x#{capacity.to_i.to_s(16)}",
lock: lock_script&.to_node,
type: type_script&.to_node
type: type_script&.to_node,
}
end

def udt_info
return unless udt?

udt_info = Udt.find_by(type_hash: type_hash, published: true)
udt_info = Udt.find_by(type_hash:, published: true)
CkbUtils.hash_value_to_s(
symbol: udt_info&.symbol,
amount: udt_amount,
decimal: udt_info&.decimal,
type_hash: type_hash,
type_hash:,
published: !!udt_info&.published,
display_name: udt_info&.display_name,
uan: udt_info&.uan
uan: udt_info&.uan,
)
end

Expand All @@ -194,7 +217,8 @@ def m_nft_info
parsed_class_data = CkbUtils.parse_token_class_data(m_nft_class_cell.data)
value = {
class_name: parsed_class_data.name, token_id: type_script.args[50..-1],
total: parsed_class_data.total }
total: parsed_class_data.total
}
else
value = { class_name: "", token_id: nil, total: "" }
end
Expand All @@ -209,32 +233,33 @@ def nrc_721_nft_info

case cell_type
when "nrc_721_factory"
factory_cell_type_script = self.type_script
factory_cell_type_script = type_script
factory_cell = NrcFactoryCell.find_by(code_hash: factory_cell_type_script.code_hash,
hash_type: factory_cell_type_script.hash_type,
args: factory_cell_type_script.args,
verified: true)
value = {
symbol: factory_cell&.symbol,
amount: self.udt_amount,
amount: udt_amount,
decimal: "",
type_hash: self.type_hash,
type_hash:,
published: factory_cell&.verified,
display_name: factory_cell&.name,
nan: ""
nan: "",
}
when "nrc_721_token"
udt = Udt.find_by(type_hash: type_hash)
factory_cell = NrcFactoryCell.where(id: udt.nrc_factory_cell_id, verified: true).first
udt = Udt.find_by(type_hash:)
factory_cell = NrcFactoryCell.where(id: udt.nrc_factory_cell_id,
verified: true).first
udt_account = UdtAccount.where(udt_id: udt.id).first
value = {
symbol: factory_cell&.symbol,
amount: udt_account.nft_token_id,
decimal: udt_account.decimal,
type_hash: type_hash,
type_hash:,
published: true,
display_name: udt_account.full_name,
uan: ""
uan: "",
}
else
raise "invalid cell type"
Expand All @@ -251,12 +276,12 @@ def create_token
name: parsed_class_data.name,
cell_id: id,
icon_url: parsed_class_data.renderer,
creator_id: address.id
creator_id: address.id,
)
when "m_nft_token"
m_nft_class_type = TypeScript.where(
code_hash: CkbSync::Api.instance.token_class_script_code_hash,
args: type_script.args[0..49]
args: type_script.args[0..49],
).first
if m_nft_class_type.present?
m_nft_class_cell = m_nft_class_type.cell_outputs.last
Expand All @@ -266,12 +291,12 @@ def create_token
name: parsed_class_data.name,
cell_id: m_nft_class_cell.id,
creator_id: m_nft_class_cell.address_id,
icon_url: parsed_class_data.renderer
icon_url: parsed_class_data.renderer,
)
item = coll.items.find_or_create_by(
token_id: type_script.args[50..-1].hex,
owner_id: address_id,
cell_id: id
cell_id: id,
)
end
end
Expand Down Expand Up @@ -340,16 +365,16 @@ def cota_registry_info
return unless cota_registry?

code_hash = CkbSync::Api.instance.cota_registry_code_hash
CkbUtils.hash_value_to_s(symbol: "", amount: self.udt_amount, decimal: "", type_hash: self.type_hash,
published: "true", display_name: "", uan: "", code_hash: code_hash)
CkbUtils.hash_value_to_s(symbol: "", amount: udt_amount, decimal: "", type_hash:,
published: "true", display_name: "", uan: "", code_hash:)
end

def cota_regular_info
return unless cota_regular?

code_hash = CkbSync::Api.instance.cota_regular_code_hash
CkbUtils.hash_value_to_s(symbol: "", amount: self.udt_amount, decimal: "", type_hash: self.type_hash,
published: "true", display_name: "", uan: "", code_hash: code_hash)
CkbUtils.hash_value_to_s(symbol: "", amount: udt_amount, decimal: "", type_hash:,
published: "true", display_name: "", uan: "", code_hash:)
end
end

Expand Down
Loading

0 comments on commit 161b02d

Please sign in to comment.