diff --git a/lib/ckb/api.rb b/lib/ckb/api.rb index 074d6a1c..cf4680e0 100644 --- a/lib/ckb/api.rb +++ b/lib/ckb/api.rb @@ -175,6 +175,14 @@ def dry_run_transaction(transaction) Types::DryRunResult.from_h(result) end + # @param out_point [CKB::Types::OutPoint] + # @param hash [String] + # + # @return [String] + def calculate_dao_maximum_withdraw(out_point, hash) + rpc.calculate_dao_maximum_withdraw(out_point.to_h, hash) + end + def inspect "\#" end diff --git a/lib/ckb/rpc.rb b/lib/ckb/rpc.rb index 74f3a910..23530110 100644 --- a/lib/ckb/rpc.rb +++ b/lib/ckb/rpc.rb @@ -101,6 +101,10 @@ def dry_run_transaction(transaction) rpc_request("dry_run_transaction", params: [transaction]) end + def calculate_dao_maximum_withdraw(out_point, hash) + rpc_request("calculate_dao_maximum_withdraw", params: [out_point, hash]) + end + def inspect "\#" end diff --git a/lib/ckb/wallet.rb b/lib/ckb/wallet.rb index e831687a..a51b33d1 100644 --- a/lib/ckb/wallet.rb +++ b/lib/ckb/wallet.rb @@ -5,6 +5,16 @@ module CKB MIN_CELL_CAPACITY = 40 * (10**8) + DAO_CODE_HASH = "0x0000000000000000000000000000004e4552564f5344414f434f444530303031" + + DAO_ISSUING_OUT_POINT = Types::OutPoint.new( + cell: Types::CellOutPoint.new( + tx_hash: "0x00000000000000000000000000004e4552564f5344414f494e50555430303031", + index: 0)) + + DAO_LOCK_PERIOD_BLOCKS = 10 + DAO_MATURITY_BLOCKS = 5 + class Wallet attr_reader :api # privkey is a bin string @@ -77,6 +87,74 @@ def send_capacity(target_address, capacity) send_transaction(tx) end + def deposit_to_dao(capacity) + i = gather_inputs(capacity, MIN_CELL_CAPACITY) + input_capacities = i.capacities + + outputs = [ + Types::Output.new( + capacity: capacity, + lock: Types::Script.generate_lock(@key.address.blake160, DAO_CODE_HASH) + ) + ] + if input_capacities > capacity + outputs << Types::Output.new( + capacity: input_capacities - capacity, + lock: lock + ) + end + + tx = Types::Transaction.new( + version: 0, + deps: [api.system_script_out_point], + inputs: i.inputs, + outputs: outputs + ) + tx_hash = api.compute_transaction_hash(tx) + send_transaction(tx.sign(key, tx_hash)) + + Types::OutPoint.new(cell: Types::CellOutPoint.new(tx_hash: tx_hash, index: 0)) + end + + def generate_withdraw_from_dao_transaction(cell_out_point) + cell_status = api.get_live_cell(cell_out_point) + unless cell_status.status == "live" + raise "Cell is not yet live!" + end + tx = api.get_transaction(cell_out_point.cell.tx_hash) + unless tx.tx_status.status == "committed" + raise "Transaction is not commtted yet!" + end + deposit_block = api.get_block(tx.tx_status.block_hash).header + deposit_block_number = deposit_block.number.to_i + current_block = api.get_tip_header + current_block_number = current_block.number.to_i + + windowleft = DAO_LOCK_PERIOD_BLOCKS - (current_block_number - deposit_block_number) % DAO_LOCK_PERIOD_BLOCKS + windowleft = DAO_MATURITY_BLOCKS if windowleft < DAO_MATURITY_BLOCKS + since = current_block_number + windowleft + 1 + + output_capacity = api.calculate_dao_maximum_withdraw(cell_out_point, current_block.hash).to_i + + new_cell_out_point = Types::OutPoint.new( + block_hash: deposit_block.hash, + cell: cell_out_point.cell.dup + ) + tx = Types::Transaction.new( + version: 0, + deps: [{block_hash: current_block.hash}], + inputs: [ + Types::Input.new(args: [current_block.hash], previous_output: new_cell_out_point, since: since), + Types::Input.new(args: [], previous_output: DAO_ISSUING_OUT_POINT) + ], + outputs: [ + Types::Output.new(capacity: output_capacity, lock: lock) + ] + ) + tx_hash = api.compute_transaction_hash(tx) + tx = tx.sign(key, tx_hash) + end + # @param hash_hex [String] "0x..." # # @return [CKB::Types::Transaction]