# RabbitMQ Peatio Event API ## Overview of RabbitMQ details Peatio submits all events into three exchanges depending on event category (read next). The exchange name consists of three parts: 1) application name, like `peatio`, `barong`. 2) fixed keyword `events`. 3) category of event, like `system` (generic system event), `model` (the attributes of some record were updated), `market` (trading events). The routing key looks like `deposit.updated`, `btcusd.new_order`. The event name matches the routing key but with event category appended at the beginning, like `model.deposit.updated`, `market.btcusd.new_order`. ## Overview of RabbitMQ message Each produced message in `Event API` is JWT (complete format). This is very similar to `Management API`. The example below demonstrates both generation and verification of JWT: ```ruby require "jwt-multisig" require "securerandom" jwt_payload = { iss: "peatio", jti: SecureRandom.uuid, iat: Time.now.to_i, exp: Time.now.to_i + 60, event: {} } require "openssl" private_key = OpenSSL::PKey::RSA.generate(2048) public_key = private_key.public_key generated_jwt = JWT::Multisig.generate_jwt(jwt_payload, { peatio: private_key }, { peatio: "RS256" }) Kernel.puts "GENERATED JWT", generated_jwt.to_json, "\n" verification_result = JWT::Multisig.verify_jwt generated_jwt.deep_stringify_keys, \ { peatio: public_key }, { verify_iss: true, iss: "peatio", verify_jti: true } decoded_jwt_payload = verification_result[:payload] Kernel.puts "MATCH AFTER VERIFICATION: #{jwt_payload == decoded_jwt_payload}." ``` The RabbitMQ message is stored in JWT field called `event`. ## Overview of Event API message The typical event looks like (JSON): ```ruby event: { name: "model.deposit.updated", foo: "...", bar: "...", qux: "..." } ``` The field `event[:name]` contains event name (same as routing key). The fields `foo`, `bar`, `qux` (just for example) are fields which carry useful information. ## Format of `model.deposit.created` event ```ruby event: { name: "model.deposit.created", record: { tid: "TID9493F6CD41", user: { uid: "ID092B2AF8E87", email: "john@doe.com" }, uid: "ID092B2AF8E87", currency: "btc", amount: "0.0855", state: "submitted", created_at: "2018-04-12T17:16:06+03:00", updated_at: "2018-04-12T17:16:06+03:00", completed_at: nil, blockchain_address: "n1Ytj6Hy57YpfueA2vtmnwJQs583bpYn7W", blockchain_txid: "c37ae1677c4c989dbde9ac22be1f3ff3ac67ed24732a9fa8c9258fdff0232d72", blockchain_confirmations: 1 } } ``` | Field | Description | | ---------- | ----------------------------------- | | `record` | The up-to-date deposit attributes. | ## Format of `model.deposit.updated` event ```ruby event: { name: "model.deposit.updated", record: { tid: "TID9493F6CD41", user: { uid: "ID092B2AF8E87", email: "john@doe.com" }, uid: "ID092B2AF8E87", currency: "btc", amount: "0.0855", state: "accepted", created_at: "2018-04-12T17:16:06+03:00", updated_at: "2018-04-12T18:46:57+03:00", completed_at: "2018-04-12T18:46:57+03:00", blockchain_address: "n1Ytj6Hy57YpfueA2vtmnwJQs583bpYn7W", blockchain_txid: "c37ae1677c4c989dbde9ac22be1f3ff3ac67ed24732a9fa8c9258fdff0232d72", blockchain_confirmations: 7 }, changes: { state: "submitted", completed_at: nil, blockchain_confirmations: 1, updated_at: "2018-04-12T17:16:06+03:00" } } ``` | Field | Description | | ---------- | ------------------------------------------------ | | `record` | The up-to-date deposit attributes. | | `changes` | The changed deposit attributes and their values. | ## Format of `model.withdraw.created` event ```ruby event: { name: "model.withdraw.created", record: { tid: "TID892F29F094", user: { uid: "ID092B2AF8E87", email: "john@doe.com" }, uid: "ID092B2AF8E87", rid: "0xdA35deE8EDDeAA556e4c26268463e26FB91ff74f", currency: "eth", amount: "4.5485", fee: "0.0015", state: "prepared", created_at: "2018-04-12T18:52:16+03:00", updated_at: "2018-04-12T18:52:16+03:00", completed_at: nil, blockchain_txid: nil } } ``` | Field | Description | | ---------- | ------------------------------------ | | `record` | The up-to-date withdraw attributes. | ## Format of `model.withdraw.updated` event ```ruby event: { name: "model.withdraw.updated", record: { tid: "TID892F29F094", user: { uid: "ID092B2AF8E87", email: "john@doe.com" }, uid: "ID092B2AF8E87", rid: "0xdA35deE8EDDeAA556e4c26268463e26FB91ff74f", currency: "eth", amount: "4.5485", fee: "0.0015", state: "succeed", created_at: "2018-04-12T18:52:16+03:00", updated_at: "2018-04-12T18:56:23+03:00", completed_at: "2018-04-12T18:56:23+03:00", blockchain_txid: "0x9c34d1750e225a95938f9884e857ab6f55eedda43b159d13abf773fe6a916164" }, changes: { state: "processing", updated_at: "2018-04-12T18:55:39+03:00", completed_at: "2018-04-12T18:55:39+03:00", blockchain_txid: nil } } ``` | Field | Description | | ---------- | ------------------------------------------------ | | `record` | The up-to-date withdraw attributes. | | `changes` | The changed withdraw attributes and their values. | ## Format of `model.account.created` event ```ruby event: { name: "model.account.created", record: { id: "1", member_id: "2", currency_id: "btc", balance: "0", locked: "0", created_at: "2018-04-12T17:16:06+03:00", updated_at: "2018-04-12T17:16:06+03:00", } } ``` | Field | Description | | ---------- | ----------------------------------- | | `record` | The up-to-date account attributes. | ## Format of `model.account.updated` event ```ruby event: { name: "model.account.updated", record: { id: "1", member_id: "2", currency_id: "btc", balance: "1", locked: "0", created_at: "2018-04-12T17:16:06+03:00", updated_at: "2018-04-12T17:17:06+03:00", }, changes: { balance: "0", updated_at: "2018-04-12T17:16:06+03:00" } } ``` | Field | Description | | ---------- | ------------------------------------------------ | | `record` | The up-to-date account attributes. | | `changes` | The changed account attributes and their values. | ## Format of `system.low_hot_wallet_balance` event ```ruby event: { name: "system.system.low_hot_wallet_balance", currency: "btc", balance: "2.82480099" } ``` | Field | Description | | ---------- | ----------------------- | | `currency` | The currency code. | | `balance` | The up-to-date balance. | ## Format of `market.btcusd.order_created` event Buy 14 BTC for 0.42 USD (0.03 USD per BTC). ```ruby event: { name: "market.btcusd.order_created", market: "btcusd", type: "buy", trader_uid: "ID022H2NF6E87", income_unit: "btc", income_fee_type: "relative", income_fee_value: "0.0015", outcome_unit: "usd", outcome_fee_type: "relative", outcome_fee_value: "0.0", initial_income_amount: "14.0", current_income_amount: "14.0", initial_outcome_amount: "0.42", current_outcome_amount: "0.42", strategy: "limit", price: "0.03", state: "open", trades_count: 0, created_at: "2018-05-07T02:12:28Z" } ``` ## Format of `market.btcusd.order_updated` event Sell 100 BTC for 3 USD (0.03 USD per BTC). ```ruby event: { name: "market.btcusd.order_updated", market: "btcusd", type: "sell", trader_uid: "ID092B2AF8E87", income_unit: "usd", income_fee_type: "relative", income_fee_value: "0.0015", outcome_unit: "btc", outcome_fee_type: "relative", outcome_fee_value: "0.0", initial_income_amount: "3.0", current_income_amount: "2.4", previous_income_amount: "3.0", initial_outcome_amount: "100.0", current_outcome_amount: "80.0", previous_outcome_amount: "100.0", strategy: "limit", price: "0.03", state: "open", trades_count: 1, created_at: "2018-05-07T02:12:28Z", updated_at: "2018-05-08T10:13:13Z" } ``` ## Format of `market.btcusd.order_canceled` event Sell 100 BTC for 3 USD (0.03 USD per BTC). ```ruby event: { name: "market.btcusd.order_canceled", market: "btcusd", type: "sell", trader_uid: "ID092B2AF8E87", income_unit: "usd", income_fee_type: "relative", income_fee_value: "0.0015", outcome_unit: "btc", outcome_fee_type: "relative", outcome_fee_value: "0.0", initial_income_amount: "3.0", current_income_amount: "3.0", initial_outcome_amount: "100.0", current_outcome_amount: "100.0", strategy: "limit", price: "0.03", state: "canceled", trades_count: 0, created_at: "2018-05-07T02:12:28Z", canceled_at: "2018-05-08T10:13:13Z" } ``` ## Format of `market.btcusd.order_completed` event Sell 100 BTC for 3 USD (0.03 USD per BTC). ```ruby event: { name: "market.btcusd.order_completed", market: "btcusd", type: "sell", trader_uid: "ID092B2AF8E87", income_unit: "usd", income_fee_type: "relative", income_fee_value: "0.0015", outcome_unit: "btc", outcome_fee_type: "relative", outcome_fee_value: "0.0", initial_income_amount: "3.0", current_income_amount: "0.0", previous_income_amount: "3.0", initial_outcome_amount: "100.0", current_outcome_amount: "0.0", previous_outcome_amount: "100.0", strategy: "limit", price: "0.03", state: "completed", trades_count: 1, created_at: "2018-05-07T02:12:28Z", completed_at: "2018-05-07T17:32:09Z" } ``` ## Format of `market.btcusd.trade_completed` event ```ruby event: { name: "market.btcusd.trade_completed", market: "btcusd", price: "0.03", buyer_uid: "ID022H2NF6E87", buyer_income_unit: "btc", buyer_income_amount: "14", buyer_income_fee: "0.021", buyer_outcome_unit: "usd", buyer_outcome_amount: "0.42", buyer_outcome_fee: "0.0", seller_uid: "ID092B2AF8E87", seller_income_unit: "usd", seller_income_amount: "0.42", seller_income_fee: "0.00063", seller_outcome_unit: "btc", seller_outcome_amount: "14.0", seller_outcome_fee: "0.0", completed_at: "2018-05-07T17:32:09Z" } ``` ## Producing events using Ruby ```ruby require "bunny" def generate_jwt(jwt_payload) Kernel.abort "Please, see «Overview of RabbitMQ message» for implementation guide." end Bunny.run host: "localhost", port: 5672, username: "guest", password: "guest" do |session| channel = session.channel exchange = channel.direct("peatio.events.model") jwt_payload = { iss: "peatio", jti: SecureRandom.uuid, iat: Time.now.to_i, exp: Time.now.to_i + 60, event: { name: "model.deposit.created", record: { tid: "TID9493F6CD41", user: { uid: "ID092B2AF8E87", email: "john@doe.com" }, uid: "ID092B2AF8E87", currency: "btc", amount: "0.0855", state: "submitted", created_at: "2018-04-12T17:16:06+03:00", updated_at: "2018-04-12T17:16:06+03:00", completed_at: nil, blockchain_address: "n1Ytj6Hy57YpfueA2vtmnwJQs583bpYn7W", blockchain_txid: "c37ae1677c4c989dbde9ac22be1f3ff3ac67ed24732a9fa8c9258fdff0232d72", blockchain_confirmations: 1 } } } exchange.publish(generate_jwt(jwt_payload), routing_key: "deposit.created") end ``` IMPORTANT: Don't forget to implement the logic for JWT exception handling! ## Producing events using `rabbitmqadmin` `rabbitmqadmin publish routing_key=deposit.created payload=JWT exchange=peatio.events.model` Don't forget to pass environment variable `JWT`. ## Consuming events using Ruby ```ruby require "bunny" def verify_jwt(jwt_payload) Kernel.abort "Please, see «Overview of RabbitMQ message» for implementation guide." end Bunny.run host: "localhost", port: 5672, username: "guest", password: "guest" do |session| channel = session.channel exchange = channel.direct("peatio.events.model") queue = channel.queue("", auto_delete: true, durable: true, exclusive: true) .bind(exchange, routing_key: "deposit.updated") queue.subscribe manual_ack: true, block: true do |delivery_info, metadata, payload| Kernel.puts verify_jwt(JSON.parse(payload)).fetch(:event) channel.ack(delivery_info.delivery_tag) rescue => e channel.nack(delivery_info.delivery_tag, false, true) end end ``` IMPORTANT: Don't forget to implement the logic for JWT exception handling!