Skip to content

Commit

Permalink
docs & tests
Browse files Browse the repository at this point in the history
  • Loading branch information
KitHat committed Feb 7, 2025
1 parent 19e40d4 commit 52d84c0
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
** xref:guides/async_backing.adoc[Async Backing]
** xref:guides/hrmp_channels.adoc[Sending XCM between Parachains]
** xref:guides/pallet_abstractions.adoc[OpenZeppelin Pallet Abstractions]
** xref:guides/pay_dot_as_a_fee.adoc[Pay DOT as a Fee]
* EVM Template Guides
** xref:guides/contract_migration.adoc[Contract Migration]
** xref:guides/predeployed_contracts.adoc[Predeployed Contracts]
Expand Down
99 changes: 99 additions & 0 deletions docs/modules/ROOT/pages/guides/pay_dot_as_a_fee.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
:source-highlighter: highlight.js
:highlightjs-languages: rust
:github-icon: pass:[<svg class="icon"><use href="#github-icon"/></svg>]

= Pay DOT as a Fee

This feature allows you to set DOT (or any other registered asset) as a fee for transaction execution. Here are the steps that you will need to execute to support it.

== Configuration

All you need to configure to start using this feature is an Oracle. You can use some service from any oracle service (like Chainlink, Pyth and others who support Substrate runtimes) or set up a development-mode solution.

=== 1. Add Oracle Members

To add oracle members, you'll need to submit transactions with sudo or root privileges:

[source,bash]
----
# Add a member (replace with actual address)
subxt tx --url "ws://localhost:9944" \
--suri "<sudo-suri>" \
pallet-membership add_member \
--account "<oracle-public-key>"
# Verify members
subxt query --url "ws://localhost:9944" \
pallet-membership members
----

=== 2. Format Oracle Values

Oracle values should be formatted according to your runtime's `OracleValue` type. Here's an example for price data:

// TODO: fix values
[source,rust]
----
// Example price format
type Price = FixedU128; // price with 18 decimals
type CurrencyId = u32; // for generic template, for EVM we use u128
----

=== 3. Submit Oracle Data

Here's how to submit oracle data using the CLI:

[source,bash]
----
# Submit price feed for DOT/USD
subxt tx --url "ws://localhost:9944" \
--suri "<oracle-member-key>" \
orml-oracle feed_values \
--values '[[1, "12000000000000000000"]]' # replace the CurrencyId with DOT's AssetId and the number with price of native DOT in native tokens
----

=== 4. Query Oracle Data

To verify the submitted data:

[source,bash]
----
# Query latest price
subxt query --url "ws://localhost:9944" \
orml-oracle get \
--key 1 # CurrencyId
----

== Development Testing

For development purposes, you can set up automated price feeds:

[source,bash]
----
#!/bin/bash
while true; do
# Generate random price between $10-15
PRICE=$((RANDOM % 5000 + 10000))
PRICE_WITH_DECIMALS="${PRICE}000000000000000"
subxt tx --url "ws://localhost:9944" \
--suri "<oracle-member-key>" \
orml-oracle feed_values \
--values "[[1, \"$PRICE_WITH_DECIMALS\"]]"
sleep 60 # Wait 1 minute before next update
done
----

== Opting out

If you want to opt out of this feature, then you can just replace the `pallet_asset_tx_payment` with `pallet_transaction_payment` piece in `SignedExtra`:

[source,patch]
pub type SignedExtra = (
...
- pallet_asset_tx_payment::ChargeAssetTxPayment<Runtime>,
+ pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
...
);
76 changes: 76 additions & 0 deletions evm-template/runtime/src/configs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,82 @@ impl fp_rpc::ConvertTransaction<opaque::UncheckedExtrinsic> for TransactionConve

#[cfg(test)]
mod tests {
mod assets_to_block_author {
use frame_support::traits::{
fungibles::{Balanced, Credit},
OnInitialize,
};
use pallet_asset_tx_payment::HandleCredit;
use parity_scale_codec::Encode;
use sp_core::H256;
use sp_runtime::{
testing::{Digest, DigestItem},
ConsensusEngineId,
};

use crate::{
configs::AssetsToBlockAuthor, AccountId, Assets, Authorship, Balance, Runtime,
RuntimeOrigin, Session, System,
};

pub const MOCK_ENGINE_ID: ConsensusEngineId = [b'M', b'O', b'C', b'K'];
#[test]
fn handle_credit_works_when_author_exists() {
new_test_ext().execute_with(|| {
// Setup
let mut data = [0u8; 32];
let author: AccountId = AccountId::from(data);
const ASSET_ID: u128 = 1;
const AMOUNT: Balance = 100;

let mut digest = Digest::default();
digest.push(DigestItem::PreRuntime(MOCK_ENGINE_ID, author.encode()));
// For unit tests we are updating storage of author in a straightforward way
frame_support::storage::unhashed::put(
&frame_support::storage::storage_prefix(b"Authorship", b"Author"),
&author,
);
// Create asset and mint initial supply
assert!(Assets::force_create(
RuntimeOrigin::root(),
ASSET_ID.into(),
author,
true,
1
)
.is_ok());

// Create credit using issue
let credit = Assets::issue(ASSET_ID, AMOUNT);

// Handle credit
AssetsToBlockAuthor::<Runtime, ()>::handle_credit(credit);

// Verify author received the assets
assert_eq!(Assets::balance(ASSET_ID, author), AMOUNT);
});
}

#[test]
fn handle_credit_drops_when_no_author() {
new_test_ext().execute_with(|| {
// Setup
const ASSET_ID: u128 = 1;
const AMOUNT: Balance = 100;

// Create credit using issue
let credit = Assets::issue(ASSET_ID, AMOUNT);

// Handle credit (should not panic)
AssetsToBlockAuthor::<Runtime, ()>::handle_credit(credit);
});
}

fn new_test_ext() -> sp_io::TestExternalities {
use sp_runtime::BuildStorage;
frame_system::GenesisConfig::<Runtime>::default().build_storage().unwrap().into()
}
}
mod transaction_converter {
use core::str::FromStr;

Expand Down

0 comments on commit 52d84c0

Please sign in to comment.