From 4d8aae8a791cbf8b0508ee0ef3e6d08edd3fc834 Mon Sep 17 00:00:00 2001 From: federiconardelli7 Date: Wed, 5 Feb 2025 12:49:37 +0100 Subject: [PATCH] Add category Hardware Wallets that list Ledger and Keystone and their SDKs --- content/docs/api-reference/index-api.mdx | 4 +- content/docs/api-reference/info-api.mdx | 25 +- content/docs/api-reference/p-chain/api.mdx | 574 +++----- content/docs/api-reference/x-chain/api.mdx | 1286 +---------------- .../avalanche-warp-messaging/deep-dive.mdx | 45 +- .../evm-integration.mdx | 66 +- .../docs/cross-chain/teleporter/overview.mdx | 6 +- content/integrations/keystone.mdx | 52 + content/integrations/ledger.mdx | 68 + public/images/keystone.png | Bin 0 -> 11320 bytes public/images/ledger.png | Bin 0 -> 2856 bytes 11 files changed, 493 insertions(+), 1633 deletions(-) create mode 100644 content/integrations/keystone.mdx create mode 100644 content/integrations/ledger.mdx create mode 100644 public/images/keystone.png create mode 100644 public/images/ledger.png diff --git a/content/docs/api-reference/index-api.mdx b/content/docs/api-reference/index-api.mdx index d67a0b46b03..05ac19f5fc6 100644 --- a/content/docs/api-reference/index-api.mdx +++ b/content/docs/api-reference/index-api.mdx @@ -3,7 +3,7 @@ title: Index API description: This page is an overview of the Index API associated with AvalancheGo. --- -AvalancheGo can be configured to run with an indexer. That is, it saves (indexes) every container (a block, vertex or transaction) it accepts on the X-Chain, P-Chain and C-Chain. To run AvalancheGo with indexing enabled, set command line flag [\--index-enabled](https://github.com/nodes/configure/configs-flags#apis) to true. +AvalancheGo can be configured to run with an indexer. That is, it saves (indexes) every container (a block, vertex or transaction) it accepts on the X-Chain, P-Chain and C-Chain. To run AvalancheGo with indexing enabled, set command line flag [\--index-enabled](https://docs.avax.network/nodes/configure/configs-flags#--index-enabled-boolean) to true. **AvalancheGo will only index containers that are accepted when running with `--index-enabled` set to true.** To ensure your node has a complete index, run a node with a fresh database and `--index-enabled` set to true. The node will accept every block, vertex and transaction in the network history during bootstrapping, ensuring your index is complete. @@ -21,7 +21,7 @@ There is a Go implementation of an Index API client. See documentation [here](ht ## Format -This API uses the `json 2.0` RPC format. For more information on making JSON RPC calls, see [here](https://github.com/api-reference/standards/guides/issuing-api-calls). +This API uses the `json 2.0` RPC format. For more information on making JSON RPC calls, see [here](https://docs.avax.network/api-reference/standards/guides/issuing-api-calls). ## Endpoints diff --git a/content/docs/api-reference/info-api.mdx b/content/docs/api-reference/info-api.mdx index c9e9e82c7b1..1de525e3b20 100644 --- a/content/docs/api-reference/info-api.mdx +++ b/content/docs/api-reference/info-api.mdx @@ -389,6 +389,10 @@ curl -X POST --data '{ ### `info.getTxFee` + +Deprecated as of [v1.12.2](https://github.com/ava-labs/avalanchego/releases/tag/v1.12.2). + + Get the fees of the network. **Signature**: @@ -408,15 +412,15 @@ info.getTxFee() -> } ``` -- `txFee` is the default fee for making transactions. -- `createAssetTxFee` is the fee for creating a new asset. -- `createSubnetTxFee` is the fee for creating a new Avalanche L1. -- `transformSubnetTxFee` is the fee for converting a PoA Avalanche L1 into a PoS Avalanche L1. -- `createBlockchainTxFee` is the fee for creating a new blockchain. -- `addPrimaryNetworkValidatorFee` is the fee for adding a new primary network validator. -- `addPrimaryNetworkDelegatorFee` is the fee for adding a new primary network delegator. -- `addSubnetValidatorFee` is the fee for adding a new Avalanche L1 validator. -- `addSubnetDelegatorFee` is the fee for adding a new Avalanche L1 delegator. +- `txFee` is the default fee for issuing X-Chain transactions. +- `createAssetTxFee` is the fee for issuing a `CreateAssetTx` on the X-Chain. +- `createSubnetTxFee` is no longer used. +- `transformSubnetTxFee` is no longer used. +- `createBlockchainTxFee` is no longer used. +- `addPrimaryNetworkValidatorFee` is no longer used. +- `addPrimaryNetworkDelegatorFee` is no longer used. +- `addSubnetValidatorFee` is no longer used. +- `addSubnetDelegatorFee` is no longer used. All fees are denominated in nAVAX. @@ -695,7 +699,8 @@ curl -X POST --data '{ "cortinaTime": "2020-12-05T05:00:00Z", "cortinaXChainStopVertexID": "11111111111111111111111111111111LpoYY", "durangoTime": "2020-12-05T05:00:00Z", - "etnaTime": "2024-10-09T20:00:00Z" + "etnaTime": "2024-10-09T20:00:00Z", + "fUpgradeTime": "9999-12-01T05:00:00Z" }, "id": 1 } diff --git a/content/docs/api-reference/p-chain/api.mdx b/content/docs/api-reference/p-chain/api.mdx index 14aab0e52bb..f8466094d96 100644 --- a/content/docs/api-reference/p-chain/api.mdx +++ b/content/docs/api-reference/p-chain/api.mdx @@ -17,63 +17,6 @@ This API uses the `json 2.0` RPC format. ## Methods -### `platform.exportKey` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](https://github.com/api-reference/keystore-api). - - - -Get the private key that controls a given address. - -**Signature:** - -``` -platform.exportKey({ - username: string, - password: string, - address: string -}) -> {privateKey: string} -``` - -- `username` is the user that controls `address`. -- `password` is `username`‘s password. -- `privateKey` is the string representation of the private key that controls `address`. - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" :1, - "method" :"platform.exportKey", - "params" :{ - "username" :"myUsername", - "password": "myPassword", - "address": "P-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "privateKey": "PrivateKey-Lf49kAJw3CbaL783vmbeAJvhscJqC7vi5yBYLxw2XfbzNS5RS" - } -} -``` - ### `platform.getBalance` @@ -624,9 +567,22 @@ platform.getCurrentValidators({ txID: string, startTime: string, endTime: string, - stakeAmount: string, nodeID: string, weight: string, + validationID: string, + publicKey: string, + remainingBalanceOwner: { + locktime: string, + threshold: string, + addresses: string[] + }, + deactivationOwner: { + locktime: string, + threshold: string, + addresses: string[] + }, + minNonce: string, + balance: string, validationRewardOwner: { locktime: string, threshold: string, @@ -651,7 +607,7 @@ platform.getCurrentValidators({ txID: string, startTime: string, endTime: string, - stakeAmount: string, + weight: string, nodeID: string, rewardOwner: { locktime: string, @@ -669,46 +625,47 @@ platform.getCurrentValidators({ - `nodeIDs` is a list of the NodeIDs of current validators to request. If omitted, all current validators are returned. If a specified NodeID is not in the set of current validators, it will not be included in the response. -- `validators`: +- `validators` can include different fields based on the subnet type (L1, PoA Subnets, the Primary Network): - `txID` is the validator transaction. - `startTime` is the Unix time when the validator starts validating the Subnet. - - `endTime` is the Unix time when the validator stops validating the Subnet. - - `stakeAmount` is the amount of tokens this validator staked. Omitted if `subnetID` is not a PoS - Subnet. + - `endTime` is the Unix time when the validator stops validating the Subnet. Ommitted if `subnetID` is a L1 Subnet. - `nodeID` is the validator’s node ID. - - `weight` is the validator’s weight when sampling validators. Omitted if `subnetID` is a PoS - Subnet. + - `weight` is the validator’s weight (stake) when sampling validators. + - `validationID` is the ID for L1 subnet validator registration transaction. Omitted if `subnetID` is not an L1 Subnet. + - `publicKey` is the compressed BLS public key of the validator. Omitted if `subnetID` is not an L1 Subnet. + - `remainingBalanceOwner` is an `OutputOwners` which includes a `locktime`, `threshold`, and an array of `addresses`. It specifies the owner that will receive any withdrawn balance. Omitted if `subnetID` is not an L1 Subnet. + - `deactivationOwner` is an `OutputOwners` which includes a `locktime`, `threshold`, and an array of `addresses`. It specifies the owner that can withdraw the balance. Omitted if `subnetID` is not an L1 Subnet. + - `minNonce` is minimum nonce that must be included in a `SetL1ValidatorWeightTx` for the transaction to be valid. Omitted if `subnetID` is not an L1 Subnet. + - `balance` is current remaining balance that can be used to pay for the validators continuous fee. Omitted if `subnetID` is not an L1 Subnet. - `validationRewardOwner` is an `OutputOwners` output which includes `locktime`, `threshold` and array of `addresses`. Specifies the owner of the potential reward earned from staking. Omitted - if `subnetID` is not a PoS Subnet. + if `subnetID` is not the Primary Network. - `delegationRewardOwner` is an `OutputOwners` output which includes `locktime`, `threshold` and - array of `addresses`. Specifies the owner of the potential reward earned from delegations. - Omitted if `subnetID` is not a PoS Subnet. - - `potentialReward` is the potential reward earned from staking. Omitted if `subnetID` is not a - PoS Subnet. + array of `addresses`. Specifies the owner of the potential reward earned from delegations. Omitted if `subnetID` is not the Primary Network. + - `potentialReward` is the potential reward earned from staking. Omitted if `subnetID` is not the Primary Network. - `delegationFeeRate` is the percent fee this validator charges when others delegate stake to - them. Omitted if `subnetID` is not a PoS Subnet. + them. Omitted if `subnetID` is not the Primary Network. - `uptime` is the % of time the queried node has reported the peer as online and validating the - Subnet. Omitted if `subnetID` is not a PoS Subnet. (Deprecated: uptime is deprecated for Subnet Validators. It will be available only for Primary Network Validators.) - - `connected` is if the node is connected and tracks the Subnet. (Deprecated: connected is deprecated for Subnet Validators. It will be available only for Primary Network Validators.) + Subnet. Omitted if `subnetID` is not the Primary Network. + - `connected` is if the node is connected and tracks the Subnet. Omitted if `subnetID` is not the Primary Network. - `signer` is the node's BLS public key and proof of possession. Omitted if the validator doesn't - have a BLS public key. + have a BLS public key. Omitted if `subnetID` is not the Primary Network. - `delegatorCount` is the number of delegators on this validator. - Omitted if `subnetID` is not a PoS Subnet. + Omitted if `subnetID` is not the Primary Network. - `delegatorWeight` is total weight of delegators on this validator. - Omitted if `subnetID` is not a PoS Subnet. - - `delegators` is the list of delegators to this validator. - Omitted if `subnetID` is not a PoS Subnet. - Omitted unless `nodeIDs` specifies a single NodeID. + Omitted if `subnetID` is not the Primary Network. + - `delegators` is the list of delegators to this validator. Omitted if `subnetID` is not the Primary Network. Omitted unless `nodeIDs` specifies a single NodeID. - `txID` is the delegator transaction. - `startTime` is the Unix time when the delegator started. - `endTime` is the Unix time when the delegator stops. - - `stakeAmount` is the amount of nAVAX this delegator staked. + - `weight` is the amount of nAVAX this delegator staked. - `nodeID` is the validating node’s node ID. - `rewardOwner` is an `OutputOwners` output which includes `locktime`, `threshold` and array of `addresses`. - `potentialReward` is the potential reward earned from staking +Note: An L1 Subnet can include both initial legacy PoA validators (before L1 conversion) and L1 validators. The response will include both types of validators. + **Example Call:** ```sh @@ -722,7 +679,7 @@ curl -X POST --data '{ }' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P ``` -**Example Response:** +**Example Response (Primary Network):** ```json { @@ -733,7 +690,7 @@ curl -X POST --data '{ "txID": "2NNkpYTGfTFLSGXJcHtVv6drwVU2cczhmjK2uhvwDyxwsjzZMm", "startTime": "1600368632", "endTime": "1602960455", - "stakeAmount": "2000000000000", + "weight": "2000000000000", "nodeID": "NodeID-5mb46qkSBj81k9g9e4VFjGGSbaaSLFRzD", "validationRewardOwner": { "locktime": "0", @@ -756,7 +713,7 @@ curl -X POST --data '{ "txID": "Bbai8nzGVcyn2VmeYcbS74zfjJLjDacGNVuzuvAQkHn1uWfoV", "startTime": "1600368523", "endTime": "1602960342", - "stakeAmount": "25000000000", + "weight": "25000000000", "nodeID": "NodeID-5mb46qkSBj81k9g9e4VFjGGSbaaSLFRzD", "rewardOwner": { "locktime": "0", @@ -773,9 +730,45 @@ curl -X POST --data '{ } ``` +**Example Response (L1):** + +```json +{ + "jsonrpc": "2.0", + "result": { + "validators": [ + { + "validationID": "2wTscvX3JUsMbZHFRd9t8Ywz2q9j2BmETg8cTvgUHgawjbSvZX", + "nodeID": "NodeID-5mb46qkSBj81k9g9e4VFjGGSbaaSLFRzD", + "publicKey": "0x91951771ff32b1a985a4936592bce8512a986353c4c2eb5a0f12dbb76bda3a0a0c975e26413ff44c0ee9d8d689eff8ed", + "remainingBalanceOwner": { + "locktime": "0", + "threshold": "1", + "addresses": [ + "P-fuji1ywzvrftfqexh5g6qa9zyrytj6pqdfetza2hqln" + ] + }, + "deactivationOwner": { + "locktime": "0", + "threshold": "1", + "addresses": [ + "P-fuji1ywzvrftfqexh5g6qa9zyrytj6pqdfetza2hqln" + ] + }, + "startTime": "1734034648", + "weight": "20", + "minNonce": "0", + "balance": "8780477952" + } + ] + }, + "id": 1 +} +``` + ### `platform.getFeeConfig` -Returns the dynamic fees configuration of the P-chain. +Returns the dynamic fee configuration of the P-chain. **Signature:** @@ -812,16 +805,16 @@ curl -X POST --data '{ ```json { - "jsonrpc": "2.0", - "result": { - "weights": [1,1000,1000,4], - "maxCapacity": 1000000, - "maxPerSecond": 100000, - "targetPerSecond": 50000, - "minPrice": 1, - "excessConversionConstant": 2164043 - }, - "id": 1 + "jsonrpc": "2.0", + "result": { + "weights": [1, 1000, 1000, 4], + "maxCapacity": 1000000, + "maxPerSecond": 100000, + "targetPerSecond": 50000, + "minPrice": 1, + "excessConversionConstant": 2164043 + }, + "id": 1 } ``` @@ -855,14 +848,50 @@ curl -X POST --data '{ ```json { + "jsonrpc": "2.0", + "result": { + "capacity": 973044, + "excess": 26956, + "price": 1, + "timestamp": "2024-12-16T17:19:07Z" + }, + "id": 1 +} +``` + +### `platform.getHeight` + +Returns the height of the last accepted block. + +**Signature:** + +``` +platform.getHeight() -> +{ + height: int, +} +``` + +**Example Call:** + +```sh +curl -X POST --data '{ "jsonrpc": "2.0", - "result": { - "capacity":973044, - "excess":26956, - "price":1, - "timestamp":"2024-12-16T17:19:07Z" - }, + "method": "platform.getHeight", + "params": {}, "id": 1 +}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P +``` + +**Example Response:** + +```json +{ + "jsonrpc": "2.0", + "result": { + "height": "56" + }, + "id": 1 } ``` @@ -876,6 +905,7 @@ Returns a current L1 validator. platform.getL1Validator({ validationID: string, }) -> { + validationID: string, subnetID: string, nodeID: string, publicKey: string, @@ -897,6 +927,7 @@ platform.getL1Validator({ } ``` +- `validationID` is the ID for L1 subnet validator registration transaction. - `subnetID` is the L1 this validator is validating. - `nodeID` is the node ID of the validator. - `publicKey` is the compressed BLS public key of the validator. @@ -923,64 +954,29 @@ curl -X POST --data '{ **Example Response:** -```json -{ - "jsonrpc": "2.0", - "result": { - "subnetID": "2DeHa7Qb6sufPkmQcFWG2uCd4pBPv9WB6dkzroiMQhd1NSRtof", - "nodeID": "NodeID-7Xhw2mDxuDS44j42TCB6U5579esbSt3Lg", - "publicKey": "0x900c9b119b5c82d781d4b49be78c3fc7ae65f2b435b7ed9e3a8b9a03e475edff86d8a64827fec8db23a6f236afbf127d", - "remainingBalanceOwner": { - "locktime": "0", - "threshold": "0", - "addresses": [] - }, - "deactivationOwner": { - "locktime": "0", - "threshold": "0", - "addresses": [] - }, - "startTime": "1731445206", - "weight": "49463", - "minNonce": "0", - "balance": "1000000000", - "height": "3" - }, - "id": 1 -} -``` - -### `platform.getHeight` - -Returns the height of the last accepted block. - -**Signature:** - -``` -platform.getHeight() -> -{ - height: int, -} -``` - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc": "2.0", - "method": "platform.getHeight", - "params": {}, - "id": 1 -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P -``` - -**Example Response:** - ```json { "jsonrpc": "2.0", "result": { - "height": "56" + "subnetID": "2DeHa7Qb6sufPkmQcFWG2uCd4pBPv9WB6dkzroiMQhd1NSRtof", + "nodeID": "NodeID-7Xhw2mDxuDS44j42TCB6U5579esbSt3Lg", + "validationID": "9FAftNgNBrzHUMMApsSyV6RcFiL9UmCbvsCu28xdLV2mQ7CMo", + "publicKey": "0x900c9b119b5c82d781d4b49be78c3fc7ae65f2b435b7ed9e3a8b9a03e475edff86d8a64827fec8db23a6f236afbf127d", + "remainingBalanceOwner": { + "locktime": "0", + "threshold": "0", + "addresses": [] + }, + "deactivationOwner": { + "locktime": "0", + "threshold": "0", + "addresses": [] + }, + "startTime": "1731445206", + "weight": "49463", + "minNonce": "0", + "balance": "1000000000", + "height": "3" }, "id": 1 } @@ -1022,64 +1018,6 @@ curl -X POST --data '{ } ``` -### `platform.getMaxStakeAmount` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - -Returns the maximum amount of nAVAX staking to the named node during a particular time period. - -**Signature:** - -``` -platform.getMaxStakeAmount ( -{ - subnetID: string, - nodeID: string, - startTime: int, - endTime: int -}) -> { amount: uint64 } -``` - -- `subnetID` is a Buffer or cb58 string representing Subnet -- `nodeID` is a string representing ID of the node whose stake amount is required during the given - duration -- `startTime` is a big number denoting start time of the duration during which stake amount of the - node is required. -- `endTime` is a big number denoting end time of the duration during which stake amount of the node - is required. - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc": "2.0", - "method": "platform.getMaxStakeAmount", - "params": { - "subnetID":"11111111111111111111111111111111LpoYY", - "nodeID":"NodeID-7Xhw2mDxuDS44j42TCB6U5579esbSt3Lg", - "startTime": 1644240334, - "endTime": 1644240634 - }, - "id": 1 -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "result": { - "amount": "2000000000000000" - }, - "id": 1 -} -``` - ### `platform.getMinStake` Get the minimum amount of tokens required to validate the requested Subnet and the minimum amount of @@ -1123,108 +1061,6 @@ curl -X POST --data '{ } ``` -### `platform.getPendingValidators` - -List the validators in the pending validator set of the specified Subnet. Each validator is not -currently validating the Subnet but will in the future. - -**Signature:** - -``` -platform.getPendingValidators({ - subnetID: string, // optional - nodeIDs: string[], // optional -}) -> { - validators: []{ - txID: string, - startTime: string, - endTime: string, - stakeAmount: string, - nodeID: string, - delegationFee: string, - connected: bool, - signer: { - publicKey: string, - proofOfPosession: string - }, - weight: string, - }, - delegators: []{ - txID: string, - startTime: string, - endTime: string, - stakeAmount: string, - nodeID: string - } -} -``` - -- `subnetID` is the Subnet whose current validators are returned. If omitted, returns the current - validators of the Primary Network. -- `nodeIDs` is a list of the NodeIDs of pending validators to request. If omitted, all pending - validators are returned. If a specified NodeID is not in the set of pending validators, it will - not be included in the response. -- `validators`: - - `txID` is the validator transaction. - - `startTime` is the Unix time when the validator starts validating the Subnet. - - `endTime` is the Unix time when the validator stops validating the Subnet. - - `stakeAmount` is the amount of tokens this validator staked. Omitted if `subnetID` is not a PoS - Subnet. - - `nodeID` is the validator’s node ID. - - `connected` if the node is connected and tracks the Subnet. - - `signer` is the node's BLS public key and proof of possession. Omitted if the validator doesn't - have a BLS public key. - - `weight` is the validator’s weight when sampling validators. Omitted if `subnetID` is a PoS - Subnet. -- `delegators`: - - `txID` is the delegator transaction. - - `startTime` is the Unix time when the delegator starts. - - `endTime` is the Unix time when the delegator stops. - - `stakeAmount` is the amount of tokens this delegator staked. - - `nodeID` is the validating node’s node ID. - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc": "2.0", - "method": "platform.getPendingValidators", - "params": {}, - "id": 1 -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "result": { - "validators": [ - { - "txID": "2NNkpYTGfTFLSGXJcHtVv6drwVU2cczhmjK2uhvwDyxwsjzZMm", - "startTime": "1600368632", - "endTime": "1602960455", - "stakeAmount": "200000000000", - "nodeID": "NodeID-5mb46qkSBj81k9g9e4VFjGGSbaaSLFRzD", - "delegationFee": "10.0000", - "connected": false - } - ], - "delegators": [ - { - "txID": "Bbai8nzGVcyn2VmeYcbS74zfjJLjDacGNVuzuvAQkHn1uWfoV", - "startTime": "1600368523", - "endTime": "1602960342", - "stakeAmount": "20000000000", - "nodeID": "NodeID-7Xhw2mDxuDS44j42TCB6U5579esbSt3Lg" - } - ] - }, - "id": 1 -} -``` - ### `platform.getRewardUTXOs` @@ -1428,7 +1264,7 @@ platform.getSubnet({ - `subnetID` is the ID of the Subnet to get information about. If omitted, fails. - `threshold` signatures from addresses in `controlKeys` are needed to make changes to - a permissioned subnet. If the Subnet is a PoS Subnet, then `threshold` will be `0` and `controlKeys` + a permissioned subnet. If the Subnet is not a PoA Subnet, then `threshold` will be `0` and `controlKeys` will be empty. - changes can not be made into the subnet until `locktime` is in the past. - `subnetTransformationTxID` is the ID of the transaction that changed the subnet into an elastic one, if it exists. @@ -1454,7 +1290,10 @@ curl -X POST --data '{ "jsonrpc": "2.0", "result": { "isPermissioned": true, - "controlKeys": ["P-fuji1ztvstx6naeg6aarfd047fzppdt8v4gsah88e0c","P-fuji193kvt4grqewv6ce2x59wnhydr88xwdgfcedyr3"], + "controlKeys": [ + "P-fuji1ztvstx6naeg6aarfd047fzppdt8v4gsah88e0c", + "P-fuji193kvt4grqewv6ce2x59wnhydr88xwdgfcedyr3" + ], "threshold": "1", "locktime": "0", "subnetTransformationTxID": "11111111111111111111111111111111LpoYY", @@ -1495,7 +1334,7 @@ platform.getSubnets({ Subnets. - `id` is the Subnet’s ID. - `threshold` signatures from addresses in `controlKeys` are needed to add a validator to the - Subnet. If the Subnet is a PoS Subnet, then `threshold` will be `0` and `controlKeys` will be + Subnet. If the Subnet is not a PoA Subnet, then `threshold` will be `0` and `controlKeys` will be empty. See [here](https://github.com/nodes/validate/add-a-validator.md) for information on adding a validator to a @@ -1980,7 +1819,7 @@ platform.getValidatorsAt( ``` - `height` is the P-Chain height to get the validator set at, or the string literal "proposed" - to return the validator set at this node's ProposerVM height. + to return the validator set at this node's ProposerVM height. - `subnetID` is the Subnet ID to get the validator set of. If not given, gets validator set of the Primary Network. @@ -2015,34 +1854,33 @@ curl -X POST --data '{ } ``` -### `platform.issueTx` +### `platform.getValidatorFeeConfig` -Issue a transaction to the Platform Chain. +Returns the validator fee configuration of the P-Chain. **Signature:** ``` -platform.issueTx({ - tx: string, - encoding: string, // optional -}) -> { txID: string } +platform.getValidatorFeeConfig() -> { + capacity: uint64, + target: uint64, + minPrice: uint64, + excessConversionConstant: uint64 +} ``` -- `tx` is the byte representation of a transaction. -- `encoding` specifies the encoding format for the transaction bytes. Can only be `hex` when a value - is provided. -- `txID` is the transaction’s ID. +- `capacity` is the maximum number of L1 validators the chain is allowed to have at any given time +- `target` is the target number of L1 validators the chain should have to keep fees stable +- `minPrice` is the minimum price per L1 validator +- `excessConversionConstant` is used to convert excess L1 validators to a gas price **Example Call:** ```sh curl -X POST --data '{ "jsonrpc": "2.0", - "method": "platform.issueTx", - "params": { - "tx":"0x00000009de31b4d8b22991d51aa6aa1fc733f23a851a8c9400000000000186a0000000005f041280000000005f9ca900000030390000000000000001fceda8f90fcb5d30614b99d79fc4baa29307762668f16eb0259a57c2d3b78c875c86ec2045792d4df2d926c40f829196e0bb97ee697af71f5b0a966dabff749634c8b729855e937715b0e44303fd1014daedc752006011b730", - "encoding": "hex" - }, + "method": "platform.getValidatorFeeConfig", + "params": {}, "id": 1 }' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P ``` @@ -2053,46 +1891,82 @@ curl -X POST --data '{ { "jsonrpc": "2.0", "result": { - "txID": "G3BuH6ytQ2averrLxJJugjWZHTRubzCrUZEXoheG5JMqL5ccY" + "capacity": 20000, + "target": 10000, + "targetPerSecond": 50000, + "minPrice": 512, + "excessConversionConstant": 1246488515 }, "id": 1 } ``` -### `platform.listAddresses` +### `platform.getValidatorFeeState` - +Returns the current validator fee state of the P-Chain. -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). +**Signature:** - +``` +platform.getValidatorFeeState() -> { + excess: uint64, + price: uint64, + timestamp: string +} +``` - +**Example Call:** -Not recommended for use on Mainnet. See warning notice in [Keystore API](https://github.com/api-reference/keystore-api). +```sh +curl -X POST --data '{ + "jsonrpc": "2.0", + "method": "platform.getValidatorFeeState", + "params": {}, + "id": 1 +}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P +``` - +**Example Response:** + +```json +{ + "jsonrpc": "2.0", + "result": { + "excess": 26956, + "price": 512, + "timestamp": "2024-12-16T17:19:07Z" + }, + "id": 1 +} +``` -List addresses controlled by the given user. +### `platform.issueTx` + +Issue a transaction to the Platform Chain. **Signature:** ``` -platform.listAddresses({ - username: string, - password: string -}) -> { addresses: []string } +platform.issueTx({ + tx: string, + encoding: string, // optional +}) -> { txID: string } ``` +- `tx` is the byte representation of a transaction. +- `encoding` specifies the encoding format for the transaction bytes. Can only be `hex` when a value + is provided. +- `txID` is the transaction’s ID. + **Example Call:** ```sh curl -X POST --data '{ "jsonrpc": "2.0", - "method": "platform.listAddresses", + "method": "platform.issueTx", "params": { - "username":"myUsername", - "password":"myPassword" + "tx":"0x00000009de31b4d8b22991d51aa6aa1fc733f23a851a8c9400000000000186a0000000005f041280000000005f9ca900000030390000000000000001fceda8f90fcb5d30614b99d79fc4baa29307762668f16eb0259a57c2d3b78c875c86ec2045792d4df2d926c40f829196e0bb97ee697af71f5b0a966dabff749634c8b729855e937715b0e44303fd1014daedc752006011b730", + "encoding": "hex" }, "id": 1 }' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/P @@ -2104,7 +1978,7 @@ curl -X POST --data '{ { "jsonrpc": "2.0", "result": { - "addresses": ["P-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"] + "txID": "G3BuH6ytQ2averrLxJJugjWZHTRubzCrUZEXoheG5JMqL5ccY" }, "id": 1 } diff --git a/content/docs/api-reference/x-chain/api.mdx b/content/docs/api-reference/x-chain/api.mdx index 3c31967f781..ae6150f74af 100644 --- a/content/docs/api-reference/x-chain/api.mdx +++ b/content/docs/api-reference/x-chain/api.mdx @@ -1,13 +1,9 @@ --- title: X-Chain API -description: "This page is an overview of the X-Chain API associated with AvalancheGo." +description: This page is an overview of the X-Chain API associated with AvalancheGo. --- -} > -This page was generated by a plugin that directly references this [file](https://github.com/ava-labs/avalanchego/tree/master/vms/avm/service.md) in the AvalancheGo GitHub repository. - - -The [X-Chain](/docs/quick-start/primary-network#x-chain), +The [X-Chain](https://github.com/learn/avalanche/avalanche-platform.md#x-chain), Avalanche's native platform for creating and trading assets, is an instance of the Avalanche Virtual Machine (AVM). This API allows clients to create and trade assets on the X-Chain and other instances of the AVM. @@ -15,7 +11,7 @@ of the AVM. ## Format This API uses the `json 2.0` RPC format. For more information on making JSON RPC calls, see -[here](/docs/api-reference/standards/guides/issuing-api-calls). +[here](https://github.com/reference/standards/guides/issuing-api-calls.md). ## Endpoints @@ -28,12 +24,12 @@ blockchain running the AVM. ### `avm.buildGenesis` -Given a JSON representation of this Virtual Machine's genesis state, create the byte representation +Given a JSON representation of this Virtual Machine’s genesis state, create the byte representation of that state. #### **Endpoint** -This call is made to the AVM's static API endpoint: +This call is made to the AVM’s static API endpoint: `/ext/vm/avm` @@ -184,476 +180,13 @@ curl -X POST --data '{ } ``` -### `avm.createAddress` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Create a new address controlled by the given user. - -**Signature:** - -```sh -avm.createAddress({ - username: string, - password: string -}) -> {address: string} -``` - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc": "2.0", - "method": "avm.createAddress", - "params": { - "username": "myUsername", - "password": "myPassword" - }, - "id": 1 -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "result": { - "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5" - }, - "id": 1 -} -``` - -### `avm.createFixedCapAsset` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Create a new fixed-cap, fungible asset. A quantity of it is created at initialization and then no -more is ever created. The asset can be sent with `avm.send`. - -**Signature:** - -```sh -avm.createFixedCapAsset({ - name: string, - symbol: string, - denomination: int, //optional - initialHolders: []{ - address: string, - amount: int - }, - from: []string, //optional - changeAddr: string, //optional - username: string, - password: string -}) -> -{ - assetID: string, - changeAddr: string -} -``` - -- `name` is a human-readable name for the asset. Not necessarily unique. -- `symbol` is a shorthand symbol for the asset. Between 0 and 4 characters. Not necessarily unique. - May be omitted. -- `denomination` determines how balances of this asset are displayed by user interfaces. If - `denomination` is 0, 100 units of this asset are displayed as 100. If `denomination` is 1, 100 - units of this asset are displayed as 10.0. If `denomination` is 2, 100 units of this asset are - displayed as 1.00, etc. Defaults to 0. -- `from` are the addresses that you want to use for this operation. If omitted, uses any of your - addresses as needed. -- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the - addresses controlled by the user. -- `username` and `password` denote the user paying the transaction fee. -- Each element in `initialHolders` specifies that `address` holds `amount` units of the asset at - genesis. -- `assetID` is the ID of the new asset. - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" : 1, - "method" :"avm.createFixedCapAsset", - "params" :{ - "name": "myFixedCapAsset", - "symbol":"MFCA", - "initialHolders": [ - { - "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", - "amount": 10000 - }, - { - "address":"X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", - "amount":50000 - } - ], - "from":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"], - "changeAddr":"X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8", - "username":"myUsername", - "password":"myPassword" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "assetID": "ZiKfqRXCZgHLgZ4rxGU9Qbycdzuq5DRY4tdSNS9ku8kcNxNLD", - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8" - } -} -``` - -### `avm.createNFTAsset` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Create a new non-fungible asset. No units of the asset exist at initialization. Minters can mint -units of this asset using `avm.mintNFT`. - -**Signature:** - -```sh -avm.createNFTAsset({ - name: string, - symbol: string, - minterSets: []{ - minters: []string, - threshold: int - }, - from: []string, //optional - changeAddr: string, //optional - username: string, - password: string -}) -> - { - assetID: string, - changeAddr: string, -} -``` - -- `name` is a human-readable name for the asset. Not necessarily unique. -- `symbol` is a shorthand symbol for the asset. Between 0 and 4 characters. Not necessarily unique. - May be omitted. -- `minterSets` is a list where each element specifies that `threshold` of the addresses in `minters` - may together mint more of the asset by signing a minting transaction. -- `from` are the addresses that you want to use for this operation. If omitted, uses any of your - addresses as needed. -- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the - addresses controlled by the user. -- `username` pays the transaction fee. -- `assetID` is the ID of the new asset. -- `changeAddr` in the result is the address where any change was sent. - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" : 1, - "method" :"avm.createNFTAsset", - "params" :{ - "name":"Coincert", - "symbol":"TIXX", - "minterSets":[ - { - "minters":[ - "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8" - ], - "threshold": 1 - } - ], - "from": ["X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8"], - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8", - "username":"myUsername", - "password":"myPassword" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "result": { - "assetID": "2KGdt2HpFKpTH5CtGZjYt5XPWs6Pv9DLoRBhiFfntbezdRvZWP", - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8" - }, - "id": 1 -} -``` - -### `avm.createVariableCapAsset` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Create a new variable-cap, fungible asset. No units of the asset exist at initialization. Minters -can mint units of this asset using `avm.mint`. - -**Signature:** - -```sh -avm.createVariableCapAsset({ - name: string, - symbol: string, - denomination: int, //optional - minterSets: []{ - minters: []string, - threshold: int - }, - from: []string, //optional - changeAddr: string, //optional - username: string, - password: string -}) -> -{ - assetID: string, - changeAddr: string, -} -``` - -- `name` is a human-readable name for the asset. Not necessarily unique. -- `symbol` is a shorthand symbol for the asset. Between 0 and 4 characters. Not necessarily unique. - May be omitted. -- `denomination` determines how balances of this asset are displayed by user interfaces. If - denomination is 0, 100 units of this asset are displayed as 100. If denomination is 1, 100 units - of this asset are displayed as 10.0. If denomination is 2, 100 units of this asset are displays as - .100, etc. -- `minterSets` is a list where each element specifies that `threshold` of the addresses in `minters` - may together mint more of the asset by signing a minting transaction. -- `from` are the addresses that you want to use for this operation. If omitted, uses any of your - addresses as needed. -- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the - addresses controlled by the user. -- `username` pays the transaction fee. -- `assetID` is the ID of the new asset. -- `changeAddr` in the result is the address where any change was sent. - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" : 1, - "method" :"avm.createVariableCapAsset", - "params" :{ - "name":"myVariableCapAsset", - "symbol":"MFCA", - "minterSets":[ - { - "minters":[ - "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5" - ], - "threshold": 1 - }, - { - "minters": [ - "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", - "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", - "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5" - ], - "threshold": 2 - } - ], - "from":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"], - "changeAddr":"X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8", - "username":"myUsername", - "password":"myPassword" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "assetID": "2QbZFE7J4MAny9iXHUwq8Pz8SpFhWk3maCw4SkinVPv6wPmAbK", - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8" - } -} -``` - -### `avm.export` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Send an asset from the X-Chain to the P-Chain or C-Chain. - -**Signature:** - -```sh -avm.export({ - to: string, - amount: int, - assetID: string, - from: []string, //optional - changeAddr: string, //optional - username: string, - password: string, -}) -> -{ - txID: string, - changeAddr: string, -} -``` - -- `to` is the P-Chain or C-Chain address the asset is sent to. -- `amount` is the amount of the asset to send. -- `assetID` is the asset id of the asset which is sent. Use `AVAX` for AVAX exports. -- `from` are the addresses that you want to use for this operation. If omitted, uses any of your - addresses as needed. -- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the - addresses controlled by the user. -- The asset is sent from addresses controlled by `username` -- `password` is `username`‘s password. -- `txID` is this transaction's ID. -- `changeAddr` in the result is the address where any change was sent. - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" :1, - "method" :"avm.export", - "params" :{ - "to":"C-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", - "amount": 10, - "assetID": "AVAX", - "from":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"], - "changeAddr":"X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8", - "username":"myUsername", - "password":"myPassword" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "result": { - "txID": "2Eu16yNaepP57XrrJgjKGpiEDandpiGWW8xbUm6wcTYny3fejj", - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8" - }, - "id": 1 -} -``` - -### `avm.exportKey` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Get the private key that controls a given address. The returned private key can be added to a user -with [`avm.importKey`](/docs/api-reference/x-chain/api#avmimportkey). - -**Signature:** - -```sh -avm.exportKey({ - username: string, - password: string, - address: string -}) -> {privateKey: string} -``` - -- `username` must control `address`. -- `privateKey` is the string representation of the private key that controls `address`. - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" :1, - "method" :"avm.exportKey", - "params" :{ - "username":"myUsername", - "password":"myPassword", - "address":"X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "privateKey": "PrivateKey-2w4XiXxPfQK4TypYqnohRL8DRNTz9cGiGmwQ1zmgEqD9c9KWLq" - } -} -``` - ### `avm.getAddressTxs` - +:::caution Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - +::: Returns all transactions that change the balance of the given address. A transaction is said to change an address's balance if either is true: @@ -661,9 +194,9 @@ change an address's balance if either is true: - A UTXO that the transaction consumes was at least partially owned by the address. - A UTXO that the transaction produces is at least partially owned by the address. -} > +:::tip Note: Indexing (`index-transactions`) must be enabled in the X-chain config. - +::: **Signature:** @@ -721,11 +254,11 @@ curl -X POST --data '{ ### `avm.getAllBalances` - +:::caution Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - +::: Get the balances of all assets controlled by a given address. @@ -790,14 +323,14 @@ avm.getAssetDescription({assetID: string}) -> { ``` - `assetID` is the id of the asset for which the information is requested. -- `name` is the asset's human-readable, not necessarily unique name. -- `symbol` is the asset's symbol. +- `name` is the asset’s human-readable, not necessarily unique name. +- `symbol` is the asset’s symbol. - `denomination` determines how balances of this asset are displayed by user interfaces. If denomination is 0, 100 units of this asset are displayed as 100. If denomination is 1, 100 units of this asset are displayed as 10.0. If denomination is 2, 100 units of this asset are displays as .100, etc. - +:::note The AssetID for AVAX differs depending on the network you are on. @@ -808,7 +341,7 @@ Testnet: U8iRqJoiJm8xZHAacmvYyZVwqQx6uDNtQeP3CQ6fcgQk3JqnK For finding the `assetID` of other assets, this [info] might be useful. Also, `avm.getUTXOs` returns the `assetID` in its output. - +::: **Example Call:** @@ -840,11 +373,11 @@ curl -X POST --data '{ ### `avm.getBalance` - +:::caution Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - +::: Get the balance of an asset controlled by a given address. @@ -980,10 +513,10 @@ avm.getBlockByHeight({ ```sh curl -X POST --data '{ "jsonrpc": "2.0", - "method": "avm.getBlockByHeight”, + "method": "avm.getBlockByHeight", "params": { - “height”: “275686313486”, - "encoding": “hex” + "height": "275686313486", + "encoding": "hex" }, "id": 1 }' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X @@ -1168,18 +701,59 @@ Most outputs use the secp256k1 FX, look like this: The above output can be consumed after Unix time `locktime` by a transaction that has signatures from `threshold` of the addresses in `addresses`. -### `avm.getTxStatus` - - -Deprecated as of **v1.10.0**. - +### `avm.getTxFee` -Get the status of a transaction sent to the network. +Get the fees of the network. -**Signature:** +**Signature**: -```sh -avm.getTxStatus({txID: string}) -> {status: string} +``` +avm.getTxFee() -> +{ + txFee: uint64, + createAssetTxFee: uint64, +} +``` + +- `txFee` is the default fee for making transactions. +- `createAssetTxFee` is the fee for creating a new asset. + +All fees are denominated in nAVAX. + +**Example Call**: + +```sh +curl -X POST --data '{ + "jsonrpc":"2.0", + "id" : 1, + "method" :"avm.getTxFee", +}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X +``` + +**Example Response**: + +```json +{ + "jsonrpc": "2.0", + "result": { + "txFee": "1000000", + "createAssetTxFee": "10000000" + } +} +``` + +### `avm.getTxStatus` + +:::caution +Deprecated as of **v1.10.0**. +::: + +Get the status of a transaction sent to the network. + +**Signature:** + +```sh +avm.getTxStatus({txID: string}) -> {status: string} ``` `status` is one of: @@ -1187,7 +761,7 @@ avm.getTxStatus({txID: string}) -> {status: string} - `Accepted`: The transaction is (or will be) accepted by every node - `Processing`: The transaction is being voted on by this node - `Rejected`: The transaction will never be accepted by any node in the network -- `Unknown`: The transaction hasn't been seen by this node +- `Unknown`: The transaction hasn’t been seen by this node **Example Call:** @@ -1340,7 +914,7 @@ This gives response: } ``` -Since `numFetched` is less than `limit`, we know that we are done fetching UTXOs and don't need to +Since `numFetched` is less than `limit`, we know that we are done fetching UTXOs and don’t need to call this method again. Suppose we want to fetch the UTXOs exported from the P Chain to the X Chain in order to build an @@ -1381,121 +955,6 @@ This gives response: } ``` -### `avm.import` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Finalize a transfer of an asset from the P-Chain or C-Chain to the X-Chain. - -**Signature:** - -```sh -avm.import({ - to: string, - sourceChain: string, - username: string, - password: string, -}) -> {txID: string} -``` - -- `to` is the address the AVAX is sent to. This must be the same as the `to` argument in the - corresponding call to the P-Chain's `exportAVAX` or C-Chain's `export`. -- `sourceChain` is the ID or alias of the chain the AVAX is being imported from. To import funds - from the C-Chain, use `"C"`. -- `username` is the user that controls `to`. -- `txID` is the ID of the newly created atomic transaction. - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" :1, - "method" :"avm.import", - "params" :{ - "to":"X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", - "sourceChain":"C", - "username":"myUsername", - "password":"myPassword" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "result": { - "txID": "2gXpf4jFoMAWQ3rxBfavgFfSdLkL2eFUYprKsUQuEdB5H6Jo1H" - }, - "id": 1 -} -``` - - -### `avm.importKey` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Give a user control over an address by providing the private key that controls the address. - -**Signature:** - -```sh -avm.importKey({ - username: string, - password: string, - privateKey: string -}) -> {address: string} -``` - -- Add `privateKey` to `username`‘s set of private keys. `address` is the address `username` now - controls with the private key. - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" :1, - "method" :"avm.importKey", - "params" :{ - "username":"myUsername", - "password":"myPassword", - "privateKey":"PrivateKey-2w4XiXxPfQK4TypYqnohRL8DRNTz9cGiGmwQ1zmgEqD9c9KWLq" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "address": "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5" - } -} -``` - ### `avm.issueTx` Send a signed transaction to the network. `encoding` specifies the format of the signed transaction. @@ -1538,438 +997,6 @@ curl -X POST --data '{ } ``` -### `avm.listAddresses` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -List addresses controlled by the given user. - -**Signature:** - -```sh -avm.listAddresses({ - username: string, - password: string -}) -> {addresses: []string} -``` - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc": "2.0", - "method": "avm.listAddresses", - "params": { - "username":"myUsername", - "password":"myPassword" - }, - "id": 1 -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "result": { - "addresses": ["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"] - }, - "id": 1 -} -``` - -### `avm.mint` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Mint units of a variable-cap asset created with -[`avm.createVariableCapAsset`](/docs/api-reference/x-chain/api#avmcreatevariablecapasset). - -**Signature:** - -```sh -avm.mint({ - amount: int, - assetID: string, - to: string, - from: []string, //optional - changeAddr: string, //optional - username: string, - password: string -}) -> -{ - txID: string, - changeAddr: string, -} -``` - -- `amount` units of `assetID` will be created and controlled by address `to`. -- `from` are the addresses that you want to use for this operation. If omitted, uses any of your - addresses as needed. -- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the - addresses controlled by the user. -- `username` is the user that pays the transaction fee. `username` must hold keys giving it - permission to mint more of this asset. That is, it must control at least _threshold_ keys for one - of the minter sets. -- `txID` is this transaction's ID. -- `changeAddr` in the result is the address where any change was sent. - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" : 1, - "method" :"avm.mint", - "params" :{ - "amount":10000000, - "assetID":"i1EqsthjiFTxunrj8WD2xFSrQ5p2siEKQacmCCB5qBFVqfSL2", - "to":"X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", - "from":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"], - "changeAddr":"X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8", - "username":"myUsername", - "password":"myPassword" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "txID": "2oGdPdfw2qcNUHeqjw8sU2hPVrFyNUTgn6A8HenDra7oLCDtja", - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8" - } -} -``` - -### `avm.mintNFT` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Mint non-fungible tokens which were created with -[`avm.createNFTAsset`](/docs/api-reference/x-chain/api#avmcreatenftasset). - -**Signature:** - -```sh -avm.mintNFT({ - assetID: string, - payload: string, - to: string, - encoding: string, //optional - from: []string, //optional - changeAddr: string, //optional - username: string, - password: string -}) -> -{ - txID: string, - changeAddr: string, -} -``` - -- `assetID` is the assetID of the newly created NFT asset. -- `payload` is an arbitrary payload of up to 1024 bytes. Its encoding format is specified by the - `encoding` argument. -- `from` are the addresses that you want to use for this operation. If omitted, uses any of your - addresses as needed. -- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the - addresses controlled by the user. -- `username` is the user that pays the transaction fee. `username` must hold keys giving it - permission to mint more of this asset. That is, it must control at least _threshold_ keys for one - of the minter sets. -- `txID` is this transaction's ID. -- `changeAddr` in the result is the address where any change was sent. -- `encoding` is the encoding format to use for the payload argument. Can only be `hex` when a value - is provided. - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" : 1, - "method" :"avm.mintNFT", - "params" :{ - "assetID":"2KGdt2HpFKpTH5CtGZjYt5XPWs6Pv9DLoRBhiFfntbezdRvZWP", - "payload":"0x415641204c61627338259aed", - "to":"X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", - "from":["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"], - "changeAddr":"X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8", - "username":"myUsername", - "password":"myPassword" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "txID": "2oGdPdfw2qcNUHeqjw8sU2hPVrFyNUTgn6A8HenDra7oLCDtja", - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8" - } -} -``` - -### `avm.send` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Send a quantity of an asset to an address. - -**Signature:** - -```sh -avm.send({ - amount: int, - assetID: string, - to: string, - memo: string, //optional - from: []string, //optional - changeAddr: string, //optional - username: string, - password: string -}) -> {txID: string, changeAddr: string} -``` - -- Sends `amount` units of asset with ID `assetID` to address `to`. `amount` is denominated in the - smallest increment of the asset. For AVAX this is 1 nAVAX (one billionth of 1 AVAX.) -- `to` is the X-Chain address the asset is sent to. -- `from` are the addresses that you want to use for this operation. If omitted, uses any of your - addresses as needed. -- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the - addresses controlled by the user. -- You can attach a `memo`, whose length can be up to 256 bytes. -- The asset is sent from addresses controlled by user `username`. (Of course, that user will need to - hold at least the balance of the asset being sent.) - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" :1, - "method" :"avm.send", - "params" :{ - "assetID" : "AVAX", - "amount" : 10000, - "to" : "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", - "from" : ["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"], - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8", - "memo" : "hi, mom!", - "username" : "userThatControlsAtLeast10000OfThisAsset", - "password" : "myPassword" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "txID": "2iXSVLPNVdnFqn65rRvLrsu8WneTFqBJRMqkBJx5vZTwAQb8c1", - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8" - } -} -``` - -### `avm.sendMultiple` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Sends multiple transfers of `amount` of `assetID`, to a specified address from a list of owned -addresses. - -**Signature:** - -```sh -avm.sendMultiple({ - outputs: []{ - assetID: string, - amount: int, - to: string - }, - from: []string, //optional - changeAddr: string, //optional - memo: string, //optional - username: string, - password: string -}) -> {txID: string, changeAddr: string} -``` - -- `outputs` is an array of object literals which each contain an `assetID`, `amount` and `to`. -- `memo` is an optional message, whose length can be up to 256 bytes. -- `from` are the addresses that you want to use for this operation. If omitted, uses any of your - addresses as needed. -- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the - addresses controlled by the user. -- The asset is sent from addresses controlled by user `username`. (Of course, that user will need to - hold at least the balance of the asset being sent.) - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" :1, - "method" :"avm.sendMultiple", - "params" :{ - "outputs": [ - { - "assetID" : "AVAX", - "to" : "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", - "amount" : 1000000000 - }, - { - "assetID" : "26aqSTpZuWDAVtRmo44fjCx4zW6PDEx3zy9Qtp2ts1MuMFn9FB", - "to" : "X-avax18knvhxx8uhc0mwlgrfyzjcm2wrd6e60w37xrjq", - "amount" : 10 - } - ], - "memo" : "hi, mom!", - "from" : ["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"], - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8", - "username" : "username", - "password" : "myPassword" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "txID": "2iXSVLPNVdnFqn65rRvLrsu8WneTFqBJRMqkBJx5vZTwAQb8c1", - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8" - } -} -``` - -### `avm.sendNFT` - - - -Deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Send a non-fungible token. - -**Signature:** - -```sh -avm.sendNFT({ - assetID: string, - groupID: number, - to: string, - from: []string, //optional - changeAddr: string, //optional - username: string, - password: string -}) -> {txID: string} -``` - -- `assetID` is the asset ID of the NFT being sent. -- `groupID` is the NFT group from which to send the NFT. NFT creation allows multiple groups under - each NFT ID. You can issue multiple NFTs to each group. -- `to` is the X-Chain address the NFT is sent to. -- `from` are the addresses that you want to use for this operation. If omitted, uses any of your - addresses as needed. `changeAddr` is the address any change will be sent to. If omitted, change is - sent to one of the addresses controlled by the user. -- The asset is sent from addresses controlled by user `username`. (Of course, that user will need to - hold at least the balance of the NFT being sent.) - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" :1, - "method" :"avm.sendNFT", - "params" :{ - "assetID" : "2KGdt2HpFKpTH5CtGZjYt5XPWs6Pv9DLoRBhiFfntbezdRvZWP", - "groupID" : 0, - "to" : "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", - "from" : ["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"], - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8", - "username" : "myUsername", - "password" : "myPassword" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "result": { - "txID": "DoR2UtG1Trd3Q8gWXVevNxD666Q3DPqSFmBSMPQ9dWTV8Qtuy", - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8" - }, - "id": 1 -} -``` - ### `wallet.issueTx` Send a signed transaction to the network and assume the TX will be accepted. `encoding` specifies @@ -1979,11 +1006,11 @@ This call is made to the wallet API endpoint: `/ext/bc/X/wallet` - +:::caution Endpoint deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - +::: **Signature:** @@ -2021,168 +1048,3 @@ curl -X POST --data '{ } } ``` - -### `wallet.send` - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Send a quantity of an asset to an address and assume the TX will be accepted so that future calls -can use the modified UTXO set. - -This call is made to the wallet API endpoint: - -`/ext/bc/X/wallet` - - - -Endpoint deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - -**Signature:** - -```sh -wallet.send({ - amount: int, - assetID: string, - to: string, - memo: string, //optional - from: []string, //optional - changeAddr: string, //optional - username: string, - password: string -}) -> {txID: string, changeAddr: string} -``` - -- Sends `amount` units of asset with ID `assetID` to address `to`. `amount` is denominated in the - smallest increment of the asset. For AVAX this is 1 nAVAX (one billionth of 1 AVAX.) -- `to` is the X-Chain address the asset is sent to. -- `from` are the addresses that you want to use for this operation. If omitted, uses any of your - addresses as needed. -- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the - addresses controlled by the user. -- You can attach a `memo`, whose length can be up to 256 bytes. -- The asset is sent from addresses controlled by user `username`. (Of course, that user will need to - hold at least the balance of the asset being sent.) - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" :1, - "method" :"wallet.send", - "params" :{ - "assetID" : "AVAX", - "amount" : 10000, - "to" : "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", - "memo" : "hi, mom!", - "from" : ["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"], - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8", - "username" : "userThatControlsAtLeast10000OfThisAsset", - "password" : "myPassword" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X/wallet -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "txID": "2iXSVLPNVdnFqn65rRvLrsu8WneTFqBJRMqkBJx5vZTwAQb8c1", - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8" - } -} -``` - -### `wallet.sendMultiple` - - -Not recommended for use on Mainnet. See warning notice in [Keystore API](/docs/api-reference/keystore-api). - - -Send multiple transfers of `amount` of `assetID`, to a specified address from a list of owned of -addresses and assume the TX will be accepted so that future calls can use the modified UTXO set. - -This call is made to the wallet API endpoint: - -`/ext/bc/X/wallet` - - - -Endpoint deprecated as of [**v1.9.12**](https://github.com/ava-labs/avalanchego/releases/tag/v1.9.12). - - - -**Signature:** - -```sh -wallet.sendMultiple({ - outputs: []{ - assetID: string, - amount: int, - to: string - }, - from: []string, //optional - changeAddr: string, //optional - memo: string, //optional - username: string, - password: string -}) -> {txID: string, changeAddr: string} -``` - -- `outputs` is an array of object literals which each contain an `assetID`, `amount` and `to`. -- `from` are the addresses that you want to use for this operation. If omitted, uses any of your - addresses as needed. -- `changeAddr` is the address any change will be sent to. If omitted, change is sent to one of the - addresses controlled by the user. -- You can attach a `memo`, whose length can be up to 256 bytes. -- The asset is sent from addresses controlled by user `username`. (Of course, that user will need to - hold at least the balance of the asset being sent.) - -**Example Call:** - -```sh -curl -X POST --data '{ - "jsonrpc":"2.0", - "id" :1, - "method" :"wallet.sendMultiple", - "params" :{ - "outputs": [ - { - "assetID" : "AVAX", - "to" : "X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5", - "amount" : 1000000000 - }, - { - "assetID" : "26aqSTpZuWDAVtRmo44fjCx4zW6PDEx3zy9Qtp2ts1MuMFn9FB", - "to" : "X-avax18knvhxx8uhc0mwlgrfyzjcm2wrd6e60w37xrjq", - "amount" : 10 - } - ], - "memo" : "hi, mom!", - "from" : ["X-avax18jma8ppw3nhx5r4ap8clazz0dps7rv5ukulre5"], - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8", - "username" : "username", - "password" : "myPassword" - } -}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/bc/X/wallet -``` - -**Example Response:** - -```json -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "txID": "2iXSVLPNVdnFqn65rRvLrsu8WneTFqBJRMqkBJx5vZTwAQb8c1", - "changeAddr": "X-avax1turszjwn05lflpewurw96rfrd3h6x8flgs5uf8" - } -} -``` \ No newline at end of file diff --git a/content/docs/cross-chain/avalanche-warp-messaging/deep-dive.mdx b/content/docs/cross-chain/avalanche-warp-messaging/deep-dive.mdx index 6085f09d46a..80ff23c88c4 100644 --- a/content/docs/cross-chain/avalanche-warp-messaging/deep-dive.mdx +++ b/content/docs/cross-chain/avalanche-warp-messaging/deep-dive.mdx @@ -4,11 +4,11 @@ description: Learn about Avalanche Warp Messaging, a cross-Avalanche L1 communic --- -Avalanche Warp Messaging (AWM) provides a primitive for cross-subnet communication on the Avalanche Network. +Avalanche Interchain Messaging (ICM) provides a primitive for cross-chain communication on the Avalanche Network. -The Avalanche P-Chain provides an index of every Subnet's validator set on the Avalanche Network, including the BLS public key of each validator (as of the [Banff Upgrade](https://github.com/ava-labs/avalanchego/releases/v1.9.0)). AWM utilizes the weighted validator sets stored on the P-Chain to build a cross-subnet communication protocol between any two Subnets on the Avalanche Network. +The Avalanche P-Chain provides an index of every network's validator set on the Avalanche Network, including the BLS public key of each validator (as of the [Banff Upgrade](https://github.com/ava-labs/avalanchego/releases/v1.9.0)). ICM utilizes the weighted validator sets stored on the P-Chain to build a cross-chain communication protocol between any two networks on Avalanche. -Any Virtual Machine (VM) on Avalanche can integrate Avalanche Warp Messaging to send and receive messages across Avalanche Subnets. +Any Virtual Machine (VM) on Avalanche can integrate Avalanche Interchain Messaging to send and receive messages cross-chain. ## Background @@ -20,15 +20,16 @@ This README assumes familiarity with: ## BLS Multi-Signatures with Public-Key Aggregation -Avalanche Warp Messaging utilizes BLS multi-signatures with public key aggregation in order to verify messages signed by another Subnet. When a validator joins a Subnet, the P-Chain records the validator's BLS public key and NodeID, as well as a proof of possession of the validator's BLS private key to defend against [rogue public-key attacks](https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html#mjx-eqn-eqaggsame). +Avalanche Interchain Messaging utilizes BLS multi-signatures with public key aggregation in order to verify messages signed by another network. When a validator joins a network, the P-Chain records the validator's BLS public key and NodeID, as well as a proof of possession of the validator's BLS private key to defend against [rogue public-key attacks](https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html#mjx-eqn-eqaggsame). -AWM utilizes the validator set's weights and public keys to verify that an aggregate signature has sufficient weight signing the message from the source Subnet. +ICM utilizes the validator set's weights and public keys to verify that an aggregate signature has sufficient weight signing the message from the source network. BLS provides a way to aggregate signatures off chain into a single signature that can be efficiently verified on chain. -## AWM Serialization +## ICM Serialization Unsigned Message: + ``` +-----------------+----------+--------------------------+ | network_id : uint32 | 4 bytes | @@ -45,8 +46,8 @@ Unsigned Message: - `sourceChainID` is the hash of the transaction that created the blockchain on the Avalanche P-Chain. It serves as the unique identifier for the blockchain across the Avalanche Network so that each blockchain can only sign a message with its own id. - `payload` provides an arbitrary byte array containing the contents of the message. VMs define their own message types to include in the `payload` - BitSetSignature: + ``` +-----------+----------+---------------------------+ | type_id : uint32 | 4 bytes | @@ -63,11 +64,12 @@ BitSetSignature: - `signers` encodes a bitset of which validators' signatures are included (a bitset is a byte array where each bit indicates membership of the element at that index in the set) - `signature` is an aggregated BLS Multi-Signature of the Unsigned Message -BitSetSignatures are verified within the context of a specific P-Chain height. At any given P-Chain height, the PlatformVM serves a canonically ordered validator set for the source subnet (validator set is ordered lexicographically by the BLS public key's byte representation). The `signers` bitset encodes which validator signatures were included. A value of `1` at index `i` in `signers` bitset indicates that a corresponding signature from the same validator at index `i` in the canonical validator set was included in the aggregate signature. +BitSetSignatures are verified within the context of a specific P-Chain height. At any given P-Chain height, the PlatformVM serves a canonically ordered validator set for the source network (validator set is ordered lexicographically by the BLS public key's byte representation). The `signers` bitset encodes which validator signatures were included. A value of `1` at index `i` in `signers` bitset indicates that a corresponding signature from the same validator at index `i` in the canonical validator set was included in the aggregate signature. -The bitset tells the verifier which BLS public keys should be aggregated to verify the warp message. +The bitset tells the verifier which BLS public keys should be aggregated to verify the interchain message. Signed Message: + ``` +------------------+------------------+-------------------------------------------------+ | unsigned_message : UnsignedMessage | size(unsigned_message) | @@ -78,9 +80,9 @@ Signed Message: +-------------------------------------------------+ ``` -## Sending an Avalanche Warp Message +## Sending an Avalanche Interchain Message -A blockchain on Avalanche sends an Avalanche Warp Message by coming to agreement on the message that every validator should be willing to sign. As an example, the VM of a blockchain may define that once a block is accepted, the VM should be willing to sign a message including the block hash in the payload to attest to any other Subnet that the block was accepted. The contents of the payload, how to aggregate the signature (VM-to-VM communication, off-chain relayer, etc.), is left to the VM. +A blockchain on Avalanche sends an Avalanche Interchain Message by coming to agreement on the message that every validator should be willing to sign. As an example, the VM of a blockchain may define that once a block is accepted, the VM should be willing to sign a message including the block hash in the payload to attest to any other network that the block was accepted. The contents of the payload, how to aggregate the signature (VM-to-VM communication, off-chain relayer, etc.), is left to the VM. Once the validator set of a blockchain is willing to sign an arbitrary message `M`, an aggregator performs the following process: @@ -90,13 +92,13 @@ Once the validator set of a blockchain is willing to sign an arbitrary message ` 4. Encode the selection of the `N` validators included in the signature in a bitset 5. Construct the signed message from the aggregate signature, bitset, and original unsigned message -## Verifying / Receiving an Avalanche Warp Message +## Verifying / Receiving an Avalanche Interchain Message -Avalanche Warp Messages are verified within the context of a specific P-Chain height included in the [ProposerVM](https://github.com/ava-labs/avalanchego/tree/master/vms/proposervm/README.md)'s header. The P-Chain height is provided as context to the underlying VM when verifying the underlying VM's blocks (implemented by the optional interface [WithVerifyContext](https://github.com/ava-labs/avalanchego/tree/master/snow/engine/snowman/block/block_context_vm.go)). +Avalanche Interchain Messages are verified within the context of a specific P-Chain height included in the [ProposerVM](https://github.com/ava-labs/avalanchego/tree/master/vms/proposervm/README.md)'s header. The P-Chain height is provided as context to the underlying VM when verifying the underlying VM's blocks (implemented by the optional interface [WithVerifyContext](https://github.com/ava-labs/avalanchego/tree/master/snow/engine/snowman/block/block_context_vm.go)). To verify the message, the underlying VM utilizes this `warp` package to perform the following steps: -1. Lookup the canonical validator set of the Subnet sending the message at the P-Chain height +1. Lookup the canonical validator set of the network sending the message at the P-Chain height 2. Filter the canonical validator set to only the validators claimed by the signature 3. Verify the weight of the included validators meets the required threshold defined by the receiving VM 4. Aggregate the public keys of the claimed validators into a single aggregate public key @@ -106,20 +108,19 @@ Once a message is verified, it is left to the VM to define the semantics of deli ## Design Considerations -### Processing Historical Avalanche Warp Messages +### Processing Historical Avalanche Interchain Messages -Verifying an Avalanche Warp Message requires a lookup of validator sets at a specific P-Chain height. The P-Chain serves lookups maintaining validator set diffs that can be applied in-order to reconstruct the validator set of any Subnet at any height. +Verifying an Avalanche Interchain Message requires a lookup of validator sets at a specific P-Chain height. The P-Chain serves lookups maintaining validator set diffs that can be applied in-order to reconstruct the validator set of any network at any height. -As the P-Chain grows, the number of validator set diffs that needs to be applied in order to reconstruct the validator set needed to verify an Avalanche Warp Messages increases over time. +As the P-Chain grows, the number of validator set diffs that needs to be applied in order to reconstruct the validator set needed to verify an Avalanche Interchain Messages increases over time. -Therefore, in order to support verifying historical Avalanche Warp Messages, VMs should provide a mechanism to determine whether an Avalanche Warp Message was treated as valid or invalid within a historical block. +Therefore, in order to support verifying historical Avalanche Interchain Messages, VMs should provide a mechanism to determine whether an Avalanche Interchain Message was treated as valid or invalid within a historical block. When nodes bootstrap in the future, they bootstrap blocks that have already been marked as accepted by the network, so they can assume the block was verified by the validators of the network when it was first accepted. -Therefore, the new bootstrapping node can assume the block was valid to determine whether an Avalanche Warp Message should be treated as valid/invalid within the execution of that block. +Therefore, the new bootstrapping node can assume the block was valid to determine whether an Avalanche Interchain Message should be treated as valid/invalid within the execution of that block. Two strategies to provide that mechanism are: -- Require warp message validity for transaction inclusion. If the transaction is included, the warp message must have passed verification. -- Include the results of warp message verification in the block itself. Use the results to determine which messages passed verification. - +- Require interchain message validity for transaction inclusion. If the transaction is included, the interchain message must have passed verification. +- Include the results of interchain message verification in the block itself. Use the results to determine which messages passed verification. diff --git a/content/docs/cross-chain/avalanche-warp-messaging/evm-integration.mdx b/content/docs/cross-chain/avalanche-warp-messaging/evm-integration.mdx index 47ae80844f4..1718217a7f7 100644 --- a/content/docs/cross-chain/avalanche-warp-messaging/evm-integration.mdx +++ b/content/docs/cross-chain/avalanche-warp-messaging/evm-integration.mdx @@ -4,19 +4,19 @@ description: Avalanche Warp Messaging provides a basic primitive for signing and --- -Avalanche Warp Messaging offers a basic primitive to enable Cross-Subnet communication on the Avalanche Network. +Avalanche Warp Messaging offers a basic primitive to enable Cross-L1 communication on the Avalanche Network. It is intended to allow communication between arbitrary Custom Virtual Machines (including, but not limited to Subnet-EVM and Coreth). -## How does Avalanche Interchain Messaging Work? +## How does Avalanche Warp Messaging Work? -Avalanche Interchain Messaging uses BLS Multi-Signatures with Public-Key Aggregation where every Avalanche validator registers a public key alongside its NodeID on the Avalanche P-Chain. +Avalanche Warp Messaging uses BLS Multi-Signatures with Public-Key Aggregation where every Avalanche validator registers a public key alongside its NodeID on the Avalanche P-Chain. -Every node tracking a Subnet has read access to the Avalanche P-Chain. This provides weighted sets of BLS Public Keys that correspond to the validator sets of each Subnet on the Avalanche Network. Avalanche Warp Messaging provides a basic primitive for signing and verifying messages between Subnets: the receiving network can verify whether an aggregation of signatures from a set of source Subnet validators represents a threshold of stake large enough for the receiving network to process the message. +Every node tracking an Avalanche L1 has read access to the Avalanche P-Chain. This provides weighted sets of BLS Public Keys that correspond to the validator sets of each L1 on the Avalanche Network. Avalanche Warp Messaging provides a basic primitive for signing and verifying messages between L1s: the receiving network can verify whether an aggregation of signatures from a set of source L1 validators represents a threshold of stake large enough for the receiving network to process the message. -For more details on Avalanche Warp Messaging, see the AvalancheGo [Warp README](/docs/cross-chain/avalanche-warp-messaging/deep-dive). +For more details on Avalanche Warp Messaging, see the AvalancheGo [Warp README](https://docs.avax.network/build/cross-chain/awm/deep-dive). -### Flow of Sending / Receiving an Interchain Message within the EVM +### Flow of Sending / Receiving a Warp Message within the EVM The Avalanche Warp Precompile enables this flow to send a message from blockchain A to blockchain B: @@ -48,20 +48,20 @@ Additionally, the `SourceChainID` is excluded because anyone parsing the chain c - `sender` - The `messageID` of the unsigned message (sha256 of the unsigned message) -The actual `message` is the entire [Avalanche Interchain Unsigned Message](https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/warp/unsigned_message.go#L14) including an [AddressedCall](https://github.com/ava-labs/avalanchego/tree/master/vms/platformvm/warp/payload#readme). The unsigned message is emitted as the unindexed data in the log. +The actual `message` is the entire [Avalanche Warp Unsigned Message](https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/warp/unsigned_message.go#L14) including an [AddressedCall](https://github.com/ava-labs/avalanchego/tree/master/vms/platformvm/warp/payload#readme). The unsigned message is emitted as the unindexed data in the log. #### getVerifiedMessage -`getVerifiedMessage` is used to read the contents of the delivered Avalanche Interchain Messaging into the expected format. +`getVerifiedMessage` is used to read the contents of the delivered Avalanche Warp Message into the expected format. It returns the message if present and a boolean indicating if a message is present. -To use this function, the transaction must include the signed Avalanche Interchain Messaging encoded in the [predicate](#predicate-encoding) of the transaction. Prior to executing a block, the VM iterates through transactions and pre-verifies all predicates. If a transaction's predicate is invalid, then it is considered invalid to include in the block and dropped. +To use this function, the transaction must include the signed Avalanche Warp Message encoded in the [predicate](#predicate-encoding) of the transaction. Prior to executing a block, the VM iterates through transactions and pre-verifies all predicates. If a transaction's predicate is invalid, then it is considered invalid to include in the block and dropped. This leads to the following advantages: -1. The EVM execution does not need to verify the Interchain Messaging at runtime (no signature verification or external calls to the P-Chain) -2. The EVM can deterministically re-execute and re-verify blocks assuming the predicate was verified by the network (eg., in bootstrapping) +1. The EVM execution does not need to verify the Warp Message at runtime (no signature verification or external calls to the P-Chain) +2. The EVM can deterministically re-execute and re-verify blocks assuming the predicate was verified by the network (e.g., in bootstrapping) This pre-verification is performed using the ProposerVM Block header during [block verification](https://github.com/ava-labs/coreth/blob/master/plugin/evm/block.go#L220) and [block building](https://github.com/ava-labs/coreth/blob/master/miner/worker.go#L200). @@ -71,60 +71,58 @@ This pre-verification is performed using the ProposerVM Block header during [blo This is different from the conventional Ethereum ChainID registered to [ChainList](https://chainlist.org/). -The `blockchainID` in Avalanche refers to the txID that created the blockchain on the Avalanche P-Chain ([docs](https://build.avax.network/docs/specs/platform-transaction-serialization#unsigned-create-chain-tx)). +The `blockchainID` in Avalanche refers to the txID that created the blockchain on the Avalanche P-Chain ([docs](https://docs.avax.network/specs/platform-transaction-serialization#unsigned-create-chain-tx)). ### Predicate Encoding -Avalanche Interchain Messages are encoded as a signed Avalanche [Interchain Messaging](https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/warp/message.go) where the [UnsignedMessage](https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/warp/unsigned_message.go)'s payload includes an [AddressedPayload](https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/warp/payload/payload.go). +Avalanche Warp Messages are encoded as a signed Avalanche [Warp Message](https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/warp/message.go) where the [UnsignedMessage](https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/warp/unsigned_message.go)'s payload includes an [AddressedPayload](https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/warp/payload/payload.go). Since the predicate is encoded into the [Transaction Access List](https://eips.ethereum.org/EIPS/eip-2930), it is packed into 32 byte hashes intended to declare storage slots that should be pre-warmed into the cache prior to transaction execution. Therefore, we use the [Predicate Utils](https://github.com/ava-labs/coreth/blob/master/predicate/Predicate.md) package to encode the actual byte slice of size N into the access list. -### Performance Optimization: C-Chain to Subnet +### Performance Optimization: C-Chain to Avalanche L1 -To support C-Chain to Subnet communication, or more generally Primary Network to Subnet communication, we special case the C-Chain for two reasons: +For communication between the C-Chain and an L1, as well as broader interactions between the Primary Network and Avalanche L1s, we have implemented special handling for the C-Chain. -1. Every Subnet validator validates the C-Chain -2. The Primary Network has the largest possible number of validators +The Primary Network has a large validator set, which creates a unique challenge for Avalanche Warp messages. To reach the required stake threshold, numerous signatures would need to be collected and verifying messages from the Primary Network would be computationally costly. However, we have developed a more efficient solution. -Since the Primary Network has the largest possible number of validators for any Subnet on Avalanche, it would also be the most expensive Subnet to receive and verify Avalanche Warp Messages from as it reaching a threshold of stake on the primary network would require many signatures. Luckily, we can do something much smarter. +When an Avalanche L1 receives a message from a blockchain on the Primary Network, we use the validator set of the receiving L1 instead of the entire network when validating the message. Note this is NOT possible if an L1 does not validate the Primary Network, in which case the Warp precompile must be configured with `requirePrimaryNetworkSigners`. -When a Subnet receives a message from a blockchain on the Primary Network, we use the validator set of the receiving Subnet instead of the entire network when validating the message. This means that the C-Chain sending a message can be the exact same as Subnet to Subnet communication. +Sending messages from the C-Chain remains unchanged. +However, when L1 XYZ receives a message from the C-Chain, it changes the semantics to the following: -However, when Subnet B receives a message from the C-Chain, it changes the semantics to the following: +1. Read the `SourceChainID` of the signed message (C-Chain) +2. Look up the `SubnetID` that validates C-Chain: Primary Network +3. Look up the validator set of L1 XYZ (instead of the Primary Network) and the registered BLS Public Keys of L1 XYZ at the P-Chain height specified by the ProposerVM header +4. Continue Warp Message verification using the validator set of L1 XYZ instead of the Primary Network -1. Read the SourceChainID of the signed message (C-Chain) -2. Look up the SubnetID that validates C-Chain: Primary Network -3. Look up the validator set of Subnet B (instead of the Primary Network) and the registered BLS Public Keys of Subnet B at the P-Chain height specified by the ProposerVM header -4. Continue Warp Message verification using the validator set of Subnet B instead of the Primary Network +This means that C-Chain to L1 communication only requires a threshold of stake on the receiving L1 to sign the message instead of a threshold of stake for the entire Primary Network. -This means that C-Chain to Subnet communication only requires a threshold of stake on the receiving subnet to sign the message instead of a threshold of stake for the entire Primary Network. +This assumes that the security of L1 XYZ already depends on the validators of L1 XYZ to behave virtuously. Therefore, requiring a threshold of stake from the receiving L1's validator set instead of the whole Primary Network does not meaningfully change security of the receiving L1. -This assumes that the security of Subnet B already depends on the validators of Subnet B to behave virtuously. Therefore, requiring a threshold of stake from the receiving Subnet's validator set instead of the whole Primary Network does not meaningfully change security of the receiving Subnet. - -Note: this special case is ONLY applied during Interchain Messaging verification. The message sent by the Primary Network will still contain the Avalanche C-Chain's blockchainID as the sourceChainID and signatures will be served by querying the C-Chain directly. +Note: this special case is ONLY applied during Warp Message verification. The message sent by the Primary Network will still contain the Avalanche C-Chain's blockchainID as the sourceChainID and signatures will be served by querying the C-Chain directly. ## Design Considerations ### Re-Processing Historical Blocks -Avalanche Interchain Messaging depends on the Avalanche P-Chain state at the P-Chain height specified by the ProposerVM block header. +Avalanche Warp Messaging depends on the Avalanche P-Chain state at the P-Chain height specified by the ProposerVM block header. -Verifying a message requires looking up the validator set of the source subnet on the P-Chain. To support this, Avalanche Warp Messaging uses the ProposerVM header, which includes the P-Chain height it was issued at as the canonical point to lookup the source subnet's validator set. +Verifying a message requires looking up the validator set of the source L1 on the P-Chain. To support this, Avalanche Warp Messaging uses the ProposerVM header, which includes the P-Chain height it was issued at as the canonical point to lookup the source L1's validator set. -This means verifying the Interchain Messaging and therefore the state transition on a block depends on state that is external to the blockchain itself: the P-Chain. +This means verifying the Warp Message and therefore the state transition on a block depends on state that is external to the blockchain itself: the P-Chain. -The Avalanche P-Chain tracks only its current state and reverse diff layers (reversing the changes from past blocks) in order to re-calculate the validator set at a historical height. This means calculating a very old validator set that is used to verify an Interchain Messaging in an old block may become prohibitively expensive. +The Avalanche P-Chain tracks only its current state and reverse diff layers (reversing the changes from past blocks) in order to re-calculate the validator set at a historical height. This means calculating a very old validator set that is used to verify a Warp Message in an old block may become prohibitively expensive. Therefore, we need a heuristic to ensure that the network can correctly re-process old blocks (note: re-processing old blocks is a requirement to perform bootstrapping and is used in some VMs to serve or verify historical data). -As a result, we require that the block itself provides a deterministic hint which determines which Avalanche Warp Messages were considered valid/invalid during the block's execution. This ensures that we can always re-process blocks and use the hint to decide whether an Avalanche Interchain Messaging should be treated as valid/invalid even after the P-Chain state that was used at the original execution time may no longer support fast lookups. +As a result, we require that the block itself provides a deterministic hint which determines which Avalanche Warp Messages were considered valid/invalid during the block's execution. This ensures that we can always re-process blocks and use the hint to decide whether an Avalanche Warp Message should be treated as valid/invalid even after the P-Chain state that was used at the original execution time may no longer support fast lookups. To provide that hint, we've explored two designs: 1. Include a predicate in the transaction to ensure any referenced message is valid -2. Append the results of checking whether an Interchain Messaging is valid/invalid to the block data itself +2. Append the results of checking whether a Warp Message is valid/invalid to the block data itself The current implementation uses option (1). diff --git a/content/docs/cross-chain/teleporter/overview.mdx b/content/docs/cross-chain/teleporter/overview.mdx index 3e63bbfb730..b86a8517aea 100644 --- a/content/docs/cross-chain/teleporter/overview.mdx +++ b/content/docs/cross-chain/teleporter/overview.mdx @@ -22,11 +22,11 @@ description: ICM Contracts is a messaging protocol built on top of Avalanche Int ## Overview -`TeleporterMessenger` is a smart contract that serves as the interface for ICM contracts to [Avalanche Interchain Messaging (ICM)](https://academy.avax.network/academy/interchain-messaging/04-icm-basics/01-icm-basics). It provides a mechanism to asynchronously invoke smart contract functions on other EVM L1s within Avalanche. `TeleporterMessenger` provides a handful of useful features to ICM, such as specifying relayer incentives for message delivery, replay protection, message delivery and execution retries, and a standard interface for sending and receiving messages within a dApp deployed across multiple Avalanche L1s. +`TeleporterMessenger` is a smart contract that serves as the interface for ICM contracts to [Avalanche Interchain Messaging (ICM)](https://academy.avax.network/course/interchain-messaging/04-icm-basics/01-icm-basics). It provides a mechanism to asynchronously invoke smart contract functions on other EVM L1s within Avalanche. `TeleporterMessenger` provides a handful of useful features to ICM, such as specifying relayer incentives for message delivery, replay protection, message delivery and execution retries, and a standard interface for sending and receiving messages within a dApp deployed across multiple Avalanche L1s. The `TeleporterMessenger` contract is a user-friendly interface to ICM, aimed at dApp developers. All of the message signing and verification is abstracted away from developers. Instead, developers simply call `sendCrossChainMessage` on the `TeleporterMessenger` contract to send a message invoking a smart contract on another Avalanche L1, and implement the `ITeleporterReceiver` interface to receive messages on the destination Avalanche L1. `TeleporterMessenger` handles all of the ICM message construction and sending, as well as the message delivery and execution. -To get started with using `TeleporterMessenger`, see [How to Deploy ICM Enabled Avalanche L1s on a Local Network](/docs/tooling/cli-cross-chain/teleporter-on-local-networks) +To get started with using `TeleporterMessenger`, see [How to Deploy ICM Enabled Avalanche L1s on a Local Network](https://docs.avax.network/tooling/cli-cross-chain/teleporter-on-local-networks) The `ITeleporterMessenger` interface provides two primary methods: @@ -91,7 +91,7 @@ Once sent on chain, ICM messages cannot be re-signed by a new validator set in s ## TeleporterMessenger Contract Deployment -**Do not deploy the `TeleporterMessenger` contract using `forge create`**. The `TeleporterMessenger` contract must be deployed to the same contract address on every chain. To achieve this, the contract can be deployed using a static transaction that uses Nick's method as documented in [this guide](https://github.com/ava-labs/icm-contracts/blob/main//utils/contract-deployment/README.md). Alternatively, if creating a new L1, the contract can be pre-allocated with the proper address and state in the new chain's [genesis file](/docs/build/subnet/upgrade/customize-a-subnet#setting-the-genesis-allocation). +**Do not deploy the `TeleporterMessenger` contract using `forge create`**. The `TeleporterMessenger` contract must be deployed to the same contract address on every chain. To achieve this, the contract can be deployed using a static transaction that uses Nick's method as documented in [this guide](https://github.com/ava-labs/icm-contracts/blob/main//utils/contract-deployment/README.md). Alternatively, if creating a new L1, the contract can be pre-allocated with the proper address and state in the new chain's [genesis file](https://docs.avax.network/build/subnet/upgrade/customize-a-subnet#setting-the-genesis-allocation). As an example, to include `TeleporterMessenger` `v1.0.0` in the genesis file, include the following values in the `alloc` settings, as documented at the link above. The `storage` values included below correspond to the two contract values that are initialized as part of the default constructor of `TeleporterMessenger`. These are the `ReentrancyGuard` values set in this [abstract contract](https://github.com/ava-labs/icm-contracts/blob/main/contracts/utilities/ReentrancyGuards.sol). Future versions of `TeleporterMessenger` may require different storage value initializations. ```json diff --git a/content/integrations/keystone.mdx b/content/integrations/keystone.mdx new file mode 100644 index 00000000000..4f69b871354 --- /dev/null +++ b/content/integrations/keystone.mdx @@ -0,0 +1,52 @@ +--- +title: Keystone +category: Hardware Wallets +available: ["C-Chain"] +description: Integrate Keystone hardware wallet support into your applications using Keystone's SDK. +logo: /images/keystone.png +developer: Keystone +website: https://keyst.one/ +documentation: https://docs.keyst.one/ +--- + +## Overview + +Keystone provides SDK support for integrating air-gapped hardware wallet functionality into applications built on Avalanche. With recent grant support, Keystone is expanding its capabilities to include X-Chain and P-Chain support. + +## SDK Components + +- **[Firmware](https://github.com/KeystoneHQ/keystone3-firmware)**: Open-source firmware for secure transaction signing +- **Integration SDK**: Coming soon with X-Chain and P-Chain support +- **QR Code Protocol**: Specifications for air-gapped transaction signing + +## Integration Features + +- **Air-Gapped Security**: QR code-based transaction signing +- **Multi-Chain Support**: Current C-Chain with upcoming X-Chain and P-Chain support +- **Cross-Platform**: Support for both desktop and mobile applications +- **Hardware Security**: Secure element protection for private keys + +## Coming Soon + +Integration documentation and SDKs for Avalanche chains will be available in the coming months, enabling developers to: + +- Initialize QR code scanning for air-gapped communication +- Generate and manage wallet addresses +- Implement secure transaction signing +- Handle key management within secure hardware + +## Use Cases + +- **Wallet Applications**: Add air-gapped hardware wallet support +- **Mobile Applications**: Implement QR-based transaction signing +- **DeFi Applications**: Enable secure hardware wallet transactions +- **Cross-Chain Applications**: Support multi-chain operations + +## Documentation + +Full SDK documentation and integration guides will be released alongside the upcoming X-Chain and P-Chain support. + +## Conclusion + +Keystone's upcoming SDK support for Avalanche chains will provide developers with tools to integrate secure, air-gapped hardware wallet functionality into their applications. The SDK will enable robust security features through QR code-based signing, making it ideal for applications requiring high-security standards. + diff --git a/content/integrations/ledger.mdx b/content/integrations/ledger.mdx new file mode 100644 index 00000000000..86e7b97aed4 --- /dev/null +++ b/content/integrations/ledger.mdx @@ -0,0 +1,68 @@ +--- +title: Ledger +category: Hardware Wallets +available: ["C-Chain", "All EVM L1s"] +description: Integrate Ledger hardware wallet support into your applications using official Ledger SDKs for Avalanche. +logo: /images/ledger.png +developer: Ledger +website: https://www.ledger.com/ +documentation: https://developers.ledger.com/ +--- + +## Overview + +Ledger provides multiple SDKs that enable wallet applications and dApps to integrate hardware wallet functionality for Avalanche chains. The SDKs are available in Go and JavaScript, making it easy to add Ledger support to both desktop and web applications. + +## Available SDKs + +- **[Avalanche Ledger App](https://github.com/ava-labs/ledger-avalanche)**: Core application running on Ledger devices +- **[Go SDK](https://github.com/ava-labs/ledger-avalanche-go)**: Native Go implementation for backend and desktop applications +- **[JavaScript SDK](https://github.com/ava-labs/ledger-avalanche)**: Browser and Node.js support for web applications + +## Integration Features + +- **Multi-Chain Support**: Enable transaction signing across C-Chain, X-Chain, and P-Chain +- **Hardware-Based Security**: Leverage Ledger's secure element for key protection +- **Cross-Platform**: Support for both desktop and web applications +- **Transaction Signing**: Secure signing for transfers, staking, and smart contracts + +## Getting Started + +### Go SDK Integration + +```go +import ledger "github.com/ava-labs/ledger-avalanche-go" + +// Initialize connection +ledgerApp, err := ledger.NewLedgerApp() +if err != nil { + // Handle connection error +} +``` + +### JavaScript SDK Integration + +```javascript +import Ledger from '@avalabs/ledger-avalanche' + +const ledger = new Ledger() +await ledger.connect() +``` + +## Use Cases + +- **Wallet Applications**: Add hardware wallet support to cryptocurrency wallets +- **DeFi Applications**: Enable secure transaction signing for DeFi operations +- **Validator Tools**: Secure validator key management and staking operations +- **Cross-Chain Applications**: Support multi-chain operations with single device + +## Documentation + +- [Ledger Developer Portal](https://developers.ledger.com/) +- [Go SDK Documentation](https://pkg.go.dev/github.com/ava-labs/ledger-avalanche-go) +- [JavaScript SDK Documentation](https://github.com/ava-labs/ledger-avalanche) + +## Conclusion + +Ledger's SDKs provide the essential tools for integrating secure hardware wallet functionality into your Avalanche applications. Whether you're building a wallet, DeFi platform, or validator tools, Ledger's SDKs offer robust support for hardware-based key management and transaction signing across all Avalanche chains. + diff --git a/public/images/keystone.png b/public/images/keystone.png new file mode 100644 index 0000000000000000000000000000000000000000..1f936168526be84b7b7c878095661c0cfe4c6a3c GIT binary patch literal 11320 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 y5`jLt8BxH7muBv_)rAQQjhSfK&ckZFfqn~