-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Conversions, fix onramp, formating proposal markdown (#78)
* GITBOOK-1: Address conversions. GET + Decode RPC/REST Block Transactions * GITBOOK-2: address conversion python * GITBOOK-3: CLI bech32 convert * GITBOOK-4: use Wynd & kado instead of Junoswap * GITBOOK-5: Formating proposal markdown
- Loading branch information
1 parent
2b28e5f
commit 05ca2be
Showing
7 changed files
with
378 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
--- | ||
description: How to convert between different aspects of data for | ||
--- | ||
|
||
# Conversions | ||
|
||
## Denominations | ||
|
||
In Cosmos, every denomination amount is formatted as an unsigned integer. With this, the chain does not have to deal with fractions. For an EVM chain this amount is typically `10**18` power, while Juno and other native Cosmos chains use the `10**6` power. This means if I want to send you 1 JUNO, I am actually sending 1,000,000 of the smaller token.\ | ||
\ | ||
You can figure out which power a token uses by its prefix character in the denomination. In the case of JUNO, the actual denomination is shown as `ujuno`. This u signals that it is using any amount times `10**6` to get the human readable amount. | ||
|
||
{% hint style="info" %} | ||
10JUNO = 10,000,000ujuno\ | ||
0.5 JUNO = 500,000ujuno\ | ||
0.00001 JUNO = 10ujuno\ | ||
\ | ||
This means the smallest amount anyone can send is 0.000001 JUNO | ||
{% endhint %} | ||
|
||
## Hex address to valcons (validator consensus) | ||
|
||
Sometimes you may want to convert from a hex address found from one of Juno's endpoints to a more readable validators consensus address to get their signing blocks and link to other data. TO do so, here is a Typescript snippet | ||
|
||
```typescript | ||
// npm i @cosmjs/encoding | ||
import {fromHex, toBech32} from '@cosmjs/encoding' | ||
|
||
// where junovalcons is the wallet prefix for the chain + valcons | ||
const prefix = "junovalcons" | ||
|
||
let addr = toBech32(prefix, fromHex("1470B9237056641663CB4DFDEC86B064578B29BF")) | ||
console.log(addr) | ||
|
||
// This outputs junovalcons1z3ctjgms2ejpvc7tfh77ep4sv3tck2dl30r3mx | ||
// which matches their page | ||
// https://ping.pub/juno/staking/junovaloper196ax4vc0lwpxndu9dyhvca7jhxp70rmcqcnylw | ||
``` | ||
|
||
With this, you can now make a mapping between a junovaloper and junovalcons address | ||
|
||
## Public Key to Valcons (Validator Consensus) | ||
|
||
{% hint style="info" %} | ||
``` | ||
You can get the Public Key from the REST/LCD endpoint: | ||
cosmos/staking/v1beta1/validators | ||
https://api.juno.strange.love/cosmos/staking/v1beta1/validators | ||
& | ||
https://.../cosmos/staking/v1beta1/validators/junovalopera_address_here | ||
``` | ||
{% endhint %} | ||
|
||
```typescript | ||
// npm i @cosmjs/encoding | ||
import {fromBase64, toBech32} from '@cosmjs/encoding' | ||
// npm i @cosmjs/crypto | ||
import { sha256 } from '@cosmjs/crypto' | ||
|
||
let prefix = "junovalcons" | ||
|
||
// Chain Format: | ||
// { | ||
// "@type":"/cosmos.crypto.ed25519.PubKey", | ||
// "key":"/O7BtNW0pafwfvomgR4ZnfldwPXiFfJs9mHg3gwfv5Q=" | ||
// } | ||
|
||
// we just need the .key string from the object | ||
let pubKey = "/O7BtNW0pafwfvomgR4ZnfldwPXiFfJs9mHg3gwfv5Q=" | ||
const addr = toBech32(prefix, sha256(fromBase64(pubKey)).slice(0, 20)) | ||
|
||
console.log(addr) | ||
// junovalcons1z3ctjgms2ejpvc7tfh77ep4sv3tck2dl30r3mx | ||
``` | ||
|
||
## Validator Operator (Valoper) to normal account | ||
|
||
```typescript | ||
// npm i @cosmjs/encoding | ||
import {toBech32, fromBech32} from '@cosmjs/encoding' | ||
|
||
let toPrefix = "juno" | ||
|
||
let initial = "junovaloper196ax4vc0lwpxndu9dyhvca7jhxp70rmcqcnylw" | ||
let converted = toBech32(toPrefix, fromBech32(initial).data) | ||
|
||
console.log(converted) | ||
// juno196ax4vc0lwpxndu9dyhvca7jhxp70rmcl99tyh | ||
``` | ||
|
||
## JUNO Address to another chain | ||
|
||
For an easy UI, you can use [https://bech32.scrtlabs.com/](https://bech32.scrtlabs.com/) for address conversions. If you need a more programmatic version | ||
|
||
#### Typescript | ||
|
||
```typescript | ||
// Typescript | ||
// npm i @cosmjs/encoding | ||
import {toBech32, fromBech32} from '@cosmjs/encoding' | ||
|
||
let toPrefix = "cosmos" | ||
|
||
let initial = "juno196ax4vc0lwpxndu9dyhvca7jhxp70rmcl99tyh" | ||
let converted = toBech32(toPrefix, fromBech32(initial).data) | ||
|
||
console.log(converted) | ||
// cosmos196ax4vc0lwpxndu9dyhvca7jhxp70rmcfhxsrt | ||
``` | ||
|
||
#### Python | ||
|
||
```python | ||
# pip install bech32 - https://pypi.org/project/bech32/ | ||
import bech32 | ||
|
||
address = "juno196ax4vc0lwpxndu9dyhvca7jhxp70rmcl99tyh" | ||
|
||
def address_convert(address=address, prefix="cosmos"): | ||
_, data = bech32.bech32_decode(address) | ||
return bech32.bech32_encode(prefix, data) | ||
|
||
converted_addr = address_convert(address, "cosmos") | ||
print(converted_addr) | ||
# cosmos196ax4vc0lwpxndu9dyhvca7jhxp70rmcfhxsrt | ||
``` | ||
|
||
#### Command Line | ||
|
||
```sh | ||
junod debug bech32-convert juno196ax4vc0lwpxndu9dyhvca7jhxp70rmcl99tyh --prefix cosmos | ||
# cosmos196ax4vc0lwpxndu9dyhvca7jhxp70rmcfhxsrt | ||
``` | ||
|
||
Here we take SG-1's JUNO address and convert it to a cosmoshub address since these are both 118 coin types. Other 118 coin types include Juno, Osmosis, Chihuahua, and others. You can only convert between the same cointype, so converting a JUNO to EVM address such as EVMOS or INJECTIVE will not function.\ | ||
\ | ||
Once converted, [you can see that SG-1 cosmos address](https://www.mintscan.io/cosmos/account/cosmos196ax4vc0lwpxndu9dyhvca7jhxp70rmcfhxsrt) also has funds just like their JUNO account by using a UI explorer like mintscan. | ||
|
184 changes: 184 additions & 0 deletions
184
developer-guides/miscellaneous/get-and-decode-transactions.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
# Get & Decode Transactions | ||
|
||
## Get Transactions | ||
|
||
You can get a blocks transactions both via the RPC and REST API. You can find other public endpoints on the [https://cosmos.directory/juno/nodes](https://cosmos.directory/juno/nodes) website | ||
|
||
### Get with RPC:  | ||
|
||
URL: [https://rpc.juno.strange.love/block](https://rpc.juno.strange.love/block)\ | ||
Transaction Array: result.block.data.txs\[] | ||
|
||
### Get with REST API: | ||
|
||
URL: [https://api.juno.strange.love/cosmos/base/tendermint/v1beta1/blocks/latest](https://api.juno.strange.love/cosmos/base/tendermint/v1beta1/blocks/latest)\ | ||
Transaction Array: block.data.txs\[] | ||
|
||
### Get with CLI: | ||
|
||
```sh | ||
# apt install jq | pacman -S jq | ||
junod q block | jq .block.data.txs | ||
``` | ||
|
||
## Decode: Command Line | ||
|
||
You can decode transaction data using the `junod` command: | ||
|
||
```sh | ||
junod tx decode <base64-amino-byte-string> --output=json | ||
``` | ||
|
||
For example | ||
|
||
```sh | ||
junod tx decode CoMECvwBCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QS0wEKK2p1bm8xaHRzOGdnMHdudXhxazl4ZXJ1a3djNHB4ZG1ncmdoZG5qdjhnZGcSP2p1bm8xZzVqOXZkNzZjcXQ3ZnNxMjJuZTdqcWZrejR2OXB0a3ZoNGprbnN2d2NocGo3NTNhdHdmczk0MmEyNRpOeyJzd2FwIjp7ImlucHV0X3Rva2VuIjoiVG9rZW4yIiwiaW5wdXRfYW1vdW50IjoiNDUyOTAwMDAwMCIsIm1pbl9vdXRwdXQiOiIwIn19KhMKBXVqdW5vEgo0NTI5MDAwMDAwCoECCiQvY29zbXdhc20ud2FzbS52MS5Nc2dFeGVjdXRlQ29udHJhY3QS2AEKK2p1bm8xaHRzOGdnMHdudXhxazl4ZXJ1a3djNHB4ZG1ncmdoZG5qdjhnZGcSP2p1bm8xZThuNmNoN21za3M0ODdlY3pueWVhZ216ZDVtbDJwcTl0Z2VkcXQydTYzdnJhMHEwcjltcXJqeTZ5cxpUeyJzd2FwIjp7ImlucHV0X3Rva2VuIjoiVG9rZW4xIiwiaW5wdXRfYW1vdW50IjoiNDUyOTAwMDAwMCIsIm1pbl9vdXRwdXQiOiI2MDAwMDAwIn19KhIKBXVqdW5vEgk5NjkwMDAwMDASZgpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohA2IKqvhI5iJwjhzNfy90VKT/UKcn7hQtmJD2WtPxiIY5EgQKAggBGEsSEgoMCgV1anVubxIDNjAwEMOaDBpAh+kKHSm07sTOYe8K/m7GhSGgmciMjGPD7eTLtLHX2x1Rp5e0m+cHK2rFB9f9ZNRITrf0L7E/emsOKjdFkUFbnA== --output json | ||
``` | ||
|
||
returns | ||
|
||
```json | ||
{ | ||
"body":{ | ||
"messages":[ | ||
{ | ||
"@type":"/cosmwasm.wasm.v1.MsgExecuteContract", | ||
"sender":"juno1hts8gg0wnuxqk9xerukwc4pxdmgrghdnjv8gdg", | ||
"contract":"juno1g5j9vd76cqt7fsq22ne7jqfkz4v9ptkvh4jknsvwchpj753atwfs942a25", | ||
"msg":{ | ||
"swap":{ | ||
"input_token":"Token2", | ||
"input_amount":"4529000000", | ||
"min_output":"0" | ||
} | ||
}, | ||
"funds":[ | ||
{ | ||
"denom":"ujuno", | ||
"amount":"4529000000" | ||
} | ||
] | ||
}, | ||
{ | ||
"@type":"/cosmwasm.wasm.v1.MsgExecuteContract", | ||
"sender":"juno1hts8gg0wnuxqk9xerukwc4pxdmgrghdnjv8gdg", | ||
"contract":"juno1e8n6ch7msks487ecznyeagmzd5ml2pq9tgedqt2u63vra0q0r9mqrjy6ys", | ||
"msg":{ | ||
"swap":{ | ||
"input_token":"Token1", | ||
"input_amount":"4529000000", | ||
"min_output":"6000000" | ||
} | ||
}, | ||
"funds":[ | ||
{ | ||
"denom":"ujuno", | ||
"amount":"969000000" | ||
} | ||
] | ||
} | ||
], | ||
"memo":"", | ||
"timeout_height":"0", | ||
"extension_options":[ | ||
|
||
], | ||
"non_critical_extension_options":[ | ||
|
||
] | ||
}, | ||
"auth_info":{ | ||
"signer_infos":[ | ||
{ | ||
"public_key":{ | ||
"@type":"/cosmos.crypto.secp256k1.PubKey", | ||
"key":"A2IKqvhI5iJwjhzNfy90VKT/UKcn7hQtmJD2WtPxiIY5" | ||
}, | ||
"mode_info":{ | ||
"single":{ | ||
"mode":"SIGN_MODE_DIRECT" | ||
} | ||
}, | ||
"sequence":"75" | ||
} | ||
], | ||
"fee":{ | ||
"amount":[ | ||
{ | ||
"denom":"ujuno", | ||
"amount":"600" | ||
} | ||
], | ||
"gas_limit":"200003", | ||
"payer":"", | ||
"granter":"" | ||
} | ||
}, | ||
"signatures":[ | ||
"h+kKHSm07sTOYe8K/m7GhSGgmciMjGPD7eTLtLHX2x1Rp5e0m+cHK2rFB9f9ZNRITrf0L7E/emsOKjdFkUFbnA==" | ||
] | ||
} | ||
``` | ||
|
||
## Decode with Python (junod) | ||
|
||
Using junod and python, we can save this JSON data for later using the following example.\ | ||
This excerpt was taken from the [juno-analysis repo](https://github.com/Reecepbcups/juno-analysis/blob/main/main.py) | ||
|
||
```python | ||
# python3 -m pip install httpx | ||
import httpx, json, os | ||
|
||
RPC_URL = "https://rpc.juno.strange.love:443" | ||
height = 7_000_000 | ||
|
||
client = httpx.Client() | ||
tx_data: dict[int, dict] = {} | ||
|
||
def run_cmd(cmd) -> str: | ||
return os.popen(cmd).read() | ||
|
||
|
||
def get_block_transactions(height: int) -> list[str]: | ||
block = client.get(f"{RPC_URL}/block?height={height}").json() | ||
block_txs = block["result"]["block"]["data"]["txs"] | ||
return block_txs | ||
|
||
|
||
def main(): | ||
version = run_cmd("junod version") | ||
if len(version) == 0: | ||
print("Junod not installed. Please install junod and try again.") | ||
exit(1) | ||
|
||
txs = get_block_transactions(height=height) | ||
|
||
for tx in txs: | ||
txs_json = json.loads(run_cmd(f"junod tx decode {tx} --output json")) | ||
tx_data[height] = txs_json.get("body", {}).get("messages", []) | ||
|
||
# Do somethign with that tx data here | ||
print(tx_data) | ||
|
||
if __name__ == "__main__": | ||
main() | ||
``` | ||
|
||
## Decode with Python (protobuf) | ||
|
||
If you have experience with protobuf, you can use cosmospy to decode transaction data and decode is from base64 strings | ||
|
||
```python | ||
# python -m pip install cosmospy-protobuf | ||
import base64 | ||
import cosmospy_protobuf.cosmos.tx.v1beta1.tx_pb2 as tx_pb2 | ||
|
||
tx = "CpMBCpABChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnAKLWNvc21vczEweGw5cXV1Z2N2amhsMGdsamplaG1oeHhhN3cwaDM5ZTJ2aGFndhItY29zbW9zMThsemp0NWpwcjdtd3U0dHlkbGNmZ2N1dHI2Z25ycGsweWo4ZnNjGhAKBXVhdG9tEgcxMDAwMDAwEmcKUApGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQM+g5XXnqLLelLxz8CTy+vG5aO7SohNKS78OtL9ysdcEhIECgIIARgCEhMKDQoFdWF0b20SBDIyNzUQ+MYFGkBbTDHP0mn8d2hxQnNUE/SeudBrXMgjyRO5Bv12D4iWgk4cPsczc6EaDQD3v7cqqD22HL8ZZXVMF3GKi1SNAGNT" | ||
decode64 = base64.b64decode(tx) | ||
tx = tx_pb2.Tx() | ||
tx.ParseFromString(decode64) | ||
|
||
print(tx) | ||
# print(tx.body.messages) | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.