diff --git a/docs/develop/cheat-sheet/index.mdx b/docs/develop/cheat-sheet/index.mdx index 27fd6d2a..9282e864 100644 --- a/docs/develop/cheat-sheet/index.mdx +++ b/docs/develop/cheat-sheet/index.mdx @@ -128,3 +128,7 @@ For Ledger support, transactions should be created and signed with the TypeScrip ### Via `injectived` Transactions can also be generated, signed, and broadcasted through the `injectived` CLI. See [Using `injectived`](../tools/injectived/02_using.md) for an overview of the process, or the full [commands](../tools/injectived/commands#tx) for documentation on possible transactions types. + +## Add Token Metadata + +To add your token's metadata to the suite of Injective products available (hub, bridge, etc.), see the instructions [here](https://docs.ts.injective.network/readme/assets/injective-list). diff --git a/docs/develop/guides/injective-101/whitelist.md b/docs/develop/guides/injective-101/whitelist.md new file mode 100644 index 00000000..efd7d3a3 --- /dev/null +++ b/docs/develop/guides/injective-101/whitelist.md @@ -0,0 +1,39 @@ +--- +sidebar_position: 9 +title: Whitelisting Addresses for Wasm Uploads +--- + +# Whitelisting Addresses for Wasm Uploads + +# Overview + +Contract upload on Injective requires governance approval. This structure has been put in place for multiple reasons: + +1. Historically, the community has discovered vulnerabilities in CosmWasm whereby certain contracts could cause a chain halt. Thus, requiring approval will be inherently more secure until the language matures and stabilizes over time. +2. Governance prevents un-audited and bogus contracts from being deployed into the network ensuring that hacks and scams will occur at a lesser degree. +3. This results in a more curated experience for ecosystem users since the blockchain does not fill up with unwanted transactions and contracts. + +This governance process is time-consuming for validators and the community. Injective builders additionally face a 4-day wait to roll out features, affecting developer experience and user growth. + +As of the [Altaris chain upgrade](../../../nodes/Validators/mainnet/canonical-chain-upgrade/canonical-1.13.0.md), it is now possible to request whitelisting your address for contract uploads. + +# Submission Guidelines + +In order to be considered for a whitelist approval, it is strongly recommended to include all the following information in the governance proposal. Validators are recommended to contact the Foundation in Discord to verify the information submitted for each proposal before voting. + +1. Are the identities of the team members known to the community? +2. Has the team completed KYC/KYB with the Injective Foundation? +3. How long has the protocol been live on Injective mainnet? +4. Has the team developed applications in other ecosystems? (provide the details) + +# Voting Guidelines + +Users that meet these criteria will have a greater chance at receiving whitelist permissions: + +1. The project has completed Injective Foundation KYC/KYB and the team members' identities are known to the community. +- Exception: Anonymous developers with proven credibility and successful apps in other ecosystems. +2. The project has been live on mainnet for at least 1 month and has achieved significant TVL/usage. + +# Operational Guidelines + +It is strongly recommended to use a multisig or Ledger wallet for the whitelisted uploads. diff --git a/docs/develop/modules/injective/peggy/01_definitions.md b/docs/develop/modules/injective/peggy/01_definitions.md index cf1715bd..037c1da0 100644 --- a/docs/develop/modules/injective/peggy/01_definitions.md +++ b/docs/develop/modules/injective/peggy/01_definitions.md @@ -3,30 +3,34 @@ sidebar_position: 1 title: Definitions --- +# Intro + +This doc aims to provide an overview of `Peggy` (Injective's Ethereum bridge) from a technical perspective and dive deep into its operational logic. +Peggy is the name of the custom Cosmos SDK module built on Injective as well as the Ethereum contract (Peggy.sol) which make up both sides of the bridge. +Connected via a middle-man process called `Peggo` users can securely move token assets between networks. + +To suggest improvements, please open a GitHub issue. + +### Key definitions + +Words matter and we seek clarity in the terminology so we can have clarity in our thinking and communication. +To help better understand, some key definitions are: + +- `Operator` - this is a person (or people) who control and operate `Validator` and `Orchestrator` processes +- `Validator` - this is an Injective Chain validating node (eg. `injectived` process) +- `Validator Set` - the (active) set of Injective Chain `Validators` (Valset) along with their respective voting power as determined by their stake weight. Each validator is associated with an Ethereum address to be represented on the Ethereum network +- `Orchestrator (Peggo)` - the off-chain process (`peggo`) that plays the middleman role between Injective and Ethereum. Orchestrators are responsible for keeping the bridge online and require active endpoints to fully synced Injective (Ethereum) nodes +- `Peggy module` - the counterparty Cosmos module for `Peggy contract`. Besides providing services to bridge token assets, it automatically reflects on the active `Validator Set` as it changes over time. The update is later applied on Ethereum via `Peggo` +- `Peggy Contract` - The Ethereum contract that holds all the ERC-20 tokens. It also maintains a compressed checkpointed representation of the Injective Chain `Validator Set` using `Delegate Keys` and normalized powers +- `Delegate Keys` - when an `Operator` sets up their `Orchestrator` for the first time they register (on Injective) their `Validator`'s address with an Ethereum address. The corresponding key is used to sign messages and represent that validator on Ethereum. + Optionally, one delegate Injective Chain account key can be provided to sign Injective messages (eg `Claims`) on behalf of the `Validator` +- `Peggy Tx pool (withdrawals)` - when a user wishes to move their asset from Injective to Ethereum their individual tx gets pooled with others with the same asset +- `Peggy Batch pool` - pooled withdrawals are batched together (by an `Orchestrator`) to be signed off and eventually relayed to Ethereum. These batches are kept within this pool +- `Claim` - a signed proof (by an `Orchestrator`) that an event occurred in the `Peggy contract` +- `Attestation` - an aggregate of claims for a particular event nonce emitted from `Peggy contract`. After a majority of `Orchestrators` attests to a claim, the event is acknowledged and executed on Injective +- `Majority` - the majority of Injective network, 2/3 + 1 validators +- `Deposit` - an asset transfer initiated from Ethereum to Injective +- `Withdrawal` - an asset transfer initiated from Injective to Ethereum (present in `Peggy Tx pool`) +- `Batch` - a batch of withdrawals with the same token type (present in `Peggy Batch pool`) + -# Definitions - -Words matter and we seek clarity in the terminology, so we can have clarity in our thinking and communication. -Key concepts that we mention below are defined here: - -- `Operator` - This is a person (or people) who control an Injective Chain validator node. This is also called `valoper` or "Validator Operator" in the Cosmos SDK staking module. -- `Validator` - This is an Injective Chain validating node (signs blocks) -- `Orchestrator` - This is the off-chain `peggo` service which performs the following roles for the `Operator`: - - `Eth Signer` - Signs transactions used to move tokens between the two chains using Ethereum private keys. - - `Oracle` - Signs `Claims` using Injective Chain account private keys which are submitted to the Peggy module where they are then aggregated into `Attestations`. - - `Relayer` - Submits Valset updates and Batch transactions to the Peggy contract on Ethereum. It earns fees from the transactions in a batch. -- `Validator Set` - The set of Injective Chain validators, along with their respective voting power as determined by their stake weight, also referred to as a Valset. These are ed25519 public keys (prefixed by`injvalcons`) used to sign Tendermint blocks. -- `Claim` - an Ethereum event signed and submitted to Injective by a single `Orchestrator` -- `Attestation` - an aggregation of claims that eventually becomes `observed` by all orchestrators. -- `Peggy Contract` - The Ethereum contract that holds all of the ERC-20 tokens. It also maintains a compressed checkpointed representation of the Injective Chain validator set using `Delegate Keys` and normalized powers. For example if a validator has 5% of the Injective Chain validator power, their delegate key will have 5% of the voting power in the `Peggy Contract`. These values are regularly updated on the contract to keep the Valset checkpoint in sync with the real Injective Chain validator set. -- `Peggy Tx pool` - a transaction pool that exists in the store of Injective -> Ethereum transactions waiting to be placed into a transaction batch. -- `Transaction batch` - A transaction batch is a set of Ethereum transactions (i.e. withdrawals) to be sent from the Peggy Ethereum contract at the same time. Batching the transactions reduces the individual costs of processing the withdrawals on Ethereum. Batches have a maximum size (currently around 100 transactions) and are only involved in the Injective -> Ethereum flow. -- `Peggy Batch pool` - A transaction pool like structure that exists in the Injective Chain store, separate from the `Peggy Tx pool`. It stores transactions that have been placed in batches that are in the process of being signed or being submitted by the `Orchestrator Set`. -- `EthBlockConfirmationDelay` - An agreed upon number of Ethereum blocks confirmations that all oracle attestations are delayed by. No `Orchestrator` will attest to have seen an event occur on Ethereum until this number of blocks has elapsed as denoted by their trusted Ethereum full node. This prevents short forks/chain reorganizations from causing disagreements on the Injective Chain. The current value used is 12 block confirmations. -- `Observed` - Events on Ethereum are considered `Observed` when the `Eth Signers` of 66% of the active Injective validator set during a given block has submitted an oracle message attesting to seeing the event. -- `Validator set delta` - This is a term for the difference between the validator set currently in the Peggy Ethereum contract and the actual validator set on the Injective Chain. Since the validator set may change every single block there is essentially guaranteed to be some nonzero `Validator set delta` at any given time. -- `Peggy ID` - This is a random 32 byte value required to be included in all Peggy signatures for a particular contract instance. It is passed into the contract constructor on Ethereum and used to prevent signature reuse when contracts may share a validator set or subsets of a validator set. -- `Peggy contract code hash` - This is the code hash of a known good version of the Peggy contract solidity code. It will be used to verify exactly which version of the bridge will be deployed. -- `Voucher` - Represents a bridged ETH token on the Injective Chain side. Their denom is has a `peggy` prefix and a hash that is build from contract address and contract token. The denom is considered unique within the system. -- `Counterpart` - to a `Voucher` is the locked ETH token in the contract -- `Delegate keys` - when an `Operator` sets up the `Eth Signer` and `Oracle` they assign `Delegate Keys` by sending a message containing these keys using their `Validator` address. There is one delegate Ethereum key, used for signing messages on Ethereum and representing this `Validator` on Ethereum and one delegate Injective Chain account key that is used to submit `Oracle` messages. diff --git a/docs/develop/modules/injective/peggy/02_workflow.md b/docs/develop/modules/injective/peggy/02_workflow.md index 6d9c1a68..2a7b4742 100644 --- a/docs/develop/modules/injective/peggy/02_workflow.md +++ b/docs/develop/modules/injective/peggy/02_workflow.md @@ -7,74 +7,93 @@ title: Workflow ## Conceptual Overview -To recap, each operator is responsible for maintaining 3 secure processes: - -1. An Injective Chain Validator node (`injectived`) to sign blocks -2. A fully synced Ethereum full node -3. The `peggo` orchestrator which runs: - * An `Eth Signer`, which signs new `Validator Set` updates and `Transaction Batch`es with the `Operator`'s Ethereum keys and submits using [messages](./04_messages.md#Ethereum-Signer-messages). - * An `Oracle`, which observes events from Ethereum full nodes and relays them using [messages](./04_messages.md#Oracle-messages). - * A `Relayer` which submits confirmed `Validator Set` updates and `Transaction Batch`es to the `Peggy Contract` on Ethereum - * A `Batch Requester` which observes (new) unbatched transactions on Injective and decides which of these to batch according to the cofigured `minBatchFeeUSD` value - -Combined, these 3 entities accomplish 3 things: -- Move assets from Ethereum to Injective -- Move assets from Injective to Ethereum +To recap, each `Operator` is responsible for maintaining 2 secure processes: + +1. A fully synced Injective Chain `Validator` node (`injectived` process) +2. The `Orchestrator` service (`peggo orchestrator` process) which interacts with both networks. Implicitly, an RPC endpoint to a fully synced Ethereum node is required as well (see peggo .env example) + +Combined, these 2 entities accomplish 3 things: +- Move token assets from Ethereum to Injective +- Move token assets from Injective to Ethereum - Keep the `Peggy.sol` contract in sync with the active `Validator Set` on Injective -### Batch Requester +It is possible to run `peggo` without ever being a `Validator`. Peggo automatically runs in "relayer mode" when configured to run with an address **not associated** with a `Validator`. +In this mode, only 2 things can happen: +* new token batches can be created on Injective +* confirmed valsets/batches can be relayed to Ethereum -The purpose of the `Batch Requester` is only in creating transaction batches (aggregated by specific token) on the Injective side. +## Types of Assets -When a user wants to withdraw assets from Injective to Ethereum, they send a special transaction to Injective (`MsgSendToEth`) which is added to `Peggy Tx pool`. `Batch Requester` continually queries for unbatched transactions by asset type (token), determining whether it's worth to batch them. If for a specific asset a batch would satisfy `minBatchFeeUSD`, it informs `peggy` to bundle these transactions into a batch (`MsgRequestBatch`), so they could eventually be picked up by a `Relayer`. +### Native Ethereum assets -### Eth Signer +Any asset originating from Ethereum which implements the ERC-20 standard can be transferred from Ethereum to Injective by calling the `sendToInjective` function on the [Peggy.sol](https://github.com/InjectiveLabs/peggo/blob/master/solidity/contracts/Peggy.sol) contract which transfers tokens from the sender's balance to the Peggy contract. -All contract calls on [Peggy.sol](https://github.com/InjectiveLabs/peggo/blob/master/solidity/contracts/Peggy.sol) accept an array of signatures provided by a validator set stored in the contract. +The `Operators` all run their `peggo` processes which submit `MsgDepositClaim` messages describing the deposit they have observed. Once more than 66% of all voting power has submitted a claim for this specific deposit representative tokens are minted and issued to the Injective Chain address that the sender requested. -Validators make these signatures with their `Delegate Ethereum address`: this is an Ethereum address set by the validator using the [SetOrchestratorAddress](./04_messages.md#SetOrchestratorAddress) message. The validator signs over this Ethereum address, as well as an Injective Chain address and submits it to the Injective chain to register these addresses for use in the signing flow (explained below) and `Oracle` subsystem. +These representative tokens have a denomination prefix of `peggy` concatenated with the ERC-20 token hex address, e.g. `peggy0xdac17f958d2ee523a2206206994597c13d831ec7`. -The `Delegate Ethereum address` then represents that validator on the Ethereum blockchain and will be added as a signing member of the multisig with a weighted voting power as close as possible to the Injective Chain voting power. +### Native Cosmos SDK assets -The `Eth Signer` plays a crucial role in moving assets from Injective to Ethereum as well as keeping the Validator Set on `Peggy.sol` updated. +An asset native to a Cosmos SDK chain (e.g. `ATOM`) first must be represented on Ethereum before it's possible to bridge it. To do so, the [Peggy contract](https://github.com/InjectiveLabs/peggo/blob/master/solidity/contracts/Peggy.sol) allows anyone to create a new ERC-20 token representing a Cosmos asset by calling the `deployERC20` function. -Whenever there is an unconfirmed `Validator Set` update or unconfirmed `Transaction Batch` on Injective, this process fetches it from the `peggy` module, signs it with the provided Ethereum address and sends a `MsgValsetConfirm`/`MsgBatchConfirm` back to `peggy`. Failure to do in a certain amount of time will result in validator slashing. In other words, this process **must be running at all times**. +This endpoint is not permissioned, so it is up to the validators and the users of the Peggy bridge to declare any given ERC-20 token as the representation of a given asset. -### Oracle +When a user on Ethereum calls `deployERC20` they pass arguments describing the desired asset. [Peggy.sol](https://github.com/InjectiveLabs/peggo/blob/master/solidity/contracts/Peggy.sol) uses an ERC-20 factory to deploy the actual ERC-20 contract and assigns ownership of the entire balance of the new token to the Peggy contract itself before emitting an `ERC20DeployedEvent`. -All `Operators` run an `Oracle` binary. This separate process monitors an Ethereum node for new events involving the `Peggy Contract` on the Ethereum chain. Every event that `Oracle` monitors has an event nonce. This nonce is a unique coordinating value for a `Claim`. Since every event that may need to be observed by the `Oracle` has a unique event nonce `Claims` can always refer to a unique event by specifying the event nonce. +The peggo orchestrators observe this event and decide if a Cosmos asset has been accurately represented (correct decimals, correct name, no pre-existing representation). If this is the case, the ERC-20 contract address is adopted and stored as the definitive representation of that Cosmos asset on Ethereum. -1. An `Oracle` observes an event on the Ethereum chain, it packages this event into a `Claim` and submits it to the Injective Chain as an [Oracle message](./04_messages.md#Oracle-messages) -2. Within the `peggy` module this `Claim` either creates or is added to an existing `Attestation` that matches the details of the `Claim`. Once more than 66% of the active `Validator` set has made a `Claim` that matches the given `Attestation` the `Attestation` is executed. This may mint tokens, burn tokens, or whatever is appropriate for this particular event. -3. In the event that the 2/3 of the validators can not agree on a single `Attestation`, the oracle is halted. This means no new events will be relayed from Ethereum until some of the validators change their votes. There is no slashing condition for this, with reasoning outlined in the [slashing spec](./05_slashing.md) +## `Orchestrator` (Peggo) subprocesses -### Relayer +The `peggo orchestrator` process consists of 4 subprocesses running concurrently at exact intervals (loops). These are: +* `Signer` which signs new `Validator Set` updates and `Token Batches` with the `Operator`'s Ethereum keys and submits using [messages](./04_messages.md#Ethereum-Signer-messages). +* `Oracle` which observes Ethereum events and sends them as [claims](./04_messages.md#Oracle-messages) to Injective. +* `Relayer` which submits confirmed `Validator Set` updates and `Token Batches` to the `Peggy Contract` on Ethereum +* `Batch Creator` which observes (new) withdrawals on Injective and decides which of these to batch according to their type and the configured `PEGGO_MIN_BATCH_FEE_USD` value -Relayers cover all messages that need to be submitted to Ethereum from Injective. This includes `Validator Set` updates and `Transaction Batch`es that the validators have confirmed on. Keep in mind that these messages cost a variable amount of money based on wildly changing Ethereum gas prices, so it's not unreasonable for a single batch to cost over a million gas. +### Batch Creator -A major design decision for our relayer rewards was to always issue them on the Ethereum chain. This has downsides, namely some strange behavior in the case of validator set update rewards. +The purpose of the `Batch Creator` is only in creating token batches on the Injective side. The relevant `Peggy module` RPC is not permissioned so anyone can create a batch. -But the upsides are undeniable, because the Ethereum messages pay `msg.sender` any existing bot in the Ethereum ecosystem will pick them up and try to submit them. This makes the relaying market much more competitive and less prone to cabal like behavior. +When a user wants to withdraw assets from Injective to Ethereum they send a special message to Injective (`MsgSendToEth`) which adds their withdrawal to `Peggy Tx Pool`. +`Batch Creator` continually queries the pool for withdrawals (by token type) and issues a `MsgRequestBatch` to Injective when a potential batch satisfies the configured `PEGGO_MIN_BATCH_FEE_USD` value (see .env example). -## Types of Assets +On the receiving end, all pooled withdrawals matching the token type in the request are moved from the `Outgoing Tx Pool` as a single batch and placed in the `Outgoing Batch Pool`. -### Native Ethereum assets +### Signer -Any asset originating from Ethereum which implements the ERC-20 standard can be transferred from Ethereum to Injective by calling the `sendToInjective` function on the [Peggy.sol](https://github.com/InjectiveLabs/peggo/blob/master/solidity/contracts/Peggy.sol) contract which transfers tokens from the sender's balance to the Peggy contract. +The responsibility of Signer is to provide confirmations that an `Operator (Orchestrator)` is partaking in bridge activity. Failure to provide these confirmations results in slashing penalties for the orchestrator's `Validator`. +In other words, this process **must be running at all times** for a `Validator` node. -The validators all run their oracle processes which submit `MsgDepositClaim` messages describing the deposit they have observed. Once more than 66% of all voting power has submitted a claim for this specific deposit representative tokens are minted and issued to the Injective Chain address that the sender requested. +Any payload moving in the Injective->Ethereum pipeline (`Validator Set` updates/`Token Batches`) requires `Validator` signatures to be successfully relayed to Ethereum. Certain calls on `Peggy Contract` accept an array of signatures to be checked against the `Validator Set` in the contract itself. +`Orchestrators` make these signatures with their `Delegate Ethereum address`: this is an Ethereum address decided by the `Operator` upon initial setup ([SetOrchestratorAddress](./04_messages.md#setorchestratoraddresses)). This address then represents that validator on the Ethereum blockchain and will be added as a signing member of the multisig with a weighted voting power as close as possible to the Injective Chain voting power. -These representative tokens have a denomination prefix of `peggy` concatenated with the ERC-20 token hex address, e.g. `peggy0xdac17f958d2ee523a2206206994597c13d831ec7`. +Whenever `Signer` finds that there is a unconfirmed valset update (token batch) present within the `Peggy Module` it issues a `MsgConfirmValset` (`MsgConfirmBatch`) as proof that the operating `Validator` is active in bridge activity. -### Native Cosmos SDK assets +### Oracle -An asset native to a Cosmos SDK chain (e.g. ATOM) first must be represented on Ethereum before it's possible to bridge it. To do so, the [Peggy contract](https://github.com/InjectiveLabs/peggo/blob/master/solidity/contracts/Peggy.sol) allows anyone to create a new ERC-20 token representing a Cosmos asset by calling the `deployERC20` function. +Monitors the Ethereum network for new events involving the `Peggy Contract`. -This endpoint is not permissioned, so it is up to the validators and the users of the Peggy module to declare any given ERC-20 token as the representation of a given asset. +Every event emitted by the contract has a unique event nonce. This nonce value is crucial in coordinating `Orchestrators` to properly observe contract activity and make sure Injective acknowledges them via `Claims`. +Multiple claims of the same nonce make up an `Attestation` and when the majority (2/3) of orchestrators have observed an event its particular logic gets executed on Injective. -When a user on Ethereum calls `deployERC20` they pass arguments describing the desired asset. [Peggy.sol](https://github.com/InjectiveLabs/peggo/blob/master/solidity/contracts/Peggy.sol) uses an ERC-20 factory to deploy the actual ERC-20 contract and assigns ownership of the entire balance of the new token to the Peggy contract itself before emitting an `ERC20DeployedEvent`. +If 2/3 of the validators can not agree on a single `Attestation`, the oracle is halted. This means no new events will be relayed from Ethereum until some of the validators change their votes. There is no slashing condition for this, with reasoning outlined in the [slashing spec](./05_slashing.md) -The peggo orchestrators observe this event and decide if a Cosmos asset has been accurately represented (correct decimals, correct name, no pre-existing representation). If this is the case, the ERC-20 contract address is adopted and stored as the definitive representation of that Cosmos asset on Ethereum. +There are 4 types of events emitted from Peggy.sol: +1. `TransactionBatchExecutedEvent` - event indicating that a token batch (withdrawals) has been successfully relayed to Ethereum +2. `ValsetUpdatedEvent` - event indicating that a `Validator Set` update has been successfully relayed to Ethereum +3. `SendToInjectiveEvent` - event indicating that a new deposit to Injective has been initiated +4. `ERC20DeployedEvent` - event indicating a new Cosmos token has been registered on Ethereum + +Injective's `Oracle` implementation ignores the last 12 blocks on Ethereum to ensure block finality. In reality, this means latest events are observed 2-3 minutes after they occurred. + +### Relayer + +`Relayer` bundles valset updates (or token batches) along with their confirmations into an Ethereum transaction and sends it to the `Peggy contract`. + +Keep in mind that these messages cost a variable amount of money based on wildly changing Ethereum gas prices, so it's not unreasonable for a single batch to cost over a million gas. +A major design decision for our relayer rewards was to always issue them on the Ethereum chain. This has downsides, namely some strange behavior in the case of validator set update rewards. + +But the upsides are undeniable, because the Ethereum messages pay `msg.sender` any existing bot in the Ethereum ecosystem will pick them up and try to submit them. This makes the relaying market much more competitive and less prone to cabal like behavior. ## End-to-end Lifecycle @@ -82,7 +101,8 @@ This document describes the end to end lifecycle of the Peggy bridge. ### Peggy Smart Contract Deployment -In order to deploy the Peggy contract, the validator set of the native chain (Injective Chain) must be known. Upon deploying the Peggy contract suite (Peggy Implementation, Proxy contract, and ProxyAdmin contracts), the Peggy contract (the Proxy contract) must be initialized with the validator set. +In order to deploy the Peggy contract, the validator set of the native chain (Injective Chain) must be known. Upon deploying the Peggy contract suite (Peggy Implementation, Proxy contract, and ProxyAdmin contracts), the Peggy contract (the Proxy contract) must be initialized with the validator set. +Upon initialization a `ValsetUpdatedEvent` is emitted from the contract. The proxy contract is used to upgrade Peggy Implementation contract which is needed for bug fixing and potential improvements during initial phase. It is a simple wrapper or "proxy" which users interact with directly and is in charge of forwarding transactions to the Peggy implementation contract, which contains the logic. The key concept to understand is that the implementation contract can be replaced but the proxy (the access point) is never changed. @@ -92,7 +112,7 @@ Then the following peggy genesis params should be updated: 1. `bridge_ethereum_address` with Peggy proxy contract address 2. `bridge_contract_start_height` with the height at which the Peggy proxy contract was deployed -This completes the bootstrap of the Peggy bridge and the chain can be started. +This completes the bootstrap of the Peggy bridge and the chain can be started. Afterward, `Operators` should start their `peggo` processes and eventually observe that the initial `ValsetUpdatedEvent` is attested on Injective. ### **Updating Injective Chain validator set on Ethereum** @@ -100,14 +120,14 @@ This completes the bootstrap of the Peggy bridge and the chain can be started. A validator set is a series of Ethereum addresses with attached normalized powers used to represent the Injective validator set (Valset) in the Peggy contract on Ethereum. The Peggy contract stays in sync with the Injective Chain validator set through the following mechanism: 1. **Creating a new Valset on Injective:** A new Valset is automatically created on the Injective Chain when either: -- the cumulative difference of the current validator set powers compared to the last recorded Valset exceeds 5% -- a validator begins unbonding -2. **Confirming a Valset on Injective:** Each operator is responsible for confirming Valsets that are created on Injective. This confirmation is constructed by having the validator's delegated Ethereum key sign over a compressed representation of the Valset data, which the orchestrator submits to Injective through a `MsgValsetConfirm`. The peggy module verifies the validity of the signature and persists the operator's Valset confirmation to the peggy state. -3. **Updating the Valset on the Peggy contract:** After a 2/3+ 1 majority of validators have submitted their Valset confirmations for a given Valset, the orchestrator submits the new Valset data to the Peggy contract by calling `updateValset`. -The Peggy contract then validates the data, updates the valset checkpoint, transfers valset rewards to sender and emits a `ValsetUpdateEvent`. -4. **Acknowledging the `ValsetUpdateEvent` on Injective:** Orchestrators witnesses the `ValsetUpdateEvent` on Ethereum, and sends a `MsgValsetUpdatedClaim` which informs the Peggy module that a given Valset has been updated on Ethereum. -5. **Pruning Valsets on Injective:** Once a 2/3 majority of validators send their `MsgValsetUpdatedClaim` message for a given `ValsetUpdateEvent`, all the previous valsets are pruned from the peggy module state. -6. **Valset Slashing:** Validators are responsible for signing and confirming the valsets as described in `Eth Signer` and are subject to slashing for not doing so. Read more [valset slashing](./05_slashing.md) + * the cumulative difference of the current validator set powers compared to the last recorded Valset exceeds 5% + * a validator begins unbonding from the set +2. **Confirming a Valset on Injective:** Each `Operator` is responsible for confirming Valset updates that are created on Injective. The `Signer` process sends these confirmations via `MsgConfirmValset` by having the validator's delegated Ethereum key sign over a compressed representation of the Valset data. The `Peggy module` verifies the validity of the signature and persists it to its state. +3. **Updating the Valset on the Peggy contract:** After a 2/3+ 1 majority of validators have submitted their confirmations for a given Valset, `Relayer` submits the new Valset data to the Peggy contract by calling `updateValset`. +The Peggy contract then validates the data, updates the valset checkpoint, transfers valset rewards to sender and emits a `ValsetUpdatedEvent`. +4. **Acknowledging the `ValsetUpdatedEvent` on Injective:** `Oracle` witnesses the `ValsetUpdatedEvent` on Ethereum, and sends a `MsgValsetUpdatedClaim` which informs the `Peggy module` that the Valset has been updated on Ethereum. +5. **Pruning Valsets on Injective:** Once a 2/3 majority of validators send their claim for a given `ValsetUpdateEvent`, all the previous valsets are pruned from the `Peggy module` state. +6. **Validator Slashing:** Validators are subject to slashing after a configured window of time (`SignedValsetsWindow`) for not providing confirmations. Read more [valset slashing](./05_slashing.md) ---- @@ -116,13 +136,12 @@ The Peggy contract then validates the data, updates the valset checkpoint, trans ![img.png](./images/SendToCosmos.png) ERC-20 tokens are transferred from Ethereum to Injective through the following mechanism: - 1. **Depositing ERC-20 tokens on the Peggy Contract:** A user initiates a transfer of ERC-20 tokens from Ethereum to Injective by calling the `SendToCosmos` function on the Peggy contract which deposits tokens on the Peggy contract and emits a `SendToCosmosEvent`. - + 1. **Depositing ERC-20 tokens on the Peggy Contract:** A user initiates a transfer of ERC-20 tokens from Ethereum to Injective by calling the `sendToInjective` function on the Peggy contract which deposits tokens on the Peggy contract and emits a `SendToInjectiveEvent`. The deposited tokens will remain locked until withdrawn at some undetermined point in the future. This event contains the amount and type of tokens, as well as a destination address on the Injective Chain to receive the funds. - 2. **Confirming the deposit:** Each peggo orchestrator witnesses the `SendToCosmosEvent` and sends a `MsgDepositClaim` which contains the deposit information to the Peggy module. + 2. **Confirming the deposit:** Each `Oracle` witnesses the `SendToInjectiveEvent` and sends a `MsgDepositClaim` which contains the deposit information to the Peggy module. - 3. **Minting tokens on the Injective:** Once a 2/3 majority of validators confirm the deposit claim, the deposit is processed. + 3. **Minting tokens on the Injective:** Once a majority of validators confirm the deposit claim, the deposit is processed. - If the asset is Ethereum originated, the tokens are minted and transferred to the intended recipient's address on the Injective Chain. - If the asset is Cosmos-SDK originated, the coins are unlocked and transferred to the intended recipient's address on the Injective Chain. @@ -132,14 +151,13 @@ ERC-20 tokens are transferred from Ethereum to Injective through the following m ![img.png](./images/SendToEth.png) 1. **Request Withdrawal from Injective:** A user can initiate the transfer of assets from the Injective Chain to Ethereum by sending a `MsgSendToEth` transaction to the peggy module. -- If the asset is Ethereum native, the represented tokens are burnt. -- If the asset is Cosmos SDK native, coins are locked in the peggy module. -The withdrawal is then added to pending withdrawal OutgoingTx Pool. -2. **Batch Creation:** The peggo orchestrator observes the pending withdrawal pool of OutgoingTx's . The orchestrator (or any external third party) then requests a batch of to be created for a given token by sending `MsgRequestBatch` to the Injective Chain. The Peggy module picks unbatched txs from the withdrawal pool and creates the token-specific Outgoing Batch. -3. **Batch Confirmation:** Upon detecting the existence of an Outgoing Batch, the peggo orchestrator signs over the batch with its Ethereum key and submits a `MsgConfirmBatch` tx to the Peggy module. -4. **Submit Batch to Peggy Contract:** Once a 2/3 majority of validators confirm the batch, the peggo orchestrator sends `SubmitBatch` tx to the Peggy contract on Ethereum. The Peggy contract validates the signatures, updates the batch checkpoint, processes the batch ERC-20 withdrawals, transfers the batch fee to the tx sender and emits a `TransactionBatchExecutedEvent`. -5. **Send Withdrawal Claim to Injective:** Validators running the peggo orchestrator witness the `TransactionBatchExecutedEvent` and send a `MsgWithdrawClaim` containing the withdrawal information to the Peggy module. -6. **Prune Batches** Once a 2/3 majority of validators submit their `MsgWithdrawClaim` , the batch is deleted along and all previous batches are cancelled on the Peggy module. + * If the asset is Ethereum native, the represented tokens are burnt. + * If the asset is Cosmos SDK native, coins are locked in the module. The withdrawal is then added to `Outgoing Tx Pool`. +2. **Batch Creation:** A `Batch Creator` observes the pool of pending withdrawals. The batch creator (or any external third party) then requests a batch of to be created for given token by sending `MsgRequestBatch` to the Injective Chain. The `Peggy module` collects withdrawals matching the token type into a batch and puts it in `Outgoing Batch Pool`. +3. **Batch Confirmation:** Upon detecting the existence of an Outgoing Batch, the `Signer` signs over the batch with its Ethereum key and submits a `MsgConfirmBatch` tx to the Peggy module. +4. **Submit Batch to Peggy Contract:** Once a majority of validators confirm the batch, the `Relayer` calls `submitBatch` on the Peggy contract with the batch and its confirmations. The Peggy contract validates the signatures, updates the batch checkpoint, processes the batch ERC-20 withdrawals, transfers the batch fee to the tx sender and emits a `TransactionBatchExecutedEvent`. +5. **Send Withdrawal Claim to Injective:** `Oracles` witness the `TransactionBatchExecutedEvent` and send a `MsgWithdrawClaim` containing the withdrawal information to the Peggy module. +6. **Prune Batches** Once a majority of validators submit their `MsgWithdrawClaim` , the batch is deleted along and all previous batches are cancelled on the Peggy module. Withdrawals in cancelled batches get moved back into `Outgoing Tx Pool`. 7. **Batch Slashing:** Validators are responsible for confirming batches and are subject to slashing if they fail to do so. Read more on [batch slashing](./05_slashing.md). Note while that batching reduces individual withdrawal costs dramatically, this comes at the cost of latency and implementation complexity. If a user wishes to withdraw quickly they will have to pay a much higher fee. However this fee will be about the same as the fee every withdrawal from the bridge would require in a non-batching system. diff --git a/docs/develop/modules/injective/peggy/03_state.md b/docs/develop/modules/injective/peggy/03_state.md index cd899524..e589efe6 100644 --- a/docs/develop/modules/injective/peggy/03_state.md +++ b/docs/develop/modules/injective/peggy/03_state.md @@ -5,73 +5,64 @@ title: State # State -## Params +This doc lists all the data Peggy module reads/writes to its state as KV pairs -Params is a module-wide configuration structure that stores system parameters and defines overall functioning of the peggy module. Detailed specification for each parameter can be found in the [Parameters section](08_params.md). +### Module Params + +Params is a module-wide configuration structure that stores parameters and defines overall functioning of the peggy module. Detailed specification for each parameter can be found in the [Parameters section](08_params.md). + +| key | Value | Type | Encoding | +|---------------|---------------|----------------|------------------| +| `[]byte{0x4}` | Module params | `types.Params` | Protobuf encoded | -- Params: `Paramsspace("peggy") -> legacy_amino(params)` ### Validator Info #### Ethereum Address by Validator -Stores each Validator's corresponding delegate Ethereum address indexed by the validator's account address. +Stores `Delegate Ethereum address` indexed by the `Validator`'s account address -| key | Value | Type | Encoding | -|--------------|-------|--------|------------------------| +| key | Value | Type | Encoding | +|---------------------------------------|------------------|------------------|------------------| | `[]byte{0x1} + []byte(validatorAddr)` | Ethereum address | `common.Address` | Protobuf encoded | #### Validator by Ethereum Address -Stores each Validator's account address indexed by Ethereum address. +Stores `Validator` account address indexed by the `Delegate Ethereum address` -| key | Value | Type | Encoding | -|--------------|-------|--------|------------------------| +| key | Value | Type | Encoding | +|-------------------------------------|-------------------|------------------|------------------| | `[]byte{0xfb} + []byte(ethAddress)` | Validator address | `sdk.ValAddress` | Protobuf encoded | -### OutgoingTxBatch -Stored in two possible ways, first with a height and second without (unsafe). Unsafe is used for testing and export and import of state. -Currently [Peggy.sol](https://github.com/InjectiveLabs/peggo/blob/master/solidity/contracts/Peggy.sol) is hardcoded to only accept batches with a single token type and only pay rewards in that same token type. +#### OrchestratorValidator -```go -// OutgoingTxBatch represents a batch of transactions going from Peggy to ETH -type OutgoingTxBatch struct { - BatchNonce uint64 - BatchTimeout uint64 - Transactions []*OutgoingTransferTx - TokenContract string - Block uint64 -} -``` +When a validator would like to delegate their voting power to another key. The value is stored using the orchestrator address as the key + +| Key | Value | Type | Encoding | +|-------------------------------------|----------------------------------------------|----------|------------------| +| `[]byte{0xe8} + []byte(AccAddress)` | Orchestrator address assigned by a validator | `[]byte` | Protobuf encoded | -| key | Value | Type | Encoding | -|--------------|-------|--------|------------------------| -| `[]byte{0xa} + []byte(tokenContract) + nonce (big endian encoded)` | A batch of outgoing transactions | `types.OutgoingTxBatch` | Protobuf encoded | -### ValidatorSet +### Valset -This is the validator set of the bridge. +This is the validator set of the bridge. Created automatically by `Peggy module` during EndBlocker. Stored in two possible ways, first with a height and second without (unsafe). Unsafe is used for testing and export and import of state. ```go -// Valset is the Ethereum Bridge Multsig Set, each peggy validator also -// maintains an ETH key to sign messages, these are used to check signatures on -// ETH because of the significant gas savings type Valset struct { Nonce uint64 Members []*BridgeValidator Height uint64 RewardAmount math.Int - // the reward token in it's Ethereum hex address representation RewardToken string } ``` -| key | Value | Type | Encoding | -|--------------|-------|--------|------------------------| +| key | Value | Type | Encoding | +|--------------------------------------------|---------------|----------------|------------------| | `[]byte{0x2} + nonce (big endian encoded)` | Validator set | `types.Valset` | Protobuf encoded | ### SlashedValsetNonce @@ -84,80 +75,37 @@ The latest validator set slash nonce. This is used to track which validator set ### ValsetNonce -The latest validator set nonce, this value is updated on every write. +Nonce of the latest validator set. Updated on each new validator set. -| key | Value | Type | Encoding | -|--------------|-------|--------|------------------------| +| key | Value | Type | Encoding | +|----------------|-------|----------|------------------------| | `[]byte{0xf6}` | Nonce | `uint64` | encoded via big endian | ### Valset Confirmation -When a validator signs over a validator set this is considered a `valSetConfirmation`, these are saved via the current nonce and the orchestrator address. - -```go -// MsgValsetConfirm -// this is the message sent by the validators when they wish to submit their -// signatures over the validator set at a given block height. A validator must -// first call MsgSetEthAddress to set their Ethereum address to be used for -// signing. Then someone (anyone) must make a ValsetRequest the request is -// essentially a messaging mechanism to determine which block all validators -// should submit signatures over. Finally validators sign the validator set, -// powers, and Ethereum addresses of the entire validator set at the height of a -// ValsetRequest and submit that signature with this message. -// ------------- -type MsgValsetConfirm struct { - Nonce uint64 - Orchestrator string - EthAddress string - Signature string -} -``` +`Singer` confirmation for a particular validator set. See [oracle messages](./04_messages.md#ValsetConfirm) | Key | Value | Type | Encoding | |---------------------------------------------|------------------------|--------------------------|------------------| | `[]byte{0x3} + (nonce + []byte(AccAddress)` | Validator Confirmation | `types.MsgValsetConfirm` | Protobuf encoded | -### ConfirmBatch - -When a validator confirms a batch it is added to the confirm batch store. It is stored using the orchestrator, token contract and nonce as the key. +### Batch Confirmation -```go -// MsgConfirmBatch -type MsgConfirmBatch struct { - Nonce uint64 - TokenContract string - EthSigner string - Orchestrator string - Signature string -} +`Singer` confirmation for a particular token batch. See [oracle messages](./04_messages.md#ConfirmBatch) -``` | Key | Value | Type | Encoding | |---------------------------------------------------------------------|------------------------------|-------------------------|------------------| | `[]byte{0xe1} + []byte(tokenContract) + nonce + []byte(AccAddress)` | Validator Batch Confirmation | `types.MsgConfirmBatch` | Protobuf encoded | -### OrchestratorValidator - -When a validator would like to delegate their voting power to another key. The value is stored using the orchestrator address as the key -| Key | Value | Type | Encoding | -|-------------------------------------|----------------------------------------------|----------|------------------| -| `[]byte{0xe8} + []byte(AccAddress)` | Orchestrator address assigned by a validator | `[]byte` | Protobuf encoded | - -### EthAddress - -A validator has an associated counter chain address. +### OutgoingTransferTx -| Key | Value | Type | Encoding | -|-------------------------------------|----------------------------------------------|----------|------------------| -| `[]byte{0x1} + []byte(ValAddress)` | Ethereum address assigned by a validator | `[]byte` | Protobuf encoded | +User withdrawals are pooled together in `Peggy Tx Pool` ready to be batched later by a `Batch Creator`. -### OutgoingTransferTx +Each withdrawal is indexed by a unique nonce set by the `Peggy module` when the withdrawal was received. -Sets an outgoing transactions into the applications transaction pool to be included into a batch. ```go -// OutgoingTransferTx represents an individual send from Peggy to ETH type OutgoingTransferTx struct { Id uint64 Sender string @@ -167,61 +115,125 @@ type OutgoingTransferTx struct { } ``` -| Key | Value | Type | Encoding | -|-------------------------------------|----------------------------------------------|----------|------------------| -| `[]byte{0x6} + id (big endian encoded)` | User created transaction to be included in a batch | `types.OutgoingTransferTx` | Protobuf encoded | +| Key | Value | Type | Encoding | +|----------------------------------------|------------------------------|----------|--------------------| +| `[]byte{0x7} + []byte("lastTxPoolId")` | nonce of outgoing withdrawal | `uint64` | Big endian encoded | + + +### LastTXPoolID -### IDS +Monotonically increasing value for each withdrawal received by Injective + +| Key | Value | Type | Encoding | +|----------------------------------------|-------------------------|----------|--------------------| +| `[]byte{0x6} + []byte("lastTxPoolId")` | Last used withdrawal ID | `uint64` | Big endian encoded | + + +### OutgoingTxBatch + +`OutgoingTxBatch` represents a collection of withdrawals of the same token type. Created on every successful `MsgRequestBatch`. + +Stored in two possible ways, first with a height and second without (unsafe). Unsafe is used for testing and export and import of state. +Currently [Peggy.sol](https://github.com/InjectiveLabs/peggo/blob/master/solidity/contracts/Peggy.sol) is hardcoded to only accept batches with a single token type and only pay rewards in that same token type. + +```go +type OutgoingTxBatch struct { + BatchNonce uint64 + BatchTimeout uint64 + Transactions []*OutgoingTransferTx + TokenContract string + Block uint64 +} +``` + +| key | Value | Type | Encoding | +|--------------------------------------------------------------------|----------------------------------|-------------------------|------------------| +| `[]byte{0xa} + []byte(tokenContract) + nonce (big endian encoded)` | A batch of outgoing transactions | `types.OutgoingTxBatch` | Protobuf encoded | +| `[]byte{0xb} + block (big endian encoded)` | A batch of outgoing transactions | `types.OutgoingTxBatch` | Protobuf encoded | + + +### LastOutgoingBatchID + +Monotonically increasing value for each batch created on Injective by some `Batch Creator` + +| Key | Value | Type | Encoding | +|---------------------------------------|--------------------|----------|--------------------| +| `[]byte{0x7} + []byte("lastBatchId")` | Last used batch ID | `uint64` | Big endian encoded | ### SlashedBlockHeight Represents the latest slashed block height. There is always only a singe value stored. -| Key | Value | Type | Encoding | -|-------------------------------------|----------------------------------------------|----------|------------------| +| Key | Value | Type | Encoding | +|----------------|-----------------------------------------|----------|--------------------| | `[]byte{0xf7}` | Latest height a batch slashing occurred | `uint64` | Big endian encoded | +### LastUnbondingBlockHeight + +Represents the latest bloch height at which a `Validator` started unbonding from the `Validator Set`. Used to determine slashing conditions. + +| Key | Value | Type | Encoding | +|----------------|------------------------------------------------------|----------|--------------------| +| `[]byte{0xf8}` | Latest height at which a Validator started unbonding | `uint64` | Big endian encoded | + ### TokenContract & Denom A denom that is originally from a counter chain will be from a contract. The token contract and denom are stored in two ways. First, the denom is used as the key and the value is the token contract. Second, the contract is used as the key, the value is the denom the token contract represents. -| Key | Value | Type | Encoding | -|-------------------------------------|----------------------------------------------|----------|------------------| -| `[]byte{0xf3} + []byte(denom)` | Token contract address | `[]byte` | stored in byte format | +| Key | Value | Type | Encoding | +|----------------------------------------|------------------------|----------|-----------------------| +| `[]byte{0xf3} + []byte(denom)` | Token contract address | `[]byte` | stored in byte format | +| `[]byte{0xf4} + []byte(tokenContract)` | Token denom | `[]byte` | stored in byte format | + +### LastObservedValset + +This entry represents the last observed Valset that was successfully relayed to Ethereum. Updates after an attestation of `ValsetUpdatedEvent` has been processed on Injective. + +| Key | Value | Type | Encoding | +|----------------|----------------------------------|----------------|------------------| +| `[]byte{0xfa}` | Last observed Valset on Ethereum | `types.Valset` | Protobuf encoded | -| Key | Value | Type | Encoding | -|-------------------------------------|----------------------------------------------|----------|------------------| -| `[]byte{0xf4} + []byte(tokenContract)` | Latest height a batch slashing occurred | `[]byte` | stored in byte format | ### LastEventNonce -The last observed event nonce. This is set when `TryAttestation()` is called. There is always only a single value held in this store. +The nonce of the last observed event on Ethereum. This is set when `TryAttestation()` is called. There is always only a single value held in this store. -| Key | Value | Type | Encoding | -|-------------------------------------|----------------------------------------------|----------|------------------| -| `[]byte{0xf2}` | Last observed event nonce| `uint64` | Big endian encoded | +| Key | Value | Type | Encoding | +|----------------|---------------------------|----------|--------------------| +| `[]byte{0xf2}` | Last observed event nonce | `uint64` | Big endian encoded | ### LastObservedEthereumHeight -This is the last observed height on ethereum. There will always only be a single value stored in this store. +This block height of the last observed event on Ethereum. There will always only be a single value stored in this store. -| Key | Value | Type | Encoding | -|-------------------------------------|----------------------------------------------|----------|------------------| -| `[]byte{0xf9}` | Last observed Ethereum Height| `uint64` | Protobuf encoded | +| Key | Value | Type | Encoding | +|----------------|-------------------------------|----------|------------------| +| `[]byte{0xf9}` | Last observed Ethereum Height | `uint64` | Protobuf encoded | + + +### LastEventByValidator + +This is the last observed event on Ethereum from a particular `Validator`. Updated every time the asssociated `Orchestrator` sends an event claim. + +```go +type LastClaimEvent struct { + EthereumEventNonce uint64 + EthereumEventHeight uint64 +} +``` + +| Key | Value | Type | Encoding | +|--------------------------------------------|---------------------------------------|------------------------|------------------| +| `[]byte{0xf1} + []byte(validator address)` | Last observed event by some Validator | `types.LastClaimEvent` | Protobuf encoded | ### Attestation +Attestation is an aggregate of claims that eventually becomes observed by all orchestrators as more votes (claims) are coming in. Once observed the claim's particular logic gets executed. + +Each attestation is bound to a unique event nonce (generated by `Peggy contract`) and they must be processed in order. This is a correctness issue, if relaying out of order transaction replay attacks become possible. + ```go -// Attestation is an aggregate of `claims` that eventually becomes `observed` by -// all orchestrators -// EVENT_NONCE: -// EventNonce a nonce provided by the peggy contract that is unique per event fired -// These event nonces must be relayed in order. This is a correctness issue, -// if relaying out of order transaction replay attacks become possible -// OBSERVED: -// Observed indicates that >67% of validators have attested to the event, -// and that the event should be executed by the peggy state machine type Attestation struct { Observed bool Votes []string @@ -229,6 +241,25 @@ type Attestation struct { Claim *types.Any } ``` -| Key | Value | Type | Encoding | -|-------------------------------------|----------------------------------------------|----------|------------------| -| `[]byte{0x5} + evenNonce (big endian encoded) + []byte(claimHash)` | Attestation of occurred events/claims| `types.Attestation` | Protobuf encoded | +| Key | Value | Type | Encoding | +|----------------------------------------------------------------------|---------------------------------------|---------------------|------------------| +| `[]byte{0x5} + event nonce (big endian encoded) + []byte(claimHash)` | Attestation of occurred events/claims | `types.Attestation` | Protobuf encoded | + +### PastEthSignatureCheckpoint + +A computed hash indicating that a validator set/token batch in fact existed on Injective. This checkpoint also exists in `Peggy contract`. +Updated on each new valset update and token batch creation. + + +| Key | Value | Type | Encoding | +|----------------|-------------------------------------------|-------------------|----------------------| +| `[]byte{0x1b}` | Last created checkpoint hash on Injective | `gethcommon.Hash` | store in byte format | + +### EthereumBlacklist + +A list of known malicious Ethereum addresses that are prevented from using the bridge. + +| Key | Value | Type | Encoding | +|-------------------------------------------|--------------------|-------------------|------------------------| +| `[]byte{0x1c} + []byte(ethereum address)` | Empty []byte slice | `gethcommon.Hash` | stored in byte format] | + diff --git a/docs/develop/modules/injective/peggy/04_messages.md b/docs/develop/modules/injective/peggy/04_messages.md index 57987dbc..d2f14516 100644 --- a/docs/develop/modules/injective/peggy/04_messages.md +++ b/docs/develop/modules/injective/peggy/04_messages.md @@ -9,55 +9,40 @@ This is a reference document for Peggy message types. For code reference and exa ## User messages -These are messages sent on the Injective Chain peggy module. See [workflow](./02_workflow.md) for a more detailed summary of the entire deposit and withdraw process. +These are messages sent on the Injective Chain peggy module by the end user. See [workflow](./02_workflow.md) for a more detailed summary of the entire deposit and withdraw process. ### SendToEth -```go +Sent to Injective whenever a user wishes to make a withdrawal back to Ethereum. Submitted amount is removed from the user's balance immediately. +The withdrawal is added to the outgoing tx pool as a `types.OutgoingTransferTx` where it will remain until it is included in a batch. -// MsgSendToEth -// This is the message that a user calls when they want to bridge an asset -// it will later be removed when it is included in a batch and successfully -// submitted tokens are removed from the users balance immediately -// ------------- -// AMOUNT: -// the coin to send across the bridge, note the restriction that this is a -// single coin not a set of coins that is normal in other Injective messages -// FEE: -// the fee paid for the bridge, distinct from the fee paid to the chain to -// actually send this message in the first place. So a successful send has -// two layers of fees for the user +```go type MsgSendToEth struct { - Sender string - EthDest string - Amount types.Coin - BridgeFee types.Coin + Sender string // sender's Injective address + EthDest string // receiver's Ethereum address + Amount types.Coin // amount of tokens to bridge + BridgeFee types.Coin // additional fee for bridge relayers. Must be of same token type as Amount } ``` -SendToEth allows the user to specify an Ethereum destination, a token to send to Ethereum and a fee denominated in that same token -to pay the relayer. Note that this transaction will contain two fees. One fee amount to submit to the Injective Chain, that can be paid -in any token and one fee amount for the Ethereum relayer that must be paid in the same token that is being bridged. ### CancelSendToEth + +This message allows the user to cancel a specific withdrawal that is not yet batched. User balance is refunded (`Amount` + `BridgeFee`). + ```go -// This call allows the sender (and only the sender) -// to cancel a given MsgSendToEth and receive a refund -// of the tokens type MsgCancelSendToEth struct { - TransactionId uint64 - Sender string + TransactionId uint64 // unique tx nonce of the withdrawal + Sender string // original sender of the withdrawal } -``` -CancelSendToEth allows a user to retrieve a transaction that is in the batch pool but has not yet been packaged into a transaction batch by a relayer running [RequestBatch](./04_messages.md#RequestBatch). +``` ### SubmitBadSignatureEvidence +This call allows anyone to submit evidence that a validator has signed a valset or batch that never existed. Subject contains the batch or valset. + ```go -// This call allows anyone to submit evidence that a -// validator has signed a valset or batch that never -// existed. Subject contains the batch or valset. type MsgSubmitBadSignatureEvidence struct { Subject *types1.Any Signature string @@ -65,163 +50,134 @@ type MsgSubmitBadSignatureEvidence struct { } ``` -SubmitBadSignatureEvidence allows anyone to submit evidence that a validator has signed a valset or batch that never existed. - -## Relayer Messages +## Batch Creator Messages -These are messages run by relayers. Relayers are unpermissioned and simply work to move things from the Injective Chain to Ethereum. +These messages are sent by the `Batch Creator` subprocess of `peggo` ### RequestBatch +This message is sent whenever some `Batch Creator` finds pooled withdrawals that when batched would satisfy their minimum batch fee (`PEGGO_MIN_BATCH_FEE_USD`). +After receiving this message the `Peggy module` collects all withdrawals of the requested token denom, creates a unique token batch (`types.OutgoingTxBatch`) and places it in the `Outgoing Batch pool`. +Withdrawals that are batched cannot be cancelled with `MsgCancelSendToEth`. + + ```go -// MsgRequestBatch -// this is a message anyone can send that requests a batch of transactions to -// send across the bridge be created for whatever block height this message is -// included in. This acts as a coordination point, the handler for this message -// looks at the AddToOutgoingPool tx's in the store and generates a batch, also -// available in the store tied to this message. The validators then grab this -// batch, sign it, submit the signatures with a MsgConfirmBatch before a relayer -// can finally submit the batch -// ------------- type MsgRequestBatch struct { - Orchestrator string - Denom string + Orchestrator string // orchestrator address interested in creating the batch. Not permissioned. + Denom string // the specific token whose withdrawals will be batched together } ``` -Relayers use `QueryPendingSendToEth` in [query.proto](https://github.com/InjectiveLabs/injective-core/blob/master/proto/injective/peggy/v1/query.proto) to query the potential fees for a batch of each -token type. When they find a batch that they wish to relay they send in a RequestBatch message and the Peggy module creates a batch. - -This then triggers the Ethereum Signers to send in ConfirmBatch messages, which the signatures required to submit the batch to the Ethereum chain. - -At this point any relayer can package these signatures up into a transaction and send them to Ethereum. - -As noted above this message is unpermissioned and it is safe to allow anyone to call this message at any time. ## Oracle Messages -All validators run two processes in addition to their Injective node. An Ethereum oracle and Ethereum signer, these are bundled into a single Orchestrator binary for ease of use. - -The oracle observes the Ethereum chain for events from the [Peggy.sol](https://github.com/InjectiveLabs/peggo/blob/master/solidity/contracts/Peggy.sol) contract before submitting them as messages to the Injective Chain. +These messages are sent by the `Oracle` subprocess of `peggo` ### DepositClaim -```go -// EthereumBridgeDepositClaim -// When more than 66% of the active validator set has -// claimed to have seen the deposit enter the ethereum blockchain coins are -// issued to the Injective address in question -// ------------- +Sent to Injective when a `SendToInjectiveEvent` is emitted from the `Peggy contract`. +This occurs whenever a user is making an individual deposit from Ethereum to Injective. + +```go type MsgDepositClaim struct { - EventNonce uint64 - BlockHeight uint64 - TokenContract string - Amount math.Int - EthereumSender string - CosmosReceiver string - Orchestrator string + EventNonce uint64 // unique nonce of the event + BlockHeight uint64 // Ethereum block height at which the event was emitted + TokenContract string // contract address of the ERC20 token + Amount sdkmath.Int // amount of deposited tokens + EthereumSender string // sender's Ethereum address + CosmosReceiver string // receiver's Injective address + Orchestrator string // address of the Orchestrator which observed the event } ``` -Deposit claims represent a `SendToCosmosEvent` emitted by the Peggy contract. After 2/3 of the validators confirm a deposit claim, the representative tokens will be issued to the specified `CosmosReceiver` Injective Chain account. ### WithdrawClaim +Sent to Injective when a `TransactionBatchExecutedEvent` is emitted from the `Peggy contract`. +This occurs when a `Relayer` has successfully called `submitBatch` on the contract to complete a batch of withdrawals. + ```go -// WithdrawClaim claims that a batch of withdrawal -// operations on the bridge contract was executed. type MsgWithdrawClaim struct { - EventNonce uint64 - BlockHeight uint64 - BatchNonce uint64 - TokenContract string - Orchestrator string + EventNonce uint64 // unique nonce of the event + BlockHeight uint64 // Ethereum block height at which the event was emitted + BatchNonce uint64 // nonce of the batch executed on Ethereum + TokenContract string // contract address of the ERC20 token + Orchestrator string // address of the Orchestrator which observed the event } ``` -Withdraw claims represent a `TransactionBatchExecutedEvent` from the Peggy contract. When this passes the oracle vote the batch in state is cleaned up and tokens are burned/locked. -### ValsetUpdateClaim +### ValsetUpdatedClaim + +Sent to Injective when a `ValsetUpdatedEvent` is emitted from the `Peggy contract`. +This occurs when a `Relayer` has successfully called `updateValset` on the contract to update the `Validator Set` on Ethereum. ```go -// This informs the peggy module that a validator -// set has been updated. type MsgValsetUpdatedClaim struct { - EventNonce uint64 - ValsetNonce uint64 - BlockHeight uint64 - Members []*BridgeValidator - RewardAmount math.Int - RewardToken string - Orchestrator string + EventNonce uint64 // unique nonce of the event + ValsetNonce uint64 // nonce of the valset + BlockHeight uint64 // Ethereum block height at which the event was emitted + Members []*BridgeValidator // members of the Validator Set + RewardAmount sdkmath.Int // Reward for relaying the valset update + RewardToken string // reward token contract address + Orchestrator string // address of the Orchestrator which observed the event } ``` -claim representing a `ValsetUpdatedEvent` from the Peggy contract. When this passes the oracle vote reward amounts are tallied and minted. ### ERC20DeployedClaim -```go -// ERC20DeployedClaim allows the peggy module -// to learn about an ERC-20 that someone deployed -// to represent a Cosmos asset +Sent to Injective when a `ERC20DeployedEvent` is emitted from the `Peggy contract`. +This occurs whenever the `deployERC20` method is called on the contract to issue a new token asset eligible for bridging. + +```go type MsgERC20DeployedClaim struct { - EventNonce uint64 - BlockHeight uint64 - CosmosDenom string - TokenContract string - Name string - Symbol string - Decimals uint64 - Orchestrator string + EventNonce uint64 // unique nonce of the event + BlockHeight uint64 // Ethereum block height at which the event was emitted + CosmosDenom string // denom of the token + TokenContract string // contract address of the token + Name string // name of the token + Symbol string // symbol of the token + Decimals uint64 // number of decimals the token has + Orchestrator string // address of the Orchestrator which observed the event } ``` -claim representing a `ERC20DeployedEvent` from the Peggy contract. When this passes the oracle vote it is checked for accuracy and adopted or rejected as the ERC-20 representation of a Cosmos SDK based asset. -## Ethereum Signer Messages -All validators run two processes in addition to their Injective Chain node. An Ethereum oracle and Ethereum signer, these are bundled into a single Orchestrator binary for ease of use. +## Signer Messages -The Ethereum signer watches several [query endpoints](https://github.com/InjectiveLabs/injective-core/blob/master/proto/injective/peggy/v1/query.proto) and it's only job is to submit a signature for anything that appears on those endpoints. For this reason the validator must provide a secure RPC to an Injective Chain node following chain consensus. Or they risk being tricked into signing the wrong thing. +These messages are sent by the `Signer` subprocess of `peggo` ### ConfirmBatch -```go -// MsgConfirmBatch -// When validators observe a MsgRequestBatch they form a batch by ordering -// transactions currently in the txqueue in order of highest to lowest fee, -// cutting off when the batch either reaches a hardcoded maximum size (to be -// decided, probably around 100) or when transactions stop being profitable -// This message includes the batch as well as an Ethereum signature over this batch by the validator -// ------------- +When `Signer` finds a batch that the `Orchestrator` (`Validator`) has not signed off, it constructs a signature with its `Delegated Ethereum Key` and sends the confirmation to Injective. +It's crucial that a `Validator` eventually provides their confirmation for a created batch as they will be slashed otherwise. + +```go type MsgConfirmBatch struct { - Nonce uint64 - TokenContract string - EthSigner string - Orchestrator string - Signature string + Nonce uint64 // nonce of the batch + TokenContract string // contract address of batch token + EthSigner string // Validator's delegated Ethereum address (previously registered) + Orchestrator string // address of the Orchestrator confirming the batch + Signature string // Validator's signature of the batch } ``` -Submits an Ethereum signature over a batch appearing in the `LastPendingBatchRequestByAddr` query. ### ValsetConfirm -```go -// MsgValsetConfirm -// this is the message sent by the validators when they wish to submit their -// signatures over the validator set at a given block height. A validator must -// first call MsgSetEthAddress to set their Ethereum address to be used for -// signing. Then someone (anyone) must make a ValsetRequest the request is -// essentially a messaging mechanism to determine which block all validators -// should submit signatures over. Finally validators sign the validator set, -// powers, and Ethereum addresses of the entire validator set at the height of a -// ValsetRequest and submit that signature with this message. +When `Signer` finds a valset update that the `Orchestrator` (`Validator`) has not signed off, it constructs a signature with its `Delegated Ethereum Key` and sends the confirmation to Injective. +It's crucial that a `Validator` eventually provides their confirmation for a created valset update as they will be slashed otherwise. + +```go type MsgValsetConfirm struct { - Nonce uint64 - Orchestrator string - EthAddress string - Signature string + Nonce uint64 // nonce of the valset + Orchestrator string // address of the Orchestrator confirming the valset + EthAddress string // Validator's delegated Ethereum address (previously registered) + Signature string // Validator's signature of the valset } ``` -Submits an Ethereum signature over a batch appearing in the `LastPendingValsetRequestByAddr` query. + +## Relayer Messages + +The `Relayer` does not send any message to Injective, rather it constructs Ethereum transactions with Injective data to update the `Peggy contract` via `submitBatch` and `updateValset` methods. ## Validator Messages @@ -229,25 +185,14 @@ These are messages sent directly using the validator's message key. ### SetOrchestratorAddresses -```go +Sent to Injective by an `Operator` managing a `Validator` node. Before being able to start their `Orchestrator` (`peggo`) process, they must register a chosen Ethereum address to represent their `Validator` on Ethereum. +Optionally, an additional Injective address can be provided (`Orchestrator` field) to represent that `Validator` in the bridging process (`peggo`). Defaults to `Validator`'s own address if omitted. -// MsgSetOrchestratorAddresses -// this message allows validators to delegate their voting responsibilities -// to a given key. This key is then used as an optional authentication method -// for sigining oracle claims -// VALIDATOR -// The validator field is a injvaloper1... string (i.e. sdk.ValAddress) -// that references a validator in the active set -// ORCHESTRATOR -// The orchestrator field is a inj1... string (i.e. sdk.AccAddress) that -// references the key that is being delegated to -// ETH_ADDRESS -// This is a hex encoded 0x Ethereum public key that will be used by this validator -// on Ethereum +```go type MsgSetOrchestratorAddresses struct { - Sender string - Orchestrator string - EthAddress string + Sender string // address of the Injective validator + Orchestrator string // optional Injective address to represent the Validator in the bridging process (Defaults to Sender if left empty) + EthAddress string // the Sender's (Validator) delegated Ethereum address } ``` This message sets the Orchestrator's delegate keys. diff --git a/docs/develop/modules/injective/peggy/06_end_block.md b/docs/develop/modules/injective/peggy/06_end_block.md index 367faa46..40bcae02 100644 --- a/docs/develop/modules/injective/peggy/06_end_block.md +++ b/docs/develop/modules/injective/peggy/06_end_block.md @@ -3,32 +3,49 @@ sidebar_position: 5 title: End-Block --- -# End-Block +# EndBlocker -Upon the end of each block, the following operation are performed to update queues and validator set changes. +Upon the end of each block the following operations are performed to the state of the module -## Slashing +## 1. Slashing -Multiple slashing conditions (validator set, batch and claim slashing) are checked in the Endblocker. +### Validator slashing -### Validator Slashing +A validator is slashed for not signing over a valset update which passed the `SignedValsetsWindow`. +In other words, if a validator fails to provide the confirmation for a valset update within a preconfigured amount of time, they will be slashed for `SlashFractionValset` portion of their stake and get jailed immediately. -A validator is slashed for not signing over a validator set. The Cosmos SDK allows active validator sets to change from block to block, for this reason we need to store multiple validator sets within a single unbonding period. This allows validators to not be slashed. +### Batch Slashing -A validator will be slashed or missing a single confirmation signing. +A validator is slashed for not signing over a batch which passed the `SignedBatchesWindow`. +In other words, if a validator fails to provide the confirmation for a batch within a preconfigured amount of time, they will be slashed for `SlashFractionBatch` portion of their stake and get jailed immediately. -### Batch Slashing +## 2. Cancelling timed out batches + +Any batch still present in the `Outgoing Batch pool` whose `BatchTimeout` (a designated Ethereum height by which the batch should have executed) is exceeded gets removed from the pool and the withdrawals are reinserted back into the `Outgoing Tx pool`. + +## 3. Creating new Valset updates + +A new `Validator Set` update will be created automatically when: +* there is a power diff greater than 5% between the latest and current validator set +* a validator begins unbonding + +The new validator set is eventually relayed to `Peggy contract` on Ethereum. -A validator is slashed for not signing over a batch request. A validator will be slashed for missing a batch request. +## 4. Pruning old validator sets -## Attestation +Previously observed valsets that passed the `SignedValsetsWindow` are removed from the state -Iterates through all attestations currently being voted on. Once an attestation nonce one higher than the previous one, we stop searching for an attestation and call `TryAttestation`. Once an attestation at a specific nonce has enough votes all the other attestations will be skipped and the `lastObservedEventNonce` incremented. +## 5. Attestation processing -## Cleanup +Processes all attestations (an aggregate of claims for a particular event) currently being voted on. Each attestation is processed one by one to ensure each `Peggy contract` event is processed. +After each processed attestation the module's `lastObservedEventNonce` and `lastObservedEthereumBlockHeight` are updated. -Cleanup loops through batches in order to clean up the timed out transactions. +Depending on the type of claim in the attestation, the following is executed: +* `MsgDepositClaim`: deposited tokens are minted/unlocked for the receiver address +* `MsgWithdrawClaim`: corresponding batch is removed from the outgoing pool and any previous batch is cancelled +* `MsgValsetUpdatedClaim`: the module's `LastObservedValset` is updated +* `MsgERC20DeployedClaim`: new token metadata is validated and registered within the module's state (`denom <-> token_contract`) -### Batches +## 6. Cleaning up processed attestations -When a batch of transactions are created they have a specified height of the opposing chain for when the batch becomes invalid. When this happens we must remove them from the store. At the end of every block, we loop through the store of batches checking the timeout heights. +Previously processed attestations (height earlier that `lastObservedEthereumBlockHeight`) are removed from the module state diff --git a/docs/develop/modules/injective/peggy/07_events.md b/docs/develop/modules/injective/peggy/07_events.md index 1c048202..68ea6656 100644 --- a/docs/develop/modules/injective/peggy/07_events.md +++ b/docs/develop/modules/injective/peggy/07_events.md @@ -10,107 +10,134 @@ The peggy module emits the following events: ## EndBlocker ### EventAttestationObserved -| Type | Attribute Key | Attribute Value | -|-------------|------------------|--------------------| -| observation | module | peggy | -| observation | attestation_type | {attestation_type} | -| observation | bridge_contract | {bridge_contract} | -| observation | bridge_chain_id | {bridge_chain_id} | -| observation | attestation_id | {attestation_id} | -| observation | nonce | {nonce} | +| Type | Attribute Key | Attribute Value | +|--------|------------------|---------------------------| +| int32 | attestation_type | {attestation_type} | +| string | bridge_contract | {bridge_contract_address} | +| uint64 | bridge_chain_id | {bridge_chain_id} | +| []byte | attestation_id | {attestation_id} | +| uint64 | nonce | {event_nonce} | + +### EventValidatorSlash +| Type | Attribute Key | Attribute Value | +|--------|-------------------|-----------------------| +| string | reason | {reason_for_slashing} | +| int64 | power | {validator_power} | +| string | consensus_address | {consensus_addr} | +| string | operator_address | {operator_addr} | +| string | moniker | {validator_moniker} | + ## Handler ### EventSetOrchestratorAddresses -| Type | Attribute Key | Attribute Value | -|---------|----------------------|--------------------| -| message | module | peggy | -| message | set_operator_address | {operator_address} | +| Type | Attribute Key | Attribute Value | +|--------|----------------------|---------------------| +| string | validator_address | {validator_addr} | +| string | orchestrator_address | {orchestrator_addr} | +| string | operator_eth_address | {eth_addr} | ### EventSendToEth -| Type | Attribute Key | Attribute Value | -|---------|----------------|-----------------| -| message | module | peggy | -| message | outgoing_tx_id | {tx_id} | - +| Type | Attribute Key | Attribute Value | +|----------|----------------|-----------------| +| message | outgoing_tx_id | {tx_id} | +| string | sender | {sender_addr} | +| string | receiver | {dest_addr} | +| sdk.Coin | amount | {token_amount} | +| sdk.Coin | bridge_fee | {token_amount} | -### EventBridgeWithdrawalReceived -| Type | Attribute Key | Attribute Value | -|---------------------|-----------------|-------------------| -| withdrawal_received | module | peggy | -| withdrawal_received | bridge_contract | {bridge_contract} | -| withdrawal_received | bridge_chain_id | {bridge_chain_id} | -| withdrawal_received | outgoing_tx_id | {outgoing_tx_id} | -| withdrawal_received | nonce | {nonce} | ### EventBridgeWithdrawCanceled | Type | Attribute Key | Attribute Value | |----------------------|-----------------|-------------------| -| withdrawal_cancelled | module | peggy | | withdrawal_cancelled | bridge_contract | {bridge_contract} | | withdrawal_cancelled | bridge_chain_id | {bridge_chain_id} | ### EventOutgoingBatch -| Type | Attribute Key | Attribute Value | -|----------------|--------------------|-------------------| -| outgoing_batch | module | peggy | -| outgoing_batch | bridge_contract | {bridge_contract} | -| outgoing_batch | bridge_chain_id | {bridge_chain_id} | -| outgoing_batch | outgoing_batch_id | {outgoing_batch_id}| -| outgoing_batch | nonce | {nonce} | +| Type | Attribute Key | Attribute Value | +|----------|----------------------|-----------------| +| string | denom | {token_denom} | +| string | orchestrator_address | {orch_addr} | +| uint64 | batch_nonce | {batch_nonce} | +| uint64 | batch_timeout | {block_height} | +| []uint64 | batch_tx_ids | {ids} | ### EventOutgoingBatchCanceled -| Type | Attribute Key | Attribute Value | -|--------------------------|-----------------|-------------------| -| outgoing_batch_cancelled | module | peggy | -| outgoing_batch_cancelled | bridge_contract | {bridge_contract} | -| outgoing_batch_cancelled | bridge_chain_id | {bridge_chain_id} | -| outgoing_batch_cancelled | outgoing_batch_id | {outgoing_batch_id} | -| outgoing_batch_cancelled | nonce | {nonce} | +| Type | Attribute Key | Attribute Value | +|--------|-----------------|-------------------| +| string | bridge_contract | {bridge_contract} | +| uint64 | bridge_chain_id | {bridge_chain_id} | +| uint64 | batch_id | {id} | +| uint64 | nonce | {nonce} | ### EventValsetConfirm -| Type | Attribute Key | Attribute Value | -|---------|----------------------|--------------------| -| message | module | peggy | -| message | valset_confirm_key | {valset_confirm_key} | +| Type | Attribute Key | Attribute Value | +|--------|----------------------|-----------------| +| uint64 | valset_nonce | {nonce} | +| string | orchestrator_address | {prch_addr} | ### EventConfirmBatch -| Type | Attribute Key | Attribute Value | -|---------|-------------------|---------------------| -| message | module | peggy | -| message | batch_confirm_key | {batch_confirm_key} | +| Type | Attribute Key | Attribute Value | +|--------|----------------------|-----------------| +| uint64 | batch_nonce | {nonce} | +| string | orchestrator_address | {orch_addr} | ### EventDepositClaim -| Type | Attribute Key | Attribute Value | -|---------|----------------|-------------------| -| message | module | peggy | -| message | attestation_id | {attestation_key} | +| Type | Attribute Key | Attribute Value | +|---------|----------------------|-------------------| +| uint64 | event_nonce | {event_nonce} | +| uint64 | event_height | {event_height} | +| []byte | attestation_id | {attestation_key} | +| string | ethereum_sender | {sender_addr} | +| string | cosmos_receiver | {receiver_addr} | +| string | token_contract | {contract_addr} | +| sdk.Int | amount | {token_amount} | +| string | orchestrator_address | {orch_addr} | +| string | data | {custom_data} | ### EventWithdrawClaim -| Type | Attribute Key | Attribute Value | -|---------|----------------|-------------------| -| message | module | peggy | -| message | attestation_id | {attestation_key} | +| Type | Attribute Key | Attribute Value | +|--------|----------------------|-------------------| +| uint64 | event_nonce | {event_nonce{ | +| uint64 | event_height | {event_height} | +| []byte | attestation_id | {attestation_key} | +| uint64 | batch_nonce | {batch_nonce} | +| string | token_contract | {contract_addr} | +| string | orchestrator_address | {orch_addr} | ### EventERC20DeployedClaim -| Type | Attribute Key | Attribute Value | -|---------|----------------|----------------------| -| message | module | peggy | -| message | attestation_id | {attestation_key} | +| Type | Attribute Key | Attribute Value | +|--------|----------------------|------------------------| +| uint64 | event_nonce | {event_nonce} | +| uint64 | event_height | {event_height} | +| []byte | attestation_id | {attestation_key} | +| string | cosmos_denom | {token_denom} | +| string | token_contract | {token_conntract_addr} | +| string | name | {token_name} | +| string | symbol | {token_symbol} | +| uint64 | decimals | {token_decimals} | +| string | orchestrator_address | {orch_addr} | ### EventValsetUpdateClaim -| Type | Attribute Key | Attribute Value | -|---------|----------------|----------------------| -| message | module | peggy | -| message | attestation_id | {attestation_key} | +| Type | Attribute Key | Attribute Value | +|--------------------|----------------------|-----------------------| +| uint64 | event_nonce | {event_nonce} | +| uint64 | event_height | {event_height} | +| []byte | attestation_id | {attestation_key} | +| uint64 | valset_nonce | {valset_nonce} | +| []*BridgeValidator | valset_members | {array_of_validators} | +| sdk.Int | reward_amount | {amount} | +| string | reward_token | {contract_addr} | +| string | orchestrator_address | {orch_addr} | + diff --git a/docs/nodes/validators/mainnet/peggo.md b/docs/nodes/validators/mainnet/peggo.md index 4e574083..60476b49 100644 --- a/docs/nodes/validators/mainnet/peggo.md +++ b/docs/nodes/validators/mainnet/peggo.md @@ -2,31 +2,141 @@ sidebar_position: 17 --- -# Configure Peggo +# Configure Peggo (Injective Mainnet) -## Mainnet +If you're on this page then you've probably become a Validator on Injective. Congratulations! +Configuring `peggo` is the final step of your setup. +Example of `.env` for peggo: +```bash +PEGGO_ENV="local" # environment name for metrics (dev/test/staging/prod/local) +PEGGO_LOG_LEVEL="debug" # log level depth + +PEGGO_COSMOS_CHAIN_ID="injective-1" # chain ID of the Injective network +PEGGO_COSMOS_GRPC="tcp://localhost:9090" # gRPC of your injectived process +PEGGO_TENDERMINT_RPC="http://localhost:26657" # Tendermint RPC of your injectived process + +# Note: omitting PEGGO_COSMOS_GRPC and PEGGO_TENDERMINT_RPC enables stand-alone peggo mode. In this mode, +# peggo is connected to load balanced endpoints provided by the Injective network. This decouples peggo's connection from your injectived process. + +# Injective config +PEGGO_COSMOS_FEE_DENOM="inj" # token used to pay fees on Injective +PEGGO_COSMOS_GAS_PRICES="160000000inj" # default --gas-prices flag value for sending messages to Injective +PEGGO_COSMOS_KEYRING="file" # keyring backends ("os", "file", "kwallet", "memory", "pass", "test") +PEGGO_COSMOS_KEYRING_DIR= # path to your keyring dir +PEGGO_COSMOS_KEYRING_APP="peggo" # arbitrary name for your keyring app +PEGGO_COSMOS_FROM= # account address of your Validator (or your Delegated Orchestrator) +PEGGO_COSMOS_FROM_PASSPHRASE= # keyring passphrase +PEGGO_COSMOS_PK= # private key of your Validator (or your Delegated Orchestrator) +PEGGO_COSMOS_USE_LEDGER=false + +# Ethereum config +PEGGO_ETH_KEYSTORE_DIR= # path to your Ethereum keystore +PEGGO_ETH_FROM= # your Ethereum address (must be Delegated Ethereum address if you're a Validator) +PEGGO_ETH_PASSPHRASE= # passphrase of your Ethereum keystore +PEGGO_ETH_PK= # private key of your Ethereum address +PEGGO_ETH_GAS_PRICE_ADJUSTMENT=1.3 # suggested Ethereum gas price will be adjusted by this factor (Relayer) +PEGGO_ETH_MAX_GAS_PRICE="500gwei" # max gas price allowed for sending Eth transactions (Relayer) +PEGGO_ETH_CHAIN_ID=1 # chain ID of Ethereum network +PEGGO_ETH_RPC="http://localhost:8545" # RPC of your Ethereum node +PEGGO_ETH_ALCHEMY_WS="" # optional websocket endpoint for listening pending transactions on Peggy.sol +PEGGO_ETH_USE_LEDGER=false + +# Price feed provider for token assets (Batch Creator) +PEGGO_COINGECKO_API="https://api.coingecko.com/api/v3" + +# Relayer config +PEGGO_RELAY_VALSETS=true # set to `true` to relay Validator Sets +PEGGO_RELAY_VALSET_OFFSET_DUR="5m" # duration which needs to expire before a Valset is eligible for relaying +PEGGO_RELAY_BATCHES=true # set to `true` to relay Token Batches +PEGGO_RELAY_BATCH_OFFSET_DUR="5m" # duration which needs to expire before a Token Batch is eligible for relaying +PEGGO_RELAY_PENDING_TX_WAIT_DURATION="20m" # time to wait until a pending tx is processed + +# Batch Creator config +PEGGO_MIN_BATCH_FEE_USD=23.2 # minimum amount of fee a Token Batch must satisfy to be created + +# Metrics config +PEGGO_STATSD_PREFIX="peggo." +PEGGO_STATSD_ADDR="localhost:8125" +PEGGO_STATSD_STUCK_DUR="5m" +PEGGO_STATSD_MOCKING=false +PEGGO_STATSD_DISABLED=true +``` -### Step 1: Configure your Peggo relayer +IMPORTANT NOTE: if you're running your own `injectived` (Injective node) and `geth` (Ethereum node) processes, ensure that they are in sync with the latest state. +Outdated nodes can skew the business logic of `peggo` to display "false alarm" logs sometimes. + +## Step 1: Configuring .env ```bash +# official Injective mainnet .env config mkdir ~/.peggo cp mainnet-config/10001/peggo-config.env ~/.peggo/.env cd ~/.peggo ``` +### Ethereum config + First, update the `PEGGO_ETH_RPC` in the `.env` file with a valid Ethereum EVM RPC Endpoint. -To set up your own Ethereum full node, follow the instructions [here](https://ethereum.org/en/developers/docs/nodes-and-clients/run-a-node/). It's possible to use an external Ethereum RPC provider such as Alchemy or Infura, but keep in mind that the Peggo bridge relayer uses a heavy use of `eth_getLogs` calls which may increase your cost burden, depending on your provider. +To set up your own Ethereum full node, follow the instructions [here](https://ethereum.org/en/developers/docs/nodes-and-clients/run-a-node/). It's possible to use an external Ethereum RPC provider such as Alchemy or Infura, but keep in mind that the Peggo bridge relayer makes a heavy use of `eth_getLogs` calls which may increase your cost burden, depending on your provider. + +#### Managing Ethereum keys for `peggo` + +Peggo supports two options to provide signing key credentials - using the Geth keystore (recommended) or by providing a plaintext Ethereum private key. + +**Option 1. Geth Keystore** + +You can find instructions for securely creating a new Ethereum account using a keystore in the Geth Documentation [here](https://geth.ethereum.org/docs/interface/managing-your-accounts). + +For convience, an example is provided below. + +```bash +geth account new --datadir=/home/ec2-user/.peggo/data/ + +INFO [03-23|18:18:36.407] Maximum peer count ETH=50 LES=0 total=50 +Your new account is locked with a password. Please give a password. Do not forget this password. +Password: +Repeat password: + +Your new key was generated + +Public address of the key: 0x9782dc957DaE6aDc394294954B27e2118D05176C +Path of the secret key file: /home/ec2-user/.peggo/data/keystore/UTC--2021-03-23T15-18-44.284118000Z--9782dc957dae6adc394294954b27e2118d05176c + +- You can share your public address with anyone. Others need it to interact with you. +- You must NEVER share the secret key with anyone! The key controls access to your funds! +- You must BACKUP your key file! Without the key, it's impossible to access account funds! +- You must REMEMBER your password! Without the password, it's impossible to decrypt the key! +``` + +Make sure you heed the warnings that geth provides, particularly in backing up your key file so that you don't lose your keys by mistake. We also recommend not using any quote or backtick characters in your passphrase for peggo compatibility purposes. + +You should now set the following env variables: + +```bash +# example values, replace with your own +PEGGO_ETH_KEYSTORE_DIR=/home/ec2-user/.peggo/data/keystore +PEGGO_ETH_FROM=0x9782dc957DaE6aDc394294954B27e2118D05176C +PEGGO_ETH_PASSPHRASE=12345678 +``` + +Then ensure that your Ethereum address has enough ETH. + +**Option 2. Ethereum Private Key (Unsafe)** + +Simply update the `PEGGO_ETH_PK` with a new Ethereum Private Key from a new account. + +Then ensure that your Ethereum address has enough ETH. -Peggo also requires access to your validator's delegated Injective account and Ethereum key credentials to sign transactions for the corresponding networks. +### Injective config #### Creating your delegated Cosmos Key for sending Injective transactions -Your peggo relayer can either +Your peggo orchestrator can either: - Use an explicitly delegated account key specific for sending validator specific Peggy transactions (i.e. `ValsetConfirm`, `BatchConfirm`, and `SendToCosmos` transactions) or - - Simply use your validator's account key. + - Simply use your validator's account key ("your Validator is your Orchestrator") For isolation purposes, we recommend creating a delegated Cosmos key to send Injective transactions instead of using your validator account key. @@ -35,7 +145,7 @@ To create a new key, run injectived keys add $ORCHESTRATOR_KEY_NAME ``` -Then ensure that your orchestrator inj address has INJ balance. +Then ensure that your orchestrator inj address has INJ balance in it, so peggo orchestrator can send messages to Injective. To obtain your orchestrators's inj address, run ```bash @@ -91,62 +201,11 @@ injectived keys unsafe-export-eth-key $VALIDATOR_KEY_NAME Again, this method is less secure and is not recommended. -#### Managing Ethereum keys for `peggo` - -Peggo supports two options to provide signing key credentials - using the Geth keystore (recommended) or by providing a plaintext Ethereum private key. - -**Option 1. Geth Keystore** - -Simply create a new private key store and update the following env variables: -* `PEGGO_ETH_KEYSTORE_DIR` -* `PEGGO_ETH_FROM` -* `PEGGO_ETH_PASSPHRASE` - -You can find instructions for securely creating a new Ethereum account using a keystore in the Geth Documentation [here](https://geth.ethereum.org/docs/interface/managing-your-accounts). - -For convience, an example is provided below. - -```bash -geth account new --datadir=/home/ec2-user/.peggo/data/ - -INFO [03-23|18:18:36.407] Maximum peer count ETH=50 LES=0 total=50 -Your new account is locked with a password. Please give a password. Do not forget this password. -Password: -Repeat password: - -Your new key was generated - -Public address of the key: 0x9782dc957DaE6aDc394294954B27e2118D05176C -Path of the secret key file: /home/ec2-user/.peggo/data/keystore/UTC--2021-03-23T15-18-44.284118000Z--9782dc957dae6adc394294954b27e2118d05176c - -- You can share your public address with anyone. Others need it to interact with you. -- You must NEVER share the secret key with anyone! The key controls access to your funds! -- You must BACKUP your key file! Without the key, it's impossible to access account funds! -- You must REMEMBER your password! Without the password, it's impossible to decrypt the key! -``` - -Make sure you heed the warnings that geth provides, particularly in backing up your key file so that you don't lose your keys by mistake. We also recommend not using any quote or backtick characters in your passphrase for peggo compatibility purposes. - -You should now set the following env variables: - -```bash -# example values, replace with your own -PEGGO_ETH_KEYSTORE_DIR=/home/ec2-user/.peggo/data/keystore -PEGGO_ETH_FROM=0x9782dc957DaE6aDc394294954B27e2118D05176C -PEGGO_ETH_PASSPHRASE=12345678 -``` - -Then ensure that your Ethereum address has enough ETH. - -**Option 2. Ethereum Private Key (Unsafe)** - -Simply update the `PEGGO_ETH_PK` with a new Ethereum Private Key from a new account. - -Then ensure that your Ethereum address has ETH. -### Step 2: Register Your Orchestrator and Ethereum Address +## Step 2: Register Your Orchestrator and Ethereum Address You can register orchestrator and ethereum address only once. It **CANNOT** be updated later. So Check twice before running below command. + ```bash injectived tx peggy set-orchestrator-address $VALIDATOR_INJ_ADDRESS $ORCHESTRATOR_INJ_ADDRESS $ETHEREUM_ADDRESS --from $VALIDATOR_KEY_NAME --chain-id=injective-1 --keyring-backend=file --yes --node=tcp://localhost:26657 --gas-prices=500000000inj @@ -159,10 +218,12 @@ Example: injectived tx peggy set-orchestrator-address inj10m247khat0esnl0x66vu9mhlanfftnvww67j9n inj1x7kvxlz2epqx3hpq6v8j8w859t29pgca4z92l2 0xf79D16a79130a07e77eE36e8067AeA783aBdA3b6 --from validator-key-name --chain-id=injective-1 --keyring-backend=file --yes --node=tcp://localhost:26657 --gas-prices=500000000inj ``` - You can verify successful registration by checking for your Validator's mapped Ethereum address on https://lcd.injective.network/peggy/v1/valset/current. -### Step 3: Start the Relayer +NOTE: Once you've registered your Orchestrator with the `set-orchestrator-address` message, you **CANNOT** register again. Once this step is complete, your `Validator` is bound to the provided Ethereum address (as well the Delegated address you may have provided). +In other words, your peggo must always run with the addresses you provided for registration. + +## Step 3: Start the Relayer ```bash cd ~/.peggo @@ -171,7 +232,7 @@ peggo orchestrator This starts the Peggo bridge (relayer / orchestrator). -### Step 4: Create a Peggo systemd service +## Step 4: Create a Peggo systemd service Add `peggo.service` file with below content under `/etc/systemd/system/peggo.service` @@ -191,7 +252,7 @@ Add `peggo.service` file with below content under `/etc/systemd/system/peggo.ser WantedBy=multi-user.target ``` -Then run the following commands to configure Environment variables, start and stop the peggo relayer. +Then use the following commands to configure Environment variables, start and stop the peggo relayer. ```bash sudo systemctl start peggo @@ -206,7 +267,7 @@ sudo systemctl enable peggo journalctl -f -u peggo ``` -### Step 5: (Optional) Protect Cosmos Keyring from unauthorized access +## Step 5: (Optional) Protect Cosmos Keyring from unauthorized access :::important This is an advanced DevOps topic, consult with your sysadmin.