Initial commit
This commit is contained in:
BIN
docs/zagros/Dena-document.pdf
Normal file
BIN
docs/zagros/Dena-document.pdf
Normal file
Binary file not shown.
24
docs/zagros/big-picture.md
Normal file
24
docs/zagros/big-picture.md
Normal file
@@ -0,0 +1,24 @@
|
||||
```mermaid
|
||||
graph LR
|
||||
A[client] -->|request| B(proxy)
|
||||
B --> |private_ip|C(BaseApp)
|
||||
B --> D(Gateway)
|
||||
D --> |private_ip|E(peatio)
|
||||
D --> |private_ip|F(barong)
|
||||
D --> |private_ip|G(ranger)
|
||||
F --> |database|H(mysql)
|
||||
E --> |database|H
|
||||
F --> |queue|I(rabbitmQ)
|
||||
E --> K(processor)
|
||||
E --> L(matching)
|
||||
E --> M(executor)
|
||||
K --> |queue|I
|
||||
L --> |queue|I
|
||||
M --> |queue|I
|
||||
|
||||
G --> |queue|I
|
||||
E --> |timebase database|J(influxDB)
|
||||
E --> |encrypt and decrypt|vault
|
||||
F --> |encrypt and decrypt|vault
|
||||
|
||||
```
|
||||
47
docs/zagros/blockchain/set-up-bitcoin.md
Normal file
47
docs/zagros/blockchain/set-up-bitcoin.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Blockchain : Bitcoin
|
||||
## how setup node
|
||||
|
||||
First, install bitcoind (Daemon for connecting main Bitcoin Blockchain), follow below guide sites:
|
||||
- [1 setup](https://gist.github.com/rjmacarthy/b56497a81a6497bfabb1)
|
||||
- [2 setup](https://stopanddecrypt.medium.com/a-complete-beginners-guide-to-installing-a-bitcoin-full-node-on-linux-2021-edition-46bf20fbe8ff)
|
||||
- [3 setup](https://www.devmanuals.net/install/ubuntu/ubuntu-12-04-lts-precise-pangolin/install-bitcoind.html)
|
||||
|
||||
so run daemon and must be uptodate and contains all of blocks<br/>
|
||||
** Start bitcoind as daemon** <br/>
|
||||
*bitcoind --daemon*
|
||||
|
||||
### then create wallet or if created before, must load them:<br/>
|
||||
|
||||
#### for loading wallet
|
||||
first ssh on btc server , then:<br>
|
||||
*bitcoin-cli loadwallet btc-hot*<br/>
|
||||
*bitcoin-cli -testnet loadwallet btc-dep*
|
||||
|
||||
#### for create walelt
|
||||
*bitcoin-cli -testnet createwallet btc-fee*<br/>
|
||||
*bitcoin-cli createwallet btc-dep*<br/>
|
||||
|
||||
###### `btc-dep` or `btc-hot` is optional name
|
||||
|
||||
### So, create new address by each wallet and keep them for next step (create wallet in panel)
|
||||
- bitcoin-cli -testnet -rpcwallet=btc-fee getnewaddress
|
||||
- bitcoin-cli -rpcwallet=btc-dep getnewaddress
|
||||
- bitcoin-cli -testnet -rpcwallet=btc-fee getnewaddress
|
||||
|
||||
### Now create relative blockchain, currency and wallet record in the panel
|
||||
[follow this guide site](https://medium.com/openware/how-to-configure-blockchain-node-in-the-tower-opendax-5e75e3264e18) <br/>
|
||||
|
||||
example for blockchain server field:
|
||||
- http://rpcuser:rpcpass@46.209.13.2:18332
|
||||
- http://rpcuser:rpcpass@192.168.15.100:8332
|
||||
|
||||
example for wallet uri field:
|
||||
- http://rpcuser:rpcpass@185.194.78.52:#{port}/wallet/#{wallet_name}
|
||||
- http://user1:changeme@46.209.13.2:18332/wallet/btc-dep
|
||||
|
||||
`18332`, `8332` these are ports that daemon listen on it, and the Peatio talks to it with `jsonrpc`.<br/>
|
||||
**ports**, **user** and **password** can be set in this file : `bitcoin.conf`
|
||||
- regtest ports are 18443, 18444
|
||||
- testnet ports are 18332, 18333
|
||||
- mainnet ports are 8332, 8333
|
||||
|
||||
87
docs/zagros/blockchain/set-up-eth-node.md
Normal file
87
docs/zagros/blockchain/set-up-eth-node.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# ether: set up node
|
||||
|
||||
###### Sprint: ?
|
||||
|
||||
|
||||
###DOC
|
||||
|
||||
we setup our node with geth.Geth(Go Ethereum) is a command line interface for running Ethereum node implemented in Go Language. Using Geth you can join Ethereum network, transfer ether between accounts or even mine ethers.
|
||||
|
||||
|
||||
###steup
|
||||
|
||||
You can start Geth in one of three different sync modes using the --syncmode "<mode>" argument that determines what sort of node it is in the network.
|
||||
|
||||
These are:
|
||||
|
||||
1. Full: Downloads all blocks (including headers, transactions, and receipts) and generates the state of the blockchain incrementally by executing every block.
|
||||
2. Fast: Downloads all blocks (including headers, transactions and receipts), verifies all headers, and downloads the state and verifies it against the headers.
|
||||
3. Snap (Default): Same functionality as fast, but with a faster algorithm.
|
||||
4. Light: Downloads all block headers, block data, and verifies some randomly.
|
||||
|
||||
we used light mode to better speed in syncing and decrease needed storage.
|
||||
|
||||
|
||||
Ethereum has many networks:
|
||||
1. mainnet
|
||||
2. testnet
|
||||
1. Görli(goerli)<br >
|
||||
A proof-of-authority testnet that works across clients.
|
||||
|
||||
2. Kovan:<br >
|
||||
A proof-of-authority testnet for those running OpenEthereum clients.
|
||||
|
||||
3. Rinkeby:<br >
|
||||
A proof-of-authority testnet for those running Geth client.
|
||||
4. Ropsten:<br >
|
||||
A proof-of-work testnet. This means it's the best like-for-like representation of Ethereum.
|
||||
|
||||
|
||||
we wrote an script to setup eth node:
|
||||
|
||||
```shell
|
||||
geth --goerli --http --http.vhosts="" --http.addr=0.0.0.0 --datadir /home/ubuntu/.ethereum --rpcaddr=0.0.0.0 --rpcport=8545 --port=30303 --rpcapi="admin,db,debug,personal,eth,net,web3" --rpccorsdomain="" --rpcvhosts="*" --syncmode="light" --cache=2048 --allow-insecure-unlock --nousb
|
||||
```
|
||||
* in goerli testnet and light mode
|
||||
|
||||
you can see more detail in [geth docs](https://geth.ethereum.org/docs/interface/command-line-options) or use
|
||||
```shell
|
||||
geth --help
|
||||
```
|
||||
after installation
|
||||
|
||||
|
||||
###some commands and tips
|
||||
1. install the geth on your machine<br/>
|
||||
commands for ubuntu
|
||||
- sudo add-apt-repository -y ppa:ethereum/ethereum
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install ethereum
|
||||
2. connect to console of Eth server:
|
||||
geth attach `http://ip:prot`
|
||||
3. personal.newAccount()<br >
|
||||
Generates a new private key and stores it in the key store directory. The key file is encrypted with the given passphrase. Returns the address of the new account.<br >
|
||||
At the geth console, newAccount will prompt for a passphrase when it is not supplied as the argument.
|
||||
```shell
|
||||
> personal.newAccount()
|
||||
Passphrase:
|
||||
Repeat passphrase:
|
||||
"0x5e97870f263700f46aa00d967821199b9bc5a120"
|
||||
```
|
||||
|
||||
2. for checking that geth is updated or not you can use:
|
||||
```shell
|
||||
> eth
|
||||
```
|
||||
for all informations
|
||||
```shell
|
||||
> eth.blockNumber
|
||||
```
|
||||
for getting only last received block<br >
|
||||
and compare it with [etherscan](https://etherscan.io/)
|
||||
|
||||
3. to connect to your node with js console you can use:
|
||||
```shell
|
||||
geth attach {$your_node_anddress}
|
||||
```
|
||||
|
||||
51
docs/zagros/deposit/blockchain.md
Normal file
51
docs/zagros/deposit/blockchain.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Blockchain Deposit
|
||||
[please read first](daemon.md)
|
||||
|
||||
### file:
|
||||
- {$Dena_path}/app/workers/daemons/blockchain.rb
|
||||
|
||||
### implementation
|
||||
daemon dockerize by below code and file:
|
||||
- bash -c "bundle exec ruby lib/daemons/daemons.rb blockchain" (called in Alvand Service up rake)
|
||||
- {$Dena_path}/lib/daemons/daemons.rb
|
||||
|
||||
Blockchain daemon as one **thread** for each active blockchain, process blocks and filter platform deposits.<br />
|
||||
this daemon use BlockchainService class in per one thread.<br/>
|
||||
that class recognizes its `adapter` (coin-connectors or coin-middleman) with help of the parameter that is passed to it when initialized,
|
||||
this parameter is **the blockchain DB record.**<br/>
|
||||
also, this class has standard functions that any coin-connectors must obey, so this class has two hands, with one hand connect to local DB and with another hand talk to the relevant Blockchain with help of `the adapter`.<br/>
|
||||
each coin has itself adapter that can be the Gem.<br />
|
||||
responsibility of these Adapters that connect to the related blockchain and doing my needed methods.<br/>
|
||||
this daemon is kept alive by an infinite loop that in every 30 seconds check the active blockchains.<br />
|
||||
also, in this 30-second time, check updated time of the blockchain or currencies record, if they have been newly updated time,
|
||||
the blockchain thread will be reset.<br />
|
||||
when the blockchain thread is reset, the last_seen_block will become **nil**.</br>
|
||||
BlockchainService class fetches relative blocks with help the Adapter,<br />
|
||||
and find transactions that included our users addresses (users addresses were saved in local DB).<br />
|
||||
after each loop of the Blockchain investigation, we update the Variable that has kept the last seen block number.<br />
|
||||
and also update the Height column of the blockchain record.<br />
|
||||
We are waiting for the N number of confirmations.<br />
|
||||
if height column of the blockchain record plus(+) the min confirmation, was bigger than the Adapters last seen block variable, synchronization will be skipped, and try again after 10 seconds<br />
|
||||
from the blockchain height to Adapters last_seen_block, the `process_block` function of **BlockchainService** class will be executed for each block.<br/>
|
||||
at last the height column will be updated.
|
||||
|
||||
#### process_block function
|
||||
1. fetch block by Adapter
|
||||
2. find relative deposits (destination address of blocks in our user address).
|
||||
3. find relative withdraws (hash transaction of blocks in our user confirming withdraws `txid`).
|
||||
4. Per deposit Blockchain, we update or create Db record and changing users balances.
|
||||
5. Per withdraw in Blockchain, we find Db records by `confirming` state, then update record state by the blockchain transaction,
|
||||
that was fetched before again by its the Adapter. so, at last, we will unlock and update user balances
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A(Peatio) -->|Blockchain stuffs| B[BlockchainService using adapter]
|
||||
|
||||
B --> |Blockchain stuffs| D((Btc Blockchain))
|
||||
B --> |Blockchain stuffs| E((Eth Blockchain))
|
||||
B --> |Blockchain stuffs| F((...))
|
||||
B --> A
|
||||
D --> B
|
||||
E --> B
|
||||
F --> B
|
||||
```
|
||||
29
docs/zagros/deposit/collection-fee.md
Normal file
29
docs/zagros/deposit/collection-fee.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Blockchain Collection fee
|
||||
[please read first](daemon.md)
|
||||
|
||||
### files:
|
||||
- {$Dena_path}/app/workers/daemons/deposit.rb
|
||||
- {$Dena_path}/app/services/wallet_service.rb
|
||||
|
||||
### implementation
|
||||
during blockchain deposit daemon, WalletService asks its Adapter (by passing The relevant deposit wallet) that the `prepare_deposit_collection!` method was implemented or not.<br />
|
||||
if not, the daemon kept continues its process, but if that method existed in the coin Adapter, the deposit daemon call the `collect_fee` method on the deposit DB record.<br />
|
||||
|
||||
#### collect_fee function
|
||||
1. Check the spread column of the deposit to find was filled or not. if not call `spread_between_wallets!` from the Deposit model.
|
||||
2. Active relevant fee wallet will be found from DB. if not found, we will back to the deposit daemon process.
|
||||
3. Create WalletService object by passing active fee wallet and run `deposit_collection_fees!` method on the deposit record.
|
||||
4. `deposit_collection_fees` method, run `prepare_deposit_collection`
|
||||
5. `prepare_deposit_collection` method will have a unique implementation for each coin (blockchain),but eventually, the output must be a transaction that in addition to sending into the relevant blockchain, also will be saved in the local DB.
|
||||
6. Change the state column of the deposit record from `processing` to `fee_processing`
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A((Depoist Daemon)) -->|deposit record| B[WalletService ]
|
||||
B --> |the Depoist Wallet Record| C{Adapter}
|
||||
C --> |`prepare_deposit_collection` is not impelemented |A
|
||||
C --> |`prepare_deposit_collection` is impelemented| E(WalletService)
|
||||
E --> |the Fee Wallet Record| C
|
||||
C --> D(`deposit_collection_fees!`)
|
||||
D --> |change state to fee_processing|A
|
||||
```
|
||||
65
docs/zagros/deposit/daemon.md
Normal file
65
docs/zagros/deposit/daemon.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Blockchain Deposit Watcher
|
||||
Peatio daemons are controlled by this gem: [God](http://godrb.com/).
|
||||
##### note: just we use the God if want using The Peatio in local without docker, in collection service, daemons handle by docker container.
|
||||
|
||||
## Daemon
|
||||
##### start daemon with the god:
|
||||
`god -c lib/daemons/daemons.god` <br/>
|
||||
**When the Peatio is being initialized, the God starts all daemons**<br />
|
||||
|
||||
##### stop daemon with the god:
|
||||
`god stop`. *God will still be up.*<br />
|
||||
|
||||
##### stop God and all daemons:
|
||||
`god terminate`
|
||||
|
||||
##### restart God: <br />
|
||||
`god restart`
|
||||
|
||||
##### status God: <br />
|
||||
`god status`
|
||||
|
||||
#### [please read it](../../../README.md)
|
||||
|
||||
|
||||
## Deposit Daemon
|
||||
###### this Daemon, become a docker service by daemons.yaml that call in service.rake
|
||||
[first read deposits_flow](../../../docs/peatio/deposits_flow.md)
|
||||
|
||||
**so we use new version of deposit**
|
||||
#### files:
|
||||
- {$Dena_path}/app/workers/daemons/deposit.rb
|
||||
- {$Dena_path}/app/workers/daemons/blockchain.rb
|
||||
|
||||
#### implementation
|
||||
daemon dockerize by below code and file:
|
||||
- bash -c "bundle exec ruby lib/daemons/daemons.rb deposit" (called in Alvand Service up rake)
|
||||
- {$Dena_path}/lib/daemons/daemons.rb
|
||||
|
||||
We decided to remove to AMQP base deposit daemons and create a new deposit daemon that will work on deposit states changes
|
||||
and will prevent immediate proceeding of erc20 deposits.
|
||||
|
||||
New deposit process diagram:
|
||||
|
||||

|
||||
|
||||
1. Blockchain daemon process blocks and filter platform deposits and save them in our DB. [document](blockchain.md) <br />
|
||||
3. In the deposit daemons we select each 60s deposits with state `processing` and `fee_processing`.
|
||||
4. For `processing` deposits we are checking if plugin implement method `prepare_deposit_collection!` if it doesn't we immediately process the deposit and collect deposit to the `hot`, `warm`, `cold` wallets.<br />
|
||||
this collection is done with help of WalletService class, that one of its responsibility is **spreading** between wallets.
|
||||
[read more about WalletService](../withdraw/withdraw-coin.md)<br/>
|
||||
every deposit record has column named `spread` that getting array value like this:<br />
|
||||
`[{"to_address"=>"xyxzx", "amount"=>"0.00083", "currency_id"=>"btc", "status"=>"pending", "hash"=>"dcffd5b7fabaa"}]`,<br />
|
||||
valued by (`spread_between_wallets!` *function* in deposit model) that was called in this daemon<br/>
|
||||
each row of the Spread array, will become transaction record and will be send to the Blockchain by WalletService and its the Adapter (`collect_deposit!` function).<br />
|
||||
If plugin implement method `prepare_deposit_collection!` daemon processing of collection fees and change deposit state to `fee_processing`.<br />
|
||||
For deposits with `fee_processing` state, we select each minute deposits that have `updated_at` older than 5 minutes and process them. With time condition we are sure that fee transaction has already been executed.<br />
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A((Blockchain)) -->|Deposit| B[Blockchain Daemon]
|
||||
B --> |waiting for numbers of confirmations| C[Deposit Daemon]
|
||||
D(BlockchainService) --> B
|
||||
E(WalletService) --> C
|
||||
```
|
||||
|
||||
57
docs/zagros/deposit/fiat.md
Normal file
57
docs/zagros/deposit/fiat.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Deposit: Fiat
|
||||
###### Sprint: 5
|
||||
|
||||
### Outcome:
|
||||
Users can do fiat deposits with the Help of the Vandar service.
|
||||
|
||||
### Implementation description:
|
||||
|
||||
#### Endpoints:
|
||||
POST {$domain}/api/v2/peatio/account/deposits/fiat <br/>
|
||||
POST {$domain}/api/v2/peatio/account/deposits/confirm<br/>
|
||||
#### File destination:
|
||||
{$Dena_Path}/app/api/v2/account/deposits.rb
|
||||
|
||||
#### Commits:
|
||||
3b189b07<br/>
|
||||
d436176b<br/>
|
||||
1cc9fb29<br/>
|
||||
9a6d7864<br/>
|
||||
5994b163<br/>
|
||||
7769e86a<br/>
|
||||
7dea7777<br/>
|
||||
#### What did we implement:
|
||||
we implemented a new client route for user, to they can deposit their money and charge their accounts
|
||||
|
||||
### TODO
|
||||
now we dont show any information of the deposit result to user, so in the result of the Vandar the amount perhaps remains as Rial
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
Title: Depost Fiat
|
||||
|
||||
note over User,Ranj:The description and factorNumber are optionals
|
||||
note over User,Ranj:callback_url parameter use for Vandar Service\n to redirect Bank Gateway into my system after deposit
|
||||
User->>Ranj:amount, callback_url, currency, card, **factorNumber**, **description**
|
||||
Ranj->>Dalan:POST: after client side checking
|
||||
Dalan->>Ranj:4xx if lose any required parameters
|
||||
note over Dalan,Vandar:The Vandar service has own documentation
|
||||
Dalan->>Ranj:4xx if entered Card number not exist in current user valid Card number list
|
||||
Dalan->>Ranj:new deoposit recored created
|
||||
Dalan->>Ranj:4xx if any model validation become false
|
||||
Dalan->>Vandar:POST valid_card_number, amount, callback_url, description
|
||||
Vandar->>Dalan:A new deposit token will be generated for Bank Gateway
|
||||
Dalan->>Ranj: pass generated Token
|
||||
Ranj->>User:if token present redirect user's page to Bank Gateway \n otherwise, show errors in the Vandar response and process finished
|
||||
User-->>Vandar: entering bank information for doing deposit
|
||||
Vandar->>Ranj:GET pass generated token to callback_url
|
||||
Ranj->>Dalan: POST generated token for confirming step
|
||||
Dalan->>Ranj:at first, we check the database to check the status of the deposit that was unique by the generated token.\n show record result if txid present in DB,\n otherwise ask The Vandar for result of this deposit.
|
||||
Dalan->>Vandar: POST generated token to find transaction
|
||||
Vandar->>Dalan: pass result of transaction
|
||||
Dalan->>Vandar: POST generated token to verify transaction
|
||||
Dalan->>Ranj: update deposit record in DB (txid) and charge user balane
|
||||
Ranj->>User: notify the user that the deposit is done.
|
||||
|
||||
```
|
||||
49
docs/zagros/deposit/spread-between-wallets.md
Normal file
49
docs/zagros/deposit/spread-between-wallets.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Spread between wallets method
|
||||
[Please read first](daemon.md)
|
||||
|
||||
### files:
|
||||
- {$Dena_path}/app/workers/daemons/deposit.rb
|
||||
- {$Dena_path}/app/models/deposit.rb
|
||||
|
||||
|
||||
### implementation
|
||||
If you have read the deposit doc, you know this function where is called.
|
||||
|
||||
#### spread_between_wallets! function
|
||||
1. Will Return to ex-process if the Spread column had value.
|
||||
2. Finding the Deposit wallet form currency and pass it as input param to the WalletService class to create the object.
|
||||
3. Calling `spread_deposit` function from **WalletService** class for the deposit record
|
||||
4. Update the spread column for DB record with return value from step **3**.
|
||||
|
||||
#### spread_deposit function
|
||||
1. The Adapter will be configured with the wallet record data and the relevant blockchain and currency setting
|
||||
2. Array list by data of the withdraw wallet form DB (HOT WARM COLD)
|
||||
3. Map them to new data by name **destination_wallets**:
|
||||
- `address` : the wallet address
|
||||
- `balance` : the current coin balance of wallet
|
||||
- `max_balance` : how many coins the wallet can host
|
||||
- `min_collection_amount` : the minimum of accepted deposit (set in the Admin panel)
|
||||
- `skip_deposit_collection` : boolean type to skip deposit or not (set in the Admin panel)
|
||||
4. Set the zero the balance for the last wallet. Since last wallet is considered to be the most secure we need always. All money which doesn't fit to other wallets will be collected to last wallet.
|
||||
5. Call `spread_between_wallets` from *WalletService* with the deposit record and the **destination_wallets**
|
||||
|
||||
|
||||
#### spread_between_wallets function
|
||||
1. Returning empty array if deposit amount smaller than the minimum of `min_collection amount` of wallets.
|
||||
2. left_amount variable is initialized with amount of the deposit (*original_amount*)
|
||||
3. starting a loop on `destination_wallets`.
|
||||
4. `amount_for_wallet` = choose the minimum value between available wallet balance and left_amount
|
||||
5. Setting zero for `amount_for_wallet` if this variable smaller than `min_collection_amount`
|
||||
6. `left_amount` will equal to (`left_amount` minus `amount_for_wallet`)
|
||||
7. If amount left is too small we will not able to collect it.So we collect everything to current wallet.<br/ >
|
||||
`amount_for_wallet` = `amount_for_wallet` + `left_amount` and `left_amount` = 0
|
||||
8. Creating `Peatio::Transaction` object:
|
||||
- to_address : `to_address` from **destination_wallets**
|
||||
- amount : `amount_for_wallet`
|
||||
- currency_id: currency_id of the deposit record
|
||||
- status : :skipped if `skip_deposit_collection` is true
|
||||
9. Ending the loop on `destination_wallets` and now we have `spread` variable that includes **transactions**.
|
||||
|
||||
10. If deposit amount doesn't fit to any wallet, collect it to the last one. (`left_amount` doesnt become zero).
|
||||
11. Remove zero and skipped transactions from spread.
|
||||
12. Return `spread` variable.
|
||||
125
docs/zagros/new_order_types/new-order-type-imp.md
Normal file
125
docs/zagros/new_order_types/new-order-type-imp.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Market: new order type imp
|
||||
|
||||
###### Sprint: ?
|
||||
|
||||
### Outcome:
|
||||
|
||||
we need to store new order types in ram.(OCO, stop-order- stop-limit-order)
|
||||
always we should follow openware road map so we implement order types just like what they did.
|
||||
so we create ne models and class with nested initializing.
|
||||
|
||||
|
||||
#### File destination:
|
||||
|
||||
{$Dena_Path}/app/trading/matching/engine.rb
|
||||
|
||||
{$Dena_Path}/app/trading/matching/oco_order.rb
|
||||
|
||||
{$Dena_Path}/app/trading/matching/special_order_book.rb
|
||||
|
||||
{$Dena_Path}/app/trading/matching/special_order_book_manager.rb
|
||||
|
||||
{$Dena_Path}/app/trading/matching/stop_order.rb
|
||||
|
||||
{$Dena_Path}/app/trading/matching/stop_limit_order.rb
|
||||
|
||||
#### Commits:
|
||||
5661b7a9c1
|
||||
f71c7724b1
|
||||
79e4aec6bf
|
||||
d5e67664b2
|
||||
8c0d87cca8
|
||||
25fd01c802
|
||||
f40cb20c7d
|
||||
<br >
|
||||
<br >
|
||||
|
||||
<br >
|
||||
|
||||
<br >
|
||||
|
||||
|
||||
#### What did we implement:
|
||||
|
||||
lets see how does every order work:
|
||||
|
||||
1.stop order:
|
||||
A stop order, also referred to as a stop-loss order, is an order to buy or sell a stock once the price of the stock reaches a specified price, known as the stop price. When the stop price is reached, a stop order becomes a market order. A buy stop order is entered at a stop price above the current market price. Investors generally use a buy stop order to limit a loss or to protect a profit on a stock that they have sold short. A sell stop order is entered at a stop price below the current market price. Investors generally use a sell stop order to limit a loss or to protect a profit on a stock that they own.
|
||||
|
||||
Before using a stop order, investors should consider the following:
|
||||
|
||||
* short-term market fluctuations in a stock’s price can activate a stop order, so a stop price should be selected carefully.
|
||||
|
||||
* The stop price is not the guaranteed execution price for a stop order. The stop price is a trigger that causes the stop order to become a market order. The execution price an investor receives for this market order can deviate significantly from the stop price in a fast-moving market where prices change rapidly. An investor can avoid the risk of a stop order executing at an unexpected price by placing a stop-limit order, but the limit price may prevent the order from being executed.
|
||||
|
||||
* For certain types of stocks, some brokerage firms have different standards for determining whether a stop price has been reached. For these stocks, some brokerage firms use only last-sale prices to trigger a stop order, while other firms use quotation prices. Investors should check with their brokerage firms to determine the specific rules that will apply to stop orders.
|
||||
|
||||
2. A stop-limit order is an order to buy or sell a stock that combines the features of a stop order and a limit order. Once the stop price is reached, a stop-limit order becomes a limit order that will be executed at a specified price (or better). The benefit of a stop-limit order is that the investor can control the price at which the order can be executed.
|
||||
|
||||
Before using a stop-limit order, investors should consider the following:
|
||||
|
||||
* As with all limit orders, a stop-limit order may not be executed if the stock’s price moves away from the specified limit price, which may occur in a fast-moving market.
|
||||
|
||||
* Short-term market fluctuations in a stock’s price can activate a stop-limit order, so stop and limit prices should be selected carefully.
|
||||
|
||||
* The stop price and the limit price for a stop-limit order do not have to be the same price. For example, a sell stop limit order with a stop price of $3.00 may have a limit price of $2.50. such an order would become an active limit order if market prices reach $3.00, although the order could only be executed at a price of $2.50 or better.
|
||||
|
||||
* For certain types of stocks, some brokerage firms have different standards for determining whether the stop price of a stop-limit order has been reached. For these stocks, some brokerage firms use only last-sale prices to trigger a stop-limit order, while other firms use quotation prices. Investors should check with their brokerage firms to determine the specific rules that will apply to stop-limit orders.
|
||||
|
||||
|
||||
3. One Cancel Other order(OCO):
|
||||
|
||||
One Cancel Other order
|
||||
The one cancels other order option allows you to place a pair of orders stipulating that if one order is executed fully or partially, then the other is automatically canceled. An OCO order combines a stop order with a limit order. This option allows you to place both take profit and stop loss targets for your position (only for limit orders).
|
||||
|
||||
Example: If the market price is 250 and the trader wants a stop order at 245 and a limit order at 260, then a OCO order may be appropriate. If the market reaches 245, the stop order will trigger a market order and cancel the limit order at 260. If the market reaches 260 before 245, the limit order will execute and cancel the stop order at 245.
|
||||
|
||||
Note: If you manually cancel one of the OCO orders; i.e., the stop or the limit, you must also manually cancel the other one. An OCO order is only automatically canceled if the other order is partially or fully executed by market price movement.
|
||||
|
||||
|
||||
so now for every new type we should create a class:
|
||||
1. stop-order:<br >
|
||||
stop orders are like a market order with an activator price(we call it igniter price)
|
||||
so we Inherit this class from Market order class and add new attr
|
||||
|
||||
1. stop-limit-order:<br >
|
||||
stop limit orders are like a limit order with an activator price(we call it igniter price)
|
||||
so we Inherit this class from Limit order class and add new attr
|
||||
|
||||
3. inherit from StopLimitOrder
|
||||
|
||||
|
||||
after creating new classes,we need an orderbook to save the new orderbook in a arranged structure:
|
||||
|
||||
* we store them in rbtree(red-black tree) to make searching faster.
|
||||
we implemented find, add and remove method for every new order type.
|
||||
|
||||
* order book manager:
|
||||
it initializes bid and ask orderbooks.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[ENGINE] -->|initializes|B(orderbook manager)
|
||||
A[ENGINE] -->|initializes|C(special orderbook manager)
|
||||
B --> |initializes|D(ask orderbook)
|
||||
B --> |initializes|E(bid orderbook)
|
||||
C --> |initializes|F(ask special orderbook)
|
||||
C --> |initializes|G(bid special orderbook)
|
||||
D --> |initializes|H(limit orders)
|
||||
D --> |initializes|I(market orders)
|
||||
E --> |initializes|J(limit orders)
|
||||
E --> |initializes|K(market orders)
|
||||
F --> |initializes|L(oco orders)
|
||||
F --> |initializes|M(stop limit orders)
|
||||
F --> |initializes|N(stop orders)
|
||||
G --> |initializes|O(oco orders)
|
||||
G --> |initializes|P(stop limit orders)
|
||||
G --> |initializes|Q(stop orders)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
53
docs/zagros/new_order_types/new-order-types.md
Normal file
53
docs/zagros/new_order_types/new-order-types.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# New order types
|
||||
###### Sprint: 10
|
||||
|
||||
### Outcome:
|
||||
Prepare the Peatio (structure and code) to support new order types<br />
|
||||
the new order types are:
|
||||
- **Stop** : the market order that is triggered by a specific price
|
||||
- **Stop-Limit** : the limit order that is triggered by a specific price
|
||||
- **OCO**: consist of two types: 1)limit 2)stop; each enters the matching stage, cancel another
|
||||
|
||||
|
||||
### Implementation description:
|
||||
#### branch :
|
||||
orderType
|
||||
|
||||
#### Commit
|
||||
361e4d99<br />
|
||||
2b6390ee
|
||||
|
||||
#### File destination:
|
||||
- {$Dena_path}/app/models/order.rb<br/>
|
||||
- {$Dena_path}/db/migrate/20210815080757_add_new_order_types_to_orders.rb<br/>
|
||||
- {$Dena_path}/app/api/v2/admin/orders.rb<br/>
|
||||
- {$Dena_path}/app/api/v2/entities/order.rb<br/>
|
||||
- {$Dena_path}/app/api/v2/management/entities/order.rb<br/>
|
||||
- {$Dena_path}/app/api/v2/management/orders.rb<br/>
|
||||
- {$Dena_path}/app/api/v2/market/named_params.rb<br/>
|
||||
- {$Dena_path}/app/api/v2/market/orders.rb<br/>
|
||||
- {$Dena_path}/app/api/v2/order_helpers.rb<br/>
|
||||
- {$Dena_path}/app/jobs/cron/ticker.rb<br/>
|
||||
- {$Dena_path}/app/models/order.rb<br/>
|
||||
- {$Dena_path}/app/models/order_ask.rb<br/>
|
||||
- {$Dena_path}/app/models/order_bid.rb<br/>
|
||||
|
||||
|
||||
#### What did we implement:
|
||||
we added three columns (`igniter_price`, `origin_type`, `relative_id`) to order table to support new types.
|
||||
- `igniter_price`: use for trigger order when the market price achieve to it
|
||||
- `origin_type`: use for keep the original type of order
|
||||
- `relative_id`: use for link OSO orders together
|
||||
|
||||
There will be a new class called `Igniter`.<br />
|
||||
This class is feed by the Ticker to know the moment price of the market.<br />
|
||||
each time the market price will be the same with igniter-price of any special order,<br />
|
||||
this class change the special-order to `limit` or `market` order. (So the past process will be repeated).<br />
|
||||
also, if order type was OCO, in matching step if matched happened, the relative order will find by relative_id, and cancel it.<br />
|
||||
this changing is happened by changing the value of `ord_type` to **limit** or **market**.<br />
|
||||
but the value of `origin_type` remains without any changes, so we always know the original type of order.
|
||||
|
||||
##### note:
|
||||
add a new step before the Matching step to prevent special orders to enter matching step.<br/>
|
||||
We can name this stage: the Controlling
|
||||
|
||||
53
docs/zagros/operation-accounting.md
Normal file
53
docs/zagros/operation-accounting.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# operation: accounting
|
||||
|
||||
###### Sprint: ?
|
||||
|
||||
### Outcome:
|
||||
a simple information about operations.
|
||||
|
||||
#### File destination:
|
||||
|
||||
{$Dena_Path}/app/model/operations/
|
||||
|
||||
##### Doc
|
||||
|
||||
* Operation:
|
||||
|
||||
this is the base class for operations and subcategories Heir from it.
|
||||
operation column:
|
||||
1. reference: it has polymorphic for every type of references(for example trades or withdraws or deposit or ..)
|
||||
2. currencies: code of currency
|
||||
3. credit: plus funds
|
||||
4. debit: minus funds
|
||||
5. account
|
||||
|
||||
methods of operations were implemented in this class and subcategories only use them.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[operation] -->|inheritance| B(Expense)
|
||||
A[operation] -->|inheritance| C(Asset)
|
||||
A[operation] -->|inheritance| D(Liability)
|
||||
A[operation] -->|inheritance| E(Revenue)
|
||||
```
|
||||
this chart showed inheritance structure of operation.
|
||||
|
||||
1. Expense:<br >
|
||||
Expense is a income statement operation.
|
||||
|
||||
2. Asset<br >
|
||||
is a balance sheet operation.every income/outcome of system store and controll by it.
|
||||
|
||||
3. Liability<br >
|
||||
is a balance sheet operation and belongs to members and we manage members accounting things by it.
|
||||
for example trades and deposit.
|
||||
|
||||
4. Revenue:<br >
|
||||
is a income statement operation and we manage exchange revenue by it.
|
||||
|
||||
####SO:
|
||||
* revenue --> revenue of exchange
|
||||
* liability --> users accounting
|
||||
* asset --> exchange assets
|
||||
* expense --> ?
|
||||
|
||||
82
docs/zagros/order-trade-steps/executor.md
Normal file
82
docs/zagros/order-trade-steps/executor.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# trading: trade executor
|
||||
|
||||
###### Sprint: ?
|
||||
|
||||
|
||||
###DOC
|
||||
* in case of reading first part processor or matching please skip this part.
|
||||
|
||||
for matching and executing orders openware creates a flow that manage by RabbitMQ and its consumers.
|
||||
we have three consumers that works on trades:
|
||||
1. order processor:<br >
|
||||
does preliminary calculations and works on order like locking order<br >
|
||||
2. matching:<br >
|
||||
match orders and pass them to executor
|
||||
3. trade executor:<br >
|
||||
execute trades that matching creates
|
||||
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> API
|
||||
API --> RabbitMQ
|
||||
RabbitMQ --> OrderProcessor
|
||||
OrderProcessor --> RabbitMQ
|
||||
RabbitMQ --> Matching
|
||||
Matching --> RabbitMQ
|
||||
RabbitMQ --> Executor
|
||||
Executor --> Notify
|
||||
Notify --> [*]
|
||||
```
|
||||
|
||||
#### Trade executor
|
||||
##### what does trade executor do step by step:
|
||||
1. it gets price and market and other informations
|
||||
2. create_trade_and_strike_orders
|
||||
1. get both orders
|
||||
2. get both needed accounts
|
||||
3. validate above informations
|
||||
4. initialize new trade with above data
|
||||
5. strike maker side
|
||||
1. change order attr like volume,locked,...
|
||||
2. unlocking funds and plus funds
|
||||
2. check order fill
|
||||
6. strike taker side
|
||||
1. change order attr like volume,locked,...
|
||||
2. check order fill
|
||||
7. create operations and accountings recorde
|
||||
1. record_liability_debit!
|
||||
2. record_liability_credit!
|
||||
3. record_liability_transfer!
|
||||
4. record_revenues!
|
||||
8. publish trade dependent on its state
|
||||
|
||||
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[RabbitMQ] -->|submit payload| B(executor)
|
||||
B --> |execute|C(get information about trade)
|
||||
C --> D(get both orders)
|
||||
D --> E(get both needed accounts)
|
||||
E --> F(validation on datas)
|
||||
F --> G(initialize new trade)
|
||||
G --> H( maker side)
|
||||
G --> I(taker side)
|
||||
H --> J(striker)
|
||||
I --> J
|
||||
J -->K(calculate incomes and fees)
|
||||
K --> L(update orders data like locked and volume,..)
|
||||
L --> M(unlock funds and plus incomes)
|
||||
M --> N{is order filled}
|
||||
N --> |yes|O(change state to done)
|
||||
O --> P(unlocked extra locked funds)
|
||||
N -->|no and market order|Q(cancell order)
|
||||
Q --> R(create operations record for cancellation)
|
||||
R --> S(create operation records)
|
||||
P --> S
|
||||
S --> T(record_liability_debit, record_liability_credit, record_liability_transfer, record_revenues)
|
||||
T --> U(save trade)
|
||||
U --> V(publish trade)
|
||||
|
||||
```
|
||||
73
docs/zagros/order-trade-steps/matching.md
Normal file
73
docs/zagros/order-trade-steps/matching.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# trading: order matching
|
||||
|
||||
###### Sprint: ?
|
||||
|
||||
|
||||
###DOC
|
||||
* in case of reading first part processor please skip this part.
|
||||
|
||||
for matching and executing orders openware creates a flow that manage by RabbitMQ and its consumers.
|
||||
we have three consumers that works on trades:
|
||||
1. order processor:<br >
|
||||
does preliminary calculations and works on order like locking order<br >
|
||||
2. matching:<br >
|
||||
match orders and pass them to executor
|
||||
3. trade executor:<br >
|
||||
execute trades that matching creates
|
||||
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> API
|
||||
API --> RabbitMQ
|
||||
RabbitMQ --> OrderProcessor
|
||||
OrderProcessor --> RabbitMQ
|
||||
RabbitMQ --> Matching
|
||||
Matching --> RabbitMQ
|
||||
RabbitMQ --> Executor
|
||||
Executor --> Notify
|
||||
Notify --> [*]
|
||||
```
|
||||
|
||||
#### Order matching
|
||||
##### what does order matching do step by step:
|
||||
1. submit order ro engine
|
||||
2. match method
|
||||
1. get orderbooks
|
||||
2. loop
|
||||
1. is order filled?(all amount)
|
||||
2. get top order of opposite order book(top means order with best price)
|
||||
* for better and faster searching they use rbtree. for more information [click here](https://www.geeksforgeeks.org/red-black-tree-set-1-introduction-2/)
|
||||
3. check can they create a trade
|
||||
4. is trade valid?(trade validation):<br >
|
||||
* not zero,calculation problems
|
||||
5. fill both orders:<br >
|
||||
* decrease order volume(if the opposite order is filled, we remove it from orderbook)
|
||||
* filled order means that order completely get its needed volume
|
||||
6. send to trade executor
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[RabbitMQ] -->|submit payload| B(Matching)
|
||||
B -->|submit engine|C(match method)
|
||||
C --> D(get orderbooks)
|
||||
D --> E(loop)
|
||||
E --> F{order filled?}
|
||||
F --> |yes|X(break)
|
||||
F --> |no|G{opposit orderbook is blanked}
|
||||
G --> |yes|H{is it limit order?}
|
||||
H --> |yes|I(add to orderbook)
|
||||
I --> X
|
||||
H --> |no|J(cancel order)
|
||||
J --> X
|
||||
G --> |no|K(get top of opposit orderbook)
|
||||
K --> L(make trade with top of opposit)
|
||||
L --> |created trade|M{trade.blank?}
|
||||
M --> |yes|H
|
||||
M --> |no|N(validate trade)
|
||||
N --> O(fill order)
|
||||
O --> P(fill opposit order)
|
||||
O --> |publish to executor|A
|
||||
O --> E
|
||||
X --> A
|
||||
```
|
||||
34
docs/zagros/order-trade-steps/order-api.md
Normal file
34
docs/zagros/order-trade-steps/order-api.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Order Creation: Api
|
||||
|
||||
### Outcome:
|
||||
Users create sell or buy order.
|
||||
|
||||
### Implementation description:
|
||||
|
||||
#### Endpoints:
|
||||
- POST {$domain}/api/v2/peatio/marker/orders/fiat
|
||||
#### Params
|
||||
- market
|
||||
- side
|
||||
- volume
|
||||
- ord_type
|
||||
|
||||
#### File destination:
|
||||
{$Dena_Path}/app/api/v2/market/orders.rb
|
||||
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
title Order Creation
|
||||
User->>Ranj: market, side, volume, ord_type
|
||||
Ranj->>Dena: POST: after client side checking
|
||||
Dena->>Ranj: 4xx if lose any required parameters
|
||||
Dena->>Ranj: 4xx if users level lower than the
|
||||
Dena->>Dena: compute lock balance
|
||||
Dena->>Dena: send order to the Order Processor queue
|
||||
Dena->>Ranj: 2xx order record created
|
||||
|
||||
Ranj->>User: show The Order response
|
||||
|
||||
```
|
||||
52
docs/zagros/order-trade-steps/processor.md
Normal file
52
docs/zagros/order-trade-steps/processor.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# trading: order processor
|
||||
|
||||
###### Sprint: ?
|
||||
|
||||
|
||||
###DOC
|
||||
for matching and executing orders openware creates a flow that manage by RabbitMQ and its consumers.
|
||||
we have three consumers that works on trades:
|
||||
1. order processor:<br >
|
||||
does preliminary calculations and works on order like locking order<br >
|
||||
2. matching:<br >
|
||||
match orders and pass them to executor
|
||||
3. trade executor:<br >
|
||||
execute trades that matching creates
|
||||
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> API
|
||||
API --> RabbitMQ
|
||||
RabbitMQ --> OrderProcessor
|
||||
OrderProcessor --> RabbitMQ
|
||||
RabbitMQ --> Matching
|
||||
Matching --> RabbitMQ
|
||||
RabbitMQ --> Executor
|
||||
Executor --> Notify
|
||||
Notify --> [*]
|
||||
```
|
||||
|
||||
#### Order Processor
|
||||
##### what does order processor do step by step:
|
||||
1. initializing: submit all orders with pending state(take them to ram)
|
||||
2. submit:<br >
|
||||
1. it finds order by id with lockversion
|
||||
2. check state of order
|
||||
3. update locked and balance of account
|
||||
4. submit operation and accounting
|
||||
5. update order state to WAIT
|
||||
6. enqueue in rabbit (pass orders to matching)
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[api] -->|enque| B(RabbitMQ)
|
||||
B --> C(order processor)
|
||||
C --> |submit order in ram|D{check state}
|
||||
D -->|pending| E[order locking]
|
||||
D -->|else| B
|
||||
E -->G[submit operation and accounting]
|
||||
G --> F[update state to wait]
|
||||
F --> |enque to matching| B
|
||||
|
||||
```
|
||||
69
docs/zagros/referral.md
Normal file
69
docs/zagros/referral.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Market: referral
|
||||
|
||||
###### Sprint: ?
|
||||
|
||||
### Outcome:
|
||||
users can invite other users.if an user sign up with another user invitation code, exchange gives inviter a bonus to encourage people to join our exchange.
|
||||
bonus amount is a percent of trade fee.
|
||||
|
||||
#### File destination:
|
||||
|
||||
{$Dena_Path}/app/jobs/referral_bonus.rb
|
||||
|
||||
{$Dena_Path}/app/models/bonus.rb
|
||||
|
||||
#### Commits:
|
||||
|
||||
|
||||
#### What did we implement:
|
||||
|
||||
first of we need a table to save bonuses.
|
||||
we create bonus table.its columns are:
|
||||
1. trade_id: foreign key to trade tables.this shows that this bonus was created from which trade.
|
||||
2. sender_member_id: foreign key to members tables.this shows bonus was created from which member trade(invited memebr).
|
||||
3. bonus_member_id: foreign key to members tables.this shows bonus was sent to which member(inviter member).
|
||||
4. amount: amoutn of bonus
|
||||
5. state: state of bonus { pending: 0, payed: 1, rejected: 2 }
|
||||
|
||||
* we have an validation on creating bonus for avoiding duplication and double paying.
|
||||
```ruby
|
||||
validates_uniqueness_of :trade, :scope => [:sender_member_id]
|
||||
```
|
||||
this means that can not create bonus with same trade **AND** same sender.
|
||||
|
||||
<br >
|
||||
<br >
|
||||
<br >
|
||||
<br >
|
||||
|
||||
* we created a cron job that runs every 24 hour (we plan to run it in midnights to avoid putting pressure on server)
|
||||
This is how it works:
|
||||
1. select all last 24 hour revenues and process them in batch of 1000.
|
||||
2. get them one by one and convert them to rial and multiply them with referral bonus percent.
|
||||
3. create bonus, update users balance(with lock version) and create on revenue debit for accounting system(we cant lost money in system)
|
||||
* all calculations and db updates that related about money(critical calculations) are in transaction so if one of them blocked or rejected all changes rollbacked .
|
||||
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
title:referral_job
|
||||
A[loop:batch 1000] -->|1000 of last 24h| B(one of revenue)
|
||||
B -->|revenue| D{has referral}
|
||||
D -->|no| B
|
||||
D -->|yes| F{is in rial}
|
||||
F -->|yes| I
|
||||
F -->|no| H[convert to irt]
|
||||
H --> I[calculation bonus amount]
|
||||
I --> J[changes balance]
|
||||
J --> K[create bonus and accounting things]
|
||||
K --> L{error happend?}
|
||||
L --> |yes| M[roll back everything]
|
||||
L --> |no| P
|
||||
M --> O[create bonus with pending state]
|
||||
O --> P{1000 ended?}
|
||||
P -->|yes| A
|
||||
P -->|no| B
|
||||
|
||||
```
|
||||
|
||||
|
||||
53
docs/zagros/user-fee-level.md
Normal file
53
docs/zagros/user-fee-level.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Market: dynamic trade fee
|
||||
|
||||
###### Sprint: ?
|
||||
|
||||
### Outcome:
|
||||
in every trade exchange take some fee from users as revenue.these fees are some percentages from all trade value.
|
||||
these percentages must be dynamic toward last thirty days trades amount.
|
||||
exchange sets some levels and amount of them. if users reach every target, exchange change the fee level of them.
|
||||
|
||||
#### File destination:
|
||||
|
||||
{$Dena_Path}/app/models/trade.rb
|
||||
|
||||
{$Dena_Path}/app/models/member.rb
|
||||
|
||||
#### Commits:
|
||||
|
||||
|
||||
#### What did we implement:
|
||||
|
||||
* trades are executed in different markets and every market has different quote currency.
|
||||
for simplifying calculation of the last thirty days trades amount we create new call back(before save) to calculate last thirty days trades amount in irt and save them in new column.
|
||||
|
||||
```def rial_total!```
|
||||
|
||||
this function has to case:
|
||||
1. quote currency is irt: total saved
|
||||
2. quote currency is usdt: first get price_now of tether and calculate rial amount(total value of trade in irt)
|
||||
|
||||
|
||||
* before creating and submitting orders, fee level of user Determined and applied on calculations.
|
||||
this calculations runs on order creation validations.
|
||||
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[API] -->|order attrs| B(order creation)
|
||||
B --> C{calculating last 30 days amount}
|
||||
C -->|touch new target| D[update its group]
|
||||
C -->|no changes| E[no change in group]
|
||||
D --> F[order created]
|
||||
E --> F
|
||||
F --> G[ ___MATCH ENGINE___]
|
||||
G --> |matched with another order|H[create trade]
|
||||
H --> I[calculate irt based amount]
|
||||
I --> J[save trade]
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
52
docs/zagros/vandar_banking/vandar.md
Normal file
52
docs/zagros/vandar_banking/vandar.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Vandar Service
|
||||
###### Sprint: 5
|
||||
|
||||
### Outcome:
|
||||
users can deposit fiat and withdraw fiat by connection to the Vandar
|
||||
|
||||
### Implementation description:
|
||||
|
||||
|
||||
#### File destination:
|
||||
{$Dena_Path}/app/services/vandar_service.rb<br />
|
||||
{$Dena_Path}/app/api/v2/account/deposits.rb<br />
|
||||
{$Dena_Path}/app/api/v2/account/withdraw.rb<br />
|
||||
{$Dena_Path}/app/models/withdraw.rb<br />
|
||||
{$Dena_Path}/app/models/deposit.rb<br />
|
||||
|
||||
|
||||
#### Commits:
|
||||
3b189b07<br/>
|
||||
2cd9b4ad<br/>
|
||||
f83585dd<br/>
|
||||
b832b0fb
|
||||
|
||||
#### What did we implement:
|
||||
in the Opendax, there is no way to deposit or withdraw for fiat,
|
||||
so we use the Vandar as a third party to connect real banks for deposit and withdraws.<br />
|
||||
for talking with The Vandar, we implemented a new service named VandarService (vandar_service.rb).<br />
|
||||
VandarService has four part, Login, Deposit, Withdraw, Transaction
|
||||
|
||||
##### login part:
|
||||
this part is used for login in the Vandar with mobile and password that these two must exist in the config file<br />
|
||||
this part has a `login` method that automatically calls when creating object from this service
|
||||
|
||||
##### deposit part:
|
||||
this part is used for doing deposits<br />
|
||||
this part has a three methods:<br />
|
||||
-`generate_token`: use for generate unique Bank Gateway token
|
||||
-`transaction`: use for finding specific deposit in the Vandar
|
||||
-`verify`: use for verify specific deposit in the Vandar
|
||||
|
||||
##### withdraw part:
|
||||
this part is used for doing withdraws<br />
|
||||
this part has a four methods:<br />
|
||||
-`list_withdraw`: use for listing withdraws (never use in process)
|
||||
-`info_withdraw`: use for get specific withdraw information from the Vandar
|
||||
-`delete_withdraw`: use for delete specific withdraw in the Vandar (never use in process)
|
||||
|
||||
##### transaction part:
|
||||
- `list_transactions`: use for listing transaction with fromDate and toDate as parameters (use it in withdraw Job)
|
||||
|
||||
#### note:
|
||||
we use Faraday Gem to send request to vandar
|
||||
BIN
docs/zagros/wallet/fee_wallet.jpeg
Normal file
BIN
docs/zagros/wallet/fee_wallet.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 93 KiB |
BIN
docs/zagros/wallet/peatio_wallets.png
Normal file
BIN
docs/zagros/wallet/peatio_wallets.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
43
docs/zagros/wallet/types.md
Normal file
43
docs/zagros/wallet/types.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Wallet types
|
||||

|
||||
|
||||
## 1. Deposit
|
||||
This wallet is the first place to store users' property.<br />
|
||||
we generated new addresses from this wallet for users,
|
||||
so users can send their crypto coin to these addresses.
|
||||
these addresses are keeping in local DB.<br/>
|
||||
so the blockchain daemon fetch stream block and recognizes a relevant transaction by these addresses
|
||||
|
||||
## 2. Fee
|
||||
Use this wallet for calculate and pays the fee for (ERC20 case)
|
||||
|
||||

|
||||
|
||||
## 3.Hot 4.Warm 5.Cold
|
||||
#### Deposit process
|
||||
If the deposit equal or higher than 'Min collection amount' the system initialise a deposit collecting process to move funds from the deposit wallet to exchange wallet/wallets ('Hot', 'Warm' or 'Cold').<br/>
|
||||
That process requires a few checks: <br />
|
||||
- If a sum of the deposit + 'Hot wallet' balance lower than 'Max balance' of 'Hot wallet' then the system moves the deposit to 'Hot wallet'
|
||||
- If a sum of the deposit + 'Hot wallet' balance is higher than 'Max balance' of 'Hot wallet' then the system checks next conditions.- If a sum of the deposit + 'Hot wallet' balance + 'Warm wallet' balance lower than a sum of "hot" and "warm" wallets max balances then the system checks next conditions.
|
||||
- If 'Hot wallet' reached max balance the system moves deposit to 'Warm wallet'
|
||||
- If 'Hot wallet' hasn't reached max balance the system divides the deposit between 'Hot wallet' and 'Warm wallet'.
|
||||
- If a sum of the deposit + 'Hot wallet' balance + 'Warm wallet' balance higher than a sum of "hot" and "warm" wallets max balances then the system does next checks:
|
||||
- If 'Warm wallet' reached max balance the system moves deposit to 'Cold wallet'
|
||||
- If 'Warm wallet' hasn't reached max balance the system divides the deposit between 'Warm wallet' and 'Cold wallet'.
|
||||
|
||||
#### Withdraw process
|
||||
- User creates a withdrawal request.
|
||||
- System checks if the user has enough funds to proceed withdrawal transaction. If the user doesn't have enough funds, the system reject to create withdrawal request.<br/>
|
||||
If the user has enough funds, the system accepts that request and do the next checks.
|
||||
- If the user hasn't reached any withdrawal limits, the system process the withdrawal request automatically from 'Hot wallet'. If 'Hot wallet' doesn't have enough funds to process the withdrawal request the system throw error.<br/>
|
||||
In this situation, the admin needs to replenish 'Hot wallet'.
|
||||
- If the user reached at least one of withdrawal limits (24h or 72h) the system accepting that request but doesn't process it automatically. <br/>
|
||||
Admin can manually reject or process that withdrawal request from 'Hot wallet'.
|
||||
- Withdrawal request for a big amount can be processed manually by the admin. Big withdrawals should be processed outside the system, from 'Warm wallet'.<br/>
|
||||
When the admin have generated and signed withdrawal transaction he has to propagate that transaction to the network. After transaction propagation admin has to upload TxId into the admin panel.<br />
|
||||
If there are not enough funds in 'Warm wallet' to process the withdrawal request the admin needs to replenish 'Warm wallet' from 'Cold wallet' (transaction signing should be done offline).
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
BIN
docs/zagros/wallet/wallets.jpeg
Normal file
BIN
docs/zagros/wallet/wallets.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 142 KiB |
53
docs/zagros/withdraw-deposit-limitation/limitation.md
Normal file
53
docs/zagros/withdraw-deposit-limitation/limitation.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# KYC withdraw, deposit limitation
|
||||
###### Sprint: 4
|
||||
[first read](../../../docs/peatio/withdraw_limits.md)
|
||||
### Outcome:
|
||||
each user's withdrawing and deposit for executing must not be reached to daily or monthly limitation
|
||||
|
||||
|
||||
### Implementation description:
|
||||
|
||||
|
||||
#### File destination:
|
||||
{$Dena_Path}/app/models/deposit.rb<br />
|
||||
{$Dena_Path}/app/models/withdraw.rb<br />
|
||||
{$Dena_Path}/app/models/deposit_limit.rb<br />
|
||||
{$Dena_Path}/app/models/withdraw_limit.rb<br />
|
||||
{$Dena_Path}/app/models/withdraws/fiat.rb<br />
|
||||
{$Dena_Path}/app/models/deposits/fiat.rb<br />
|
||||
{$Dena_Path}/db/migrate/20210504102945_add_kind_to_withdraw_limits.rb<br />
|
||||
{$Dena_Path}/db/migrate/20210504102945_add_kind_to_withdraw_limits.rb<br />
|
||||
|
||||
|
||||
#### Commits:
|
||||
7d4bd576<br/>
|
||||
d436176b
|
||||
|
||||
#### What did we implement:
|
||||
in the Opendax, withdrawal limitation was handled by a model named `WithdrawLimit`,
|
||||
but for deposit limitation, there was no way.<br />
|
||||
so by following existence rules, we create a new model and called it `DepositLimit` with the same columns,
|
||||
and those columns are :
|
||||
|
||||
|
||||
| Name | Type | Description |<br/>
|
||||
| ---- | ---- | ----------- |<br/>
|
||||
| id | integer | Unique table identifier in database. |<br/>
|
||||
| group | string | Member group for define limits. |<br/>
|
||||
| kyc_level | string | KYC level for define limits.|<br/>
|
||||
| limit_24_hour | double | 24 hours limit. |<br/>
|
||||
| limit_1_month | double | 1 month limit. |<br/>
|
||||
|
||||
and also we added a new column to the mentioned models by name: `kind` to support `fiat` and `coin` limitation<br/>
|
||||
| Name | Type | Description |<br/>
|
||||
| ---- | ---- | ----------- |<br/>
|
||||
| kind | integer | Withdraw or Deposit kind (coin or fiat).|<br/>
|
||||
|
||||
before creation a withdrawal or deposit record by the user,
|
||||
we implemented a new function called `verify_limits` that check the user reached limitation or not,
|
||||
then permit the new withdraw or deposit record to be created.
|
||||
|
||||
### TODO
|
||||
implement admin side include APIs (tower panel) for deposit limitation part
|
||||
|
||||
|
||||
49
docs/zagros/withdraw/coin.md
Normal file
49
docs/zagros/withdraw/coin.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Withdraw: Coin
|
||||
###### Sprint: 7
|
||||
|
||||
### Outcome:
|
||||
Users can do coin withdrawal from any wallet to favorite address
|
||||
|
||||
### Implementation description:
|
||||
|
||||
#### Endpoints:
|
||||
POST {$domain}/api/v2/peatio/account/withdraws
|
||||
|
||||
#### File destination:
|
||||
{$Dena_Path}/app/api/v2/account/withdraws.rb
|
||||
|
||||
#### Commits:
|
||||
016303d1<br />
|
||||
cc565d9e<br />
|
||||
12322261<br />
|
||||
#### What did we implement:
|
||||
we add controlling step before withdraw creation, so at first check 2fa (if was enabled),<br />
|
||||
the check auth code that was sent to the email
|
||||
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
Title: Withdraw Coin
|
||||
|
||||
User->>Ranj:select favorite beneficiary
|
||||
Ranj->>User:Ask OTP code for confirming
|
||||
User-->>Ranj:if OTP code not received, try for resend after 120 seconds
|
||||
Ranj-->>Dena: Ask for sending OTP code again
|
||||
Dena-->>User:2xx send otp to his or her email
|
||||
note over User,Ranj:note parameter is optioanl
|
||||
User->>Ranj:otp, beneficiary_id, currency, amount, **note**
|
||||
Ranj->>Dena:POST: after client side checking
|
||||
Dena->>Ranj:4xx if lose any required parameters
|
||||
|
||||
Dena->>Ranj:4xx if the config variable: **ENABLE_ACCOUNT_WITHDRAWAL_API** is FALSE
|
||||
Dena->>Ranj:4xx if enter 2fa code wrong (will be check if 2fa is activated before)
|
||||
Dena->>Ranj:4xx if OTP code expired
|
||||
Dena->>Ranj:4xx if beneficiary is not active
|
||||
Dena->>Ranj:4xx if withdrawal is disabled for the currency
|
||||
note over Dena,Blockchain:The Blockchain service has own documentation
|
||||
note over Dena,Blockchain:The Blockchain service trigged by hook method in withdraw model
|
||||
Dena->>Blockchain:coin withdraw record created and balance locked
|
||||
Dena->>Ranj:2xx coin withdraw created
|
||||
Ranj->>User: notify user that new withdraw created
|
||||
```
|
||||
57
docs/zagros/withdraw/fiat.md
Normal file
57
docs/zagros/withdraw/fiat.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Withdraw: Fiat
|
||||
###### Sprint: 5
|
||||
|
||||
### Outcome:
|
||||
Users can do fiat withdrawal with the Help of the Vandar service.
|
||||
|
||||
### Implementation description:
|
||||
|
||||
#### Endpoints:
|
||||
POST {$domain}/api/v2/peatio/account/withdraws/fiat <br/>
|
||||
POST {$domain}/api/v2/peatio/account/withdraws/confirm
|
||||
#### File destination:
|
||||
{$Dena_Path}/app/api/v2/account/withdraws.rb
|
||||
|
||||
#### Commits:
|
||||
2cd9b4ad<br />
|
||||
cc7ce09c<br />
|
||||
2826a52c<br />
|
||||
b9154ef8<br />
|
||||
79d4b137<br />
|
||||
807f350b<br />
|
||||
638b493c<br />
|
||||
7769e86a<br />
|
||||
14fdfd2a<br />
|
||||
#### What did we implement:
|
||||
we implemented a new client route for user, to they can withdraw their money after entering valid 2fa and also,
|
||||
auth code that was sent to the email
|
||||
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
Title: Withdraw Fiat
|
||||
|
||||
note over User,Ranj:note parameter is optioanl
|
||||
User->>Ranj:amount, iban, currency, **note**
|
||||
Ranj->>Dena:POST: after client side checking
|
||||
Dena->>Ranj:4xx if lose any required parameters
|
||||
note over Dena,Vandar:The Vandar service has own documentation
|
||||
Dena->>Ranj:4xx if the config variable: **ENABLE_ACCOUNT_WITHDRAWAL_API** is FALSE
|
||||
Dena->>Ranj:4xx if enter 2fa code wrong (will be check if 2fa is activated before)
|
||||
Dena->>Ranj:4xx if entered IBAN not exist in current user valid IBAN list
|
||||
Dena->>User:2xx withdraw record created and send otp to his or her mail
|
||||
Ranj->>User:Ask OTP code for confirming
|
||||
User-->>Ranj:if OTP code not received, try for resend after 120 seconds
|
||||
Ranj-->>Dena: Ask for sending OTP code again
|
||||
Dena-->>User:2xx send otp to his or her email
|
||||
User->>Ranj: enter OTP code
|
||||
Ranj->>Dena:Post : OTP code for checking
|
||||
Dena->>Ranj:4xx if OTP code expired
|
||||
Dena->>Vandar:2xx account balance locked
|
||||
Dena->>Vandar:POST track_id, amount, IBAN
|
||||
Vandar->>Dena:200 new withdraw with transaction_id was created for sending the Bank
|
||||
Dena->>Ranj:withdraw will be rejected if the status of the Vandar response is false \n or withdraw will be confirmed and updated transaction_id if the status of the response is true
|
||||
Ranj->>User: show The vandar response
|
||||
|
||||
```
|
||||
58
docs/zagros/withdraw/withdraw-coin.md
Normal file
58
docs/zagros/withdraw/withdraw-coin.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Blockchain Withdraw: Coin
|
||||
###### Sprint: 7
|
||||
|
||||
### Outcome:
|
||||
Users can do coin withdrawal from any wallet to favorite address
|
||||
|
||||
#### File destination:
|
||||
- {$Dena_Path}/app/model/withdraw.rb
|
||||
- {$Dena_Path}/app/workers/amqp/withdraw_coin.rb
|
||||
|
||||
### Implementation description:
|
||||
after withdraw was created by the user through the API,
|
||||
the hooked method will be called and send the hash message (withdraw data) to RabbitMq relevant queue.<br />
|
||||
the class is responsible to handle the hash message is: `WithdrawCoin`
|
||||
|
||||
1- finding the Withdraw by the id in the hash message if not, an error will be logged that not found a record in DB and exit
|
||||
2- locking the Withdraw
|
||||
3- check state of the Withdraw is processing, if not, an error will be logged and exit
|
||||
4- check destination address was present, if not, an error will be logged, the Withdraw will be failed and exit
|
||||
5- logging warning message that withdraw is ready for sending to blockchain
|
||||
6- find an active hot wallet, if not, an error will be logged, the Withdraw will be skipped, and exit
|
||||
7- check the balance of the active hot wallet, if not appropriate log error, skip the Withdraw and exit
|
||||
8- create an object from WalletService by the active hot wallet
|
||||
9- **WalletService** call `build_withdrawal!` for the withdraw and return transaction
|
||||
10- the `txid` of the Withdraw being update by the Hash of the transaction
|
||||
11- changing withdraw the state from `processing` to `confirming` with `dispatch` function
|
||||
12- save the Withdraw in DB
|
||||
```mermaid
|
||||
graph TD
|
||||
A[API] --> |post request| B[withdraw model]
|
||||
B --> |hooked method| C(RabbitMq)
|
||||
D(withdraw coin) --> |hash message in queue| C
|
||||
D --> E((WalletService))
|
||||
|
||||
```
|
||||
#### WalletService
|
||||
this class using as a middleman for connecting to every coin wallet.<br />
|
||||
In the time of creation object, the adapter (the hand of this class to talk the crypto coin wallet) receives its config.<br />
|
||||
The aim of WalletService class is to union and structurize all crypto coin wallets implemented in the Peatio.<br />
|
||||
|
||||
##### build_withdrawal! function
|
||||
this method create transaction on blockchain by the help of adapter and specific its config
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A(Peatio) -->|Blockchain stuffs| B[BlockchainService using adapter]
|
||||
|
||||
A --> |Wallet Deposit/Withdraw| C[WalletService using adapter]
|
||||
B --> |Blockchain stuffs| D((Btc Blockchain))
|
||||
B --> |Blockchain stuffs| E((Eth Blockchain))
|
||||
B --> |Blockchain stuffs| F((...))
|
||||
B --> A
|
||||
|
||||
C --> |Wallet Deposit/Withdraw| G((Btc Wallet))
|
||||
C --> |Wallet Deposit/Withdraw| H((Eth Wallet))
|
||||
C --> |Wallet Deposit/Withdraw| I((...))
|
||||
C --> A
|
||||
```
|
||||
Reference in New Issue
Block a user