From ee0c675bca8822ed52fea22d80a7a80e8e33da52 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 14 May 2020 15:39:40 -0600 Subject: [PATCH] Add exchange integration doc --- docs/src/SUMMARY.md | 2 + docs/src/integrations/README.md | 0 docs/src/integrations/exchange.md | 183 ++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 docs/src/integrations/README.md create mode 100644 docs/src/integrations/exchange.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index d9d30ea47554d0..cf4d54d799626c 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -30,6 +30,8 @@ * [Anatomy of a Transaction](transaction.md) * [JSON RPC API](apps/jsonrpc-api.md) * [JavaScript API](apps/javascript-api.md) +* [Integration Guides](integrations/README.md) + * [Exchange](integrations/exchange.md) * [Run a Validator](running-validator/README.md) * [Validator Requirements](running-validator/validator-reqs.md) * [Start a Validator](running-validator/validator-start.md) diff --git a/docs/src/integrations/README.md b/docs/src/integrations/README.md new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/docs/src/integrations/exchange.md b/docs/src/integrations/exchange.md new file mode 100644 index 00000000000000..f1a5ba104c4388 --- /dev/null +++ b/docs/src/integrations/exchange.md @@ -0,0 +1,183 @@ +# Add Solana to Your Exchange + +This guide describes how to add Solana's native token SOL to your cryptocurrency +exchange. + +## Node Setup + +We highly recommend setting up at least one of your own Solana api nodes to +give you a trusted entrypoint to the network and allow you full control over how +much data is retained. + +To run an api node: +1. [Install the Solana command-line tool suite](../cli/install-solana-cli-tools.md) +2. Boot the node with at least the following parameters: +```bash +solana-validator \ + --ledger \ + --entrypoint \ + --expected-genesis-hash \ + --expected-shred-version \ + --rpc-port 8899 \ + --no-voting \ + --enable-rpc-transaction-history +``` + + Customize `--ledger` to your desired ledger storage location, and `--rpc-port` to the port you want to expose. + + The `--entrypoint`, `--expected-genesis-hash`, and `--expected-shred-version` parameters are all specific to the cluster you are joining. + [Current parameters for Mainnet Beta](../clusters.md#example-solana-validator-command-line-2) + + Optional parameters to consider: + - `--limit-ledger-size` specifies how many ledger shreds to retain on disk. If you do not include this parameter, the ledger will keep the entire ledger until it runs out of disk space. A larger value like `--limit-ledger-size 250000000000` is good for a couple days + - `--trusted-validator` can protect you from booting from a malicious snapshot. [More on the value of booting with trusted validators](../running-validator/validator-start.md#trusted-validators) + +## Setting up Deposit Accounts + +Solana accounts do not require any on-chain initialization; once they contain +some SOL, they exist. To set up a deposit account for your exchange, simply +generate a Solana keypair using any of our [wallet tools](../wallet-guide/cli.md). + +We recommend using a unique deposit account for each of your users. + +## Listening for Deposits + +When a user wants to deposit SOL into your exchange, instruct them to send a +transfer to the appropriate deposit address. + +### Poll for Blocks + +The easiest way to track all the deposit accounts for your exchange is to poll +for each confirmed block and inspect for addresses of interest, using the +JSON-RPC service of the Solana api node. + +1. To identify which blocks are available, send a [`getConfirmedBlocks` request](../apps/jsonrpc-api.md#getconfirmedblocks), +passing the last block you have already processed as the start-slot parameter: + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlocks","params":[5]}' localhost:8899 + +{"jsonrpc":"2.0","result":[5,6,8,9,11],"id":1} +``` +Not every slot produces a block, so there may be gaps in the sequence of integers. + +2. For each block, request its contents with a [`getConfirmedBlock` request](../apps/jsonrpc-api.md#getconfirmedblock): + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedBlock","params":[5, "json"]}' localhost:8899 + +{"jsonrpc":"2.0","result":{"blockhash":"2WcrsKSVANoe6xQHKtCcqNdUpCQPQ3vb6QTgi1dcE2oL","parentSlot":4,"previousBlockhash":"7ZDoGW83nXgP14vnn9XhGSaGjbuLdLWkQAoUQ7pg6qDZ","rewards":[],"transactions":[{"meta":{"err":null,"fee":5000,"postBalances":[2033973061360,218099990000,42000000003],"preBalances":[2044973066360,207099990000,42000000003],"status":{"Ok":null}},"transaction":{"message":{"accountKeys":["Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX","47Sbuv6jL7CViK9F2NMW51aQGhfdpUu7WNvKyH645Rfi","11111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":1,"numRequiredSignatures":1},"instructions":[{"accounts":[0,1],"data":"3Bxs3zyH82bhpB8j","programIdIndex":2}],"recentBlockhash":"7GytRgrWXncJWKhzovVoP9kjfLwoiuDb3cWjpXGnmxWh"},"signatures":["dhjhJp2V2ybQGVfELWM1aZy98guVVsxRCB5KhNiXFjCBMK5KEyzV8smhkVvs3xwkAug31KnpzJpiNPtcD5bG1t6"]}}]},"id":1} +``` + +The `preBalances` and `postBalances` fields allow you to track the balance +changes in every account without having to parse the entire transaction. They +list the starting and ending balances of each account in +[lamports](../terminology.md#lamports), indexed to the `accountKeys` list. For +example, if the deposit address if interest is +`47Sbuv6jL7CViK9F2NMW51aQGhfdpUu7WNvKyH645Rfi`, this transaction represents a +transfer of 218099990000 - 207099990000 = 11000000000 lamports = 11 SOL + +If you need more information about the transaction type or other specifics, you +can request the block in binary format, and parse it using either our +[Rust SDK](https://github.com/solana-labs/solana/tree/master/sdk) or +[Javascript SDK](https://github.com/solana-labs/solana-web3.js). + +### Address History + +You can also query the transaction history of a specific address. + +1. Send a [`getConfirmedSignaturesForAddress`](../apps/jsonrpc-api.md#getconfirmedsignaturesforaddress) +request to the api node, specifying a range of recent slots: + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedSignaturesForAddress","params":["6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC", 0, 10]}' localhost:8899 + +{"jsonrpc":"2.0","result":{["35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby","4bJdGN8Tt2kLWZ3Fa1dpwPSEkXWWTSszPSf1rRVsCwNjxbbUdwTeiWtmi8soA26YmwnKD4aAxNp8ci1Gjpdv4gsr","dhjhJp2V2ybQGVfELWM1aZy98guVVsxRCB5KhNiXFjCBMK5KEyzV8smhkVvs3xwkAug31KnpzJpiNPtcD5bG1t6"]},"id":1} +``` + +2. For each signature returned, get the transaction details by sending a +[`getConfirmedTransaction`](../apps/jsonrpc-api.md#getconfirmedtransaction) request: + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getConfirmedTransaction","params":["dhjhJp2V2ybQGVfELWM1aZy98guVVsxRCB5KhNiXFjCBMK5KEyzV8smhkVvs3xwkAug31KnpzJpiNPtcD5bG1t6", "json"]}' localhost:8899 + +// Result +{"jsonrpc":"2.0","result":{"slot":5,"transaction":{"message":{"accountKeys":["Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX","47Sbuv6jL7CViK9F2NMW51aQGhfdpUu7WNvKyH645Rfi","11111111111111111111111111111111"],"header":{"numReadonlySignedAccounts":0,"numReadonlyUnsignedAccounts":1,"numRequiredSignatures":1},"instructions":[{"accounts":[0,1],"data":"3Bxs3zyH82bhpB8j","programIdIndex":2}],"recentBlockhash":"7GytRgrWXncJWKhzovVoP9kjfLwoiuDb3cWjpXGnmxWh"},"signatures":["dhjhJp2V2ybQGVfELWM1aZy98guVVsxRCB5KhNiXFjCBMK5KEyzV8smhkVvs3xwkAug31KnpzJpiNPtcD5bG1t6"]},"meta":{"err":null,"fee":5000,"postBalances":[2033973061360,218099990000,42000000003],"preBalances":[2044973066360,207099990000,42000000003],"status":{"Ok":null}}},"id":1} +``` + +## Sending Withdrawals + +To accommodate a user's request to withdraw SOL, you must generate a Solana +transfer transaction, and send it to the api node to be forwarded to the +cluster. + +### Synchronous + +Sending a synchronous transfer to the Solana cluster allows you to easily ensure +that a transfer is successful and finalized by the cluster. + +Solana's command-line tool offers a simple command, `solana transfer`, to +generate, submit, and confirm transfer transactions. By default, this method +will wait and track progress on stderr until the transaction has been finalized +by the cluster. If the transaction fails, it will report any transaction errors. + +```bash +solana transfer --keypair --url http://api.mainnet-beta.solana.com +``` + +The [Solana Javascript SDK](https://github.com/solana-labs/solana-web3.js) +offers a similar approach for the JS ecosystem. Use the `SystemProgram` to build +a transfer transaction, and submit it using the `sendAndConfirmTransaction` +method. + +### Asynchronous + +For greater flexibility, you can submit withdrawal transfers asynchronously. In +these cases, it is your responsibility to verify that the transaction succeeded +and was finalized by the cluster. + +Note: Each transaction contains a [recent blockhash](../transaction.md#blockhash-format) +to indicate its liveness. It is **critical** to wait until this blockhash +expires before retrying a withdrawal transfer that does not appear to have been +confirmed or finalized by the cluster. Otherwise, you risk a double spend. We +recommend waiting 500 slots between retries. + +In the command-line tool, pass the `--no-wait` argument to send a transfer +asynchronously: + +```bash +solana transfer --no-wait --keypair --url http://api.mainnet-beta.solana.com +``` + +You can also build and serialize the transaction manually, and fire it off to +the cluster using the JSON-RPC [`sendTransaction` endpoint](../apps/jsonrpc-api.md#sendtransaction). + +#### Transaction Confirmations & Finality + +Get the status of a batch of transactions using the +[`getSignatureStatuses` JSON-RPC endpoint](../apps/jsonrpc-api.md#getsignaturestatuses). +The `confirmations` field reports how many +[confirmed blocks](../terminology.md#confirmed-block) have elapsed since the +transaction was processed. If `confirmations: null`, it is [finalized](../terminology.md#finality). + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getSignatureStatuses", "params":[["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW", "5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7"]]}' http://localhost:8899 + +{"jsonrpc":"2.0","result":{"context":{"slot":82},"value":[{"slot": 72, "confirmations": 10, "err": null, "status": {"Ok": null}}, {"slot": 48, "confirmations": null, "err": null, "status": {"Ok": null}}]},"id":1} +``` + +#### Blockhash Expiration + +To check whether a recent blockhash is still valid, send a +[`getFeeCalculatorForBlockhash`](../apps/jsonrpc-api.md#getfeecalculatorforblockhash) +request with the blockhash as a parameter. If the response value is null, the +blockhash is expired, and the withdrawal transaction is safe to retry. + +## Testing the Integration + + + +## Going Further + +- **Offline accounts:** you may wish to keep the keys for one or more collection accounts offline for greater security. If so, you will need to move SOL to hot accounts using our [offline methods](../offline-signing/README.md). +-