docs: Add versioned tx info to exchange integration guide (#27564)

* docs: Add versioned tx info to exchange integration guide

* feedback, extra tips, formatting
This commit is contained in:
Justin Starry 2022-09-22 14:19:36 +08:00 committed by GitHub
parent 108b245e6b
commit 91d556dc66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 241 additions and 91 deletions

View File

@ -159,8 +159,14 @@ the minimum rent-exempt balance for your deposit accounts, query the
[`getMinimumBalanceForRentExemption` endpoint](developing/clients/jsonrpc-api.md#getminimumbalanceforrentexemption):
```bash
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getMinimumBalanceForRentExemption","params":[0]}' localhost:8899
curl localhost:8899 -X POST -H "Content-Type: application/json" -d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getMinimumBalanceForRentExemption",
"params":[0]
}'
# Result
{"jsonrpc":"2.0","result":890880,"id":1}
```
@ -175,6 +181,37 @@ greater security. If so, you will need to move SOL to hot accounts using our
When a user wants to deposit SOL into your exchange, instruct them to send a
transfer to the appropriate deposit address.
### Versioned Transaction Migration
When the Mainnet Beta network starts processing versioned transactions, exchanges
**MUST** make changes. If no changes are made, deposit detection will no longer
work properly because fetching a versioned transaction or a block containing
versioned transactions will return an error.
- `{"maxSupportedTransactionVersion": 0}`
The `maxSupportedTransactionVersion` parameter must be added to `getBlock` and
`getTransaction` requests to avoid disruption to deposit detection. The latest
transaction version is `0` and should be specified as the max supported
transaction version value.
It's important to understand that versioned transactions allow users to create
transactions that use another set of account keys loaded from on-chain address
lookup tables.
- `{"encoding": "jsonParsed"}`
When fetching blocks and transactions, it's now recommended to use the
`"jsonParsed"` encoding because it includes all transaction account keys
(including those from lookup tables) in the message `"accountKeys"` list.
This makes it straightforward to resolve balance changes detailed in
`preBalances` / `postBalances` and `preTokenBalances` / `postTokenBalances`.
If the `"json"` encoding is used instead, entries in `preBalances` /
`postBalances` and `preTokenBalances` / `postTokenBalances` may refer to
account keys that are **NOT** in the `"accountKeys"` list and need to be
resolved using `"loadedAddresses"` entries in the transaction metadata.
### Poll for Blocks
To track all the deposit accounts for your exchange, poll for each confirmed
@ -185,8 +222,14 @@ Solana API node.
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":"getBlocks","params":[5]}' localhost:8899
curl localhost:8899 -X POST -H "Content-Type: application/json" -d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getBlocks",
"params": [5]
}'
# Result
{"jsonrpc":"2.0","result":[5,6,8,9,11],"id":1}
```
@ -194,63 +237,92 @@ Not every slot produces a block, so there may be gaps in the sequence of integer
- For each block, request its contents with a [`getBlock` request](developing/clients/jsonrpc-api.md#getblock):
```bash
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getBlock","params":[5, "json"]}' localhost:8899
### Block Fetching Tips
- `{"rewards": false}`
By default, fetched blocks will return information about validator fees on each
block and staking rewards on epoch boundaries. If you don't need this
information, disable it with the "rewards" parameter.
- `{"transactionDetails": "accounts"}`
By default, fetched blocks will return a lot of transaction info and metadata
that isn't necessary for tracking account balances. Set the "transactionDetails"
parameter to speed up block fetching.
```bash
curl localhost:8899 -X POST -H 'Content-Type: application/json' -d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getBlock",
"params": [
148696677,
{
"encoding": "jsonParsed",
"maxSupportedTransactionVersion": 0,
"transactionDetails": "accounts",
"rewards": false
}
]
}'
# Result
{
"jsonrpc": "2.0",
"result": {
"blockhash": "2WcrsKSVANoe6xQHKtCcqNdUpCQPQ3vb6QTgi1dcE2oL",
"parentSlot": 4,
"previousBlockhash": "7ZDoGW83nXgP14vnn9XhGSaGjbuLdLWkQAoUQ7pg6qDZ",
"rewards": [],
"blockHeight": 134239354,
"blockTime": 1662064341,
"blockhash": "AuPLyvFX2yA1aVFUqvFfyiB2Sxwu2McL8ALhwbU6w7er",
"parentSlot": 148696675,
"previousBlockhash": "AKu155zCvrgrPvcVBFyboAfY2GF33S3ZDkj2Pa8x19XM",
"transactions": [
{
"meta": {
"err": null,
"fee": 5000,
"postBalances": [
2033973061360,
218099990000,
42000000003
7161091286,
2769675090,
1
],
"postTokenBalances": [],
"preBalances": [
2044973066360,
207099990000,
42000000003
8130576328,
1800195048,
1
],
"preTokenBalances": [],
"status": {
"Ok": null
}
},
"transaction": {
"message": {
"accountKeys": [
"Bbqg1M4YVVfbhEzwA9SpC9FhsaG83YMTYoR4a8oTDLX",
"47Sbuv6jL7CViK9F2NMW51aQGhfdpUu7WNvKyH645Rfi",
"11111111111111111111111111111111"
],
"header": {
"numReadonlySignedAccounts": 0,
"numReadonlyUnsignedAccounts": 1,
"numRequiredSignatures": 1
"accountKeys": [
{
"pubkey": "ogDsdvMKRRRMmsrT2hTPdkQBu1qY2z1jBDzgpi8HZri",
"signer": true,
"source": "transaction",
"writable": true
},
"instructions": [
{
"accounts": [
0,
1
],
"data": "3Bxs3zyH82bhpB8j",
"programIdIndex": 2
}
],
"recentBlockhash": "7GytRgrWXncJWKhzovVoP9kjfLwoiuDb3cWjpXGnmxWh"
},
{
"pubkey": "3M2b3tLji7rvscqrLAHMukYxDK2nB96Q9hwfV6QkdzBN",
"signer": false,
"source": "transaction",
"writable": true
},
{
"pubkey": "11111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
}
],
"signatures": [
"dhjhJp2V2ybQGVfELWM1aZy98guVVsxRCB5KhNiXFjCBMK5KEyzV8smhkVvs3xwkAug31KnpzJpiNPtcD5bG1t6"
"36Q383JMiqiobuPV9qBqy41xjMsVnQBm9rdZSdpbrLTGhSQDTGZJnocM4TQTVfUGfV2vEX9ZB3sex6wUBUWzjEvs"
]
}
},
"version": "legacy"
}
]
},
@ -262,9 +334,9 @@ 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#lamport), 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
example, if the deposit address of interest is
`3M2b3tLji7rvscqrLAHMukYxDK2nB96Q9hwfV6QkdzBN`, this transaction represents a
transfer of 2769675090 - 1800195048 = 969,480,042 lamports = 0.969485042 SOL
If you need more information about the transaction type or other specifics, you
can request the block from RPC in binary format, and parse it using either our
@ -282,28 +354,45 @@ time.
request to the api node:
```bash
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getSignaturesForAddress","params":["6H94zdiaYfRfPfKjYLjyr2VFBg6JHXygy84r3qhc3NsC", {"limit": 3}]}' localhost:8899
curl localhost:8899 -X POST -H "Content-Type: application/json" -d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getSignaturesForAddress",
"params": [
"3M2b3tLji7rvscqrLAHMukYxDK2nB96Q9hwfV6QkdzBN",
{
"limit": 3
}
]
}'
# Result
{
"jsonrpc": "2.0",
"result": [
{
"blockTime": 1662064640,
"confirmationStatus": "finalized",
"err": null,
"memo": null,
"signature": "35YGay1Lwjwgxe9zaH6APSHbt9gYQUCtBWTNL3aVwVGn9xTFw2fgds7qK5AL29mP63A9j3rh8KpN1TgSR62XCaby",
"slot": 114
"signature": "3EDRvnD5TbbMS2mCusop6oyHLD8CgnjncaYQd5RXpgnjYUXRCYwiNPmXb6ZG5KdTK4zAaygEhfdLoP7TDzwKBVQp",
"slot": 148697216
},
{
"blockTime": 1662064434,
"confirmationStatus": "finalized",
"err": null,
"memo": null,
"signature": "4bJdGN8Tt2kLWZ3Fa1dpwPSEkXWWTSszPSf1rRVsCwNjxbbUdwTeiWtmi8soA26YmwnKD4aAxNp8ci1Gjpdv4gsr",
"slot": 112
"signature": "4rPQ5wthgSP1kLdLqcRgQnkYkPAZqjv5vm59LijrQDSKuL2HLmZHoHjdSLDXXWFwWdaKXUuryRBGwEvSxn3TQckY",
"slot": 148696843
},
{
"blockTime": 1662064341,
"confirmationStatus": "finalized",
"err": null,
"memo": null,
"signature": "dhjhJp2V2ybQGVfELWM1aZy98guVVsxRCB5KhNiXFjCBMK5KEyzV8smhkVvs3xwkAug31KnpzJpiNPtcD5bG1t6",
"slot": 108
"signature": "36Q383JMiqiobuPV9qBqy41xjMsVnQBm9rdZSdpbrLTGhSQDTGZJnocM4TQTVfUGfV2vEX9ZB3sex6wUBUWzjEvs",
"slot": 148696677
}
],
"id": 1
@ -314,58 +403,102 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"m
[`getTransaction`](developing/clients/jsonrpc-api.md#gettransaction) request:
```bash
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getTransaction","params":["dhjhJp2V2ybQGVfELWM1aZy98guVVsxRCB5KhNiXFjCBMK5KEyzV8smhkVvs3xwkAug31KnpzJpiNPtcD5bG1t6", "json"]}' localhost:8899
curl localhost:8899 -X POST -H 'Content-Type: application/json' -d '{
"jsonrpc":"2.0",
"id":1,
"method":"getTransaction",
"params":[
"4Cswku8E9sm8TVZ4kP4iHbwCQygMDx78SXSURBkJuJAaXCbL9eYM8RPS2BDooLd5ftML4JjQrohe4deJrFkVzPBa",
{
"encoding":"jsonParsed",
"maxSupportedTransactionVersion":0
}
]
}'
// Result
# 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"
]
},
"blockTime": 1660763773,
"meta": {
"err": null,
"fee": 5000,
"innerInstructions": [],
"logMessages": [
"Program 11111111111111111111111111111111 invoke [1]",
"Program 11111111111111111111111111111111 success"
],
"postBalances": [
2033973061360,
218099990000,
42000000003
2078778739,
1,
26396753106
],
"postTokenBalances": [],
"preBalances": [
2044973066360,
207099990000,
42000000003
2078783740,
1,
26396753105
],
"preTokenBalances": [],
"rewards": [],
"status": {
"Ok": null
}
}
},
"slot": 155713260,
"transaction": {
"message": {
"accountKeys": [
{
"pubkey": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde",
"signer": true,
"source": "transaction",
"writable": true
},
{
"pubkey": "11111111111111111111111111111111",
"signer": false,
"source": "transaction",
"writable": false
},
{
"pubkey": "2xNweLHLqrbx4zo1waDvgWJHgsUpPj8Y8icbAFeR4a8i",
"signer": false,
"source": "lookupTable",
"writable": true
}
],
"addressTableLookups": [
{
"accountKey": "3LZbwptsCkv5R5uu1GNZKiX9SoC6egNG8NXg9zH5ZVM9",
"readonlyIndexes": [],
"writableIndexes": [
1
]
}
],
"instructions": [
{
"parsed": {
"info": {
"destination": "2xNweLHLqrbx4zo1waDvgWJHgsUpPj8Y8icbAFeR4a8i",
"lamports": 1,
"source": "9aE476sH92Vz7DMPyq5WLPkrKWivxeuTKEFKd2sZZcde"
},
"type": "transfer"
},
"program": "system",
"programId": "11111111111111111111111111111111"
}
],
"recentBlockhash": "9nLh3gmVhyjrh68UeV1rafyo8BFNyZtHSRUUjZYikveh"
},
"signatures": [
"4Cswku8E9sm8TVZ4kP4iHbwCQygMDx78SXSURBkJuJAaXCbL9eYM8RPS2BDooLd5ftML4JjQrohe4deJrFkVzPBa"
]
},
"version": 0
},
"id": 1
}
@ -435,8 +568,19 @@ The `confirmations` field reports how many
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
curl localhost:8899 -X POST -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0",
"id":1,
"method":"getSignatureStatuses",
"params":[
[
"5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW",
"5j7s6NiJS3JAkvgkoc18WVAsiSaci2pxB2A6ueCJP4tprA2TFg9wSyTLeYouxPBJEMzJinENTkpA52YStRW5Dia7"
]
]
}'
# Result
{
"jsonrpc": "2.0",
"result": {
@ -480,7 +624,7 @@ As withdrawals are irreversible, it may be a good practice to validate a
user-supplied account address before authorizing a withdrawal in order to
prevent accidental loss of user funds.
#### Basic verfication
#### Basic verification
Solana addresses a 32-byte array, encoded with the bitcoin base58 alphabet. This
results in an ASCII text string matching the following regular expression:
@ -575,8 +719,14 @@ holding no data), currently: 0.000890880 SOL
Similarly, every deposit account must contain at least this balance.
```bash
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"getMinimumBalanceForRentExemption","params":[0]}' localhost:8899
curl localhost:8899 -X POST -H "Content-Type: application/json" -d '{
"jsonrpc": "2.0",
"id": 1,
"method": "getMinimumBalanceForRentExemption",
"params": [0]
}'
# Result
{"jsonrpc":"2.0","result":890880,"id":1}
```
@ -722,7 +872,7 @@ identify the token mint and account owner (main wallet address) of the affected
account.
Note that if a receiving account is created during the transaction, it will have no
`preTokenBalance` entry as there is no existing account state. In this
`preTokenBalance` entry as there is no existing account state. In this
case, the initial balance can be assumed to be zero.
### Withdrawing
@ -734,7 +884,7 @@ the exchange should check the address as
[described above](#validating-user-supplied-account-addresses-for-withdrawals).
Additionally this address must be owned by the System Program and have no
account data. If the address has no SOL balance, user confirmation should be
obtained before proceeding with the withdrawal. All other withdrawal addresses
obtained before proceeding with the withdrawal. All other withdrawal addresses
must be rejected.
From the withdrawal address, the [Associated Token Account](https://spl.solana.com/associated-token-account)