diff --git a/.dockerignore b/.dockerignore index 24b7e2cc8..b60de5b5f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1 @@ **/target -rust-toolchain diff --git a/Dockerfile.evm b/Dockerfile.evm index 7f44ddcba..5d0d05d5e 100644 --- a/Dockerfile.evm +++ b/Dockerfile.evm @@ -1,21 +1,24 @@ FROM docker.io/paritytech/ci-linux:production as builder LABEL description="This is the build stage for Parallel. Here we create the binary." -ARG PROFILE=production +ARG PROFILE=release ARG BIN=parallel WORKDIR /parallel COPY . /parallel +RUN rustup default nightly + RUN cargo build --workspace --exclude runtime-integration-tests --profile $PROFILE --bin $BIN --features with-evm-runtime --features runtime-benchmarks --features try-runtime # ===== SECOND STAGE ====== FROM docker.io/library/ubuntu:20.04 +ENV DEBIAN_FRONTEND=noninteractive LABEL description="This is the 2nd stage: a very small image where we copy the Parallel binary." -ARG PROFILE=production +ARG PROFILE=release ARG BIN=parallel ENV BIN_PATH=/usr/local/bin/$BIN @@ -23,7 +26,7 @@ ENV BIN_PATH=/usr/local/bin/$BIN COPY --from=builder /parallel/target/$PROFILE/$BIN /usr/local/bin RUN apt update -y \ - && apt install -y ca-certificates libssl-dev \ + && apt install -y ca-certificates libssl-dev tzdata \ && useradd -m -u 1000 -U -s /bin/sh -d /parallel parallel \ && mkdir -p /parallel/.local \ && mkdir /data \ diff --git a/Dockerfile.release b/Dockerfile.release index 799da1cc8..d9fb48d58 100644 --- a/Dockerfile.release +++ b/Dockerfile.release @@ -8,11 +8,14 @@ WORKDIR /parallel COPY . /parallel +RUN rustup default nightly + RUN cargo build --workspace --exclude runtime-integration-tests --profile $PROFILE --bin $BIN --features runtime-benchmarks --features try-runtime # ===== SECOND STAGE ====== FROM docker.io/library/ubuntu:20.04 +ENV DEBIAN_FRONTEND=noninteractive LABEL description="This is the 2nd stage: a very small image where we copy the Parallel binary." ARG PROFILE=production @@ -23,7 +26,7 @@ ENV BIN_PATH=/usr/local/bin/$BIN COPY --from=builder /parallel/target/$PROFILE/$BIN /usr/local/bin RUN apt update -y \ - && apt install -y ca-certificates libssl-dev \ + && apt install -y ca-certificates libssl-dev tzdata \ && useradd -m -u 1000 -U -s /bin/sh -d /parallel parallel \ && mkdir -p /parallel/.local \ && mkdir /data \ diff --git a/Makefile b/Makefile index 9099ca11a..93e82dee8 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ SURI := //Alice LAUNCH_CONFIG_YAML := config.yml LAUNCH_CONFIG_JSON := config.json DOCKER_OVERRIDE_YAML := docker-compose.override.yml -DOCKER_TAG := latest +DOCKER_TAG := latest_evm RELAY_DOCKER_TAG := v0.9.24 CUMULUS_DOCKER_TAG := v0.9.24 @@ -253,13 +253,19 @@ wasm: spec: docker run --rm parallelfinance/parallel:$(DOCKER_TAG) build-spec --chain $(CHAIN) --disable-default-bootnode --raw > ./resources/$(CHAIN)-raw.json -.PHONY: image -image: - docker build --build-arg BIN=parallel \ +.PHONY: production-image +production-image: + DOCKER_BUILDKIT=1 docker build --build-arg BIN=parallel \ -c 512 \ - -t parallelfinance/parallel:$(DOCKER_TAG) \ - -f Dockerfile.release \ - . --network=host + -t parallelfinance/parallel:latest \ + -f Dockerfile.release . + +.PHONY: integration-image-with-evm +integration-image-with-evm: + DOCKER_BUILDKIT=1 docker build --build-arg BIN=parallel \ + -c 512 \ + -t parallelfinance/parallel:latest_evm \ + -f Dockerfile.evm . .PHONY: key key: diff --git a/config.yml b/config.yml index 24170b841..de6de8d0c 100644 --- a/config.yml +++ b/config.yml @@ -45,7 +45,7 @@ parachains: - --execution=wasm - --state-cache-size=0 env: - RUST_LOG: xcm=trace,loans=trace,liquidStaking=trace,crowdloans=trace,amm=trace,stableswap=trace,router=trace,bridge=trace,prices=trace + RUST_LOG: eth=trace,xcm=trace,loans=trace,liquidStaking=trace,crowdloans=trace,amm=trace,stableswap=trace,router=trace,bridge=trace,prices=trace nodes: - flags: - --alice diff --git a/integration-tests/src/setup.rs b/integration-tests/src/setup.rs index 2ad023dfb..8b410e94b 100644 --- a/integration-tests/src/setup.rs +++ b/integration-tests/src/setup.rs @@ -12,7 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +use frame_support::traits::ConstU32; use frame_support::traits::GenesisBuild; +use frame_support::WeakBoundedVec; use frame_support::traits::Currency; use pallet_loans::{InterestRateModel, JumpModel, Market, MarketState}; @@ -35,6 +37,7 @@ pub const DOT_DECIMAL: u32 = 10; pub const RMRK_DECIMAL: u8 = 10; pub const USDT_DECIMAL: u8 = 6; pub const HEIKO_DECIMAL: u8 = 12; +pub const KAR_DECIMAL: u8 = 12; pub const RMRK_ASSET_ID: u32 = 8; pub const USDT_ASSET_ID: u32 = 1984; @@ -42,6 +45,7 @@ pub const RMRK: CurrencyId = 126; pub const RMRK_WEIGHT_PER_SEC: u128 = 20_000_000_000; pub const USDT_WEIGHT_PER_SEC: u128 = 30_000_000; +pub const KAR_WEIGHT_PER_SEC: u128 = 30_000_000_000; pub const FEE_IN_STATEMINE: u128 = 15_540_916; pub const WEIGHT_IN_STATEMINE: u64 = 4_000_000_000; @@ -259,6 +263,44 @@ impl ExtBuilder { ) .unwrap(); + //initialize for acala kar as mock sibling + Assets::force_create( + Origin::root(), + KAR, + MultiAddress::Id(AccountId::from(ALICE)), + true, + 1, + ) + .unwrap(); + Assets::force_set_metadata( + Origin::root(), + KAR, + b"KAR".to_vec(), + b"KAR".to_vec(), + KAR_DECIMAL, + false, + ) + .unwrap(); + let kar_asset_location = MultiLocation::new( + 1, + X2( + Parachain(2000), + //since we use hko to mock kar,just use hko location here + GeneralKey(WeakBoundedVec::>::force_from( + b"HKO".to_vec(), + None, + )), + ), + ); + let kar_asset_type = AssetType::Xcm(kar_asset_location); + AssetRegistry::register_asset(Origin::root(), KAR, kar_asset_type.clone()).unwrap(); + AssetRegistry::update_asset_units_per_second( + Origin::root(), + kar_asset_type, + KAR_WEIGHT_PER_SEC, + ) + .unwrap(); + //initialize for liquidate staking Assets::force_create( Origin::root(), diff --git a/integration-tests/src/sibling_transfer.rs b/integration-tests/src/sibling_transfer.rs index 46b18c023..d40ce0785 100644 --- a/integration-tests/src/sibling_transfer.rs +++ b/integration-tests/src/sibling_transfer.rs @@ -14,16 +14,52 @@ use crate::{kusama_test_net::*, setup::*}; -use frame_support::assert_ok; -use primitives::AccountId; +use frame_support::{assert_ok, traits::ConstU32, WeakBoundedVec}; +use primitives::{AccountId, KAR}; use xcm::latest::prelude::*; use xcm_emulator::TestExt; #[test] fn transfer_sibling_chain_asset() { - use heiko_runtime::{Balances, Origin, XTokens}; TestNet::reset(); + //since not easy to introduce runtime from other chain,just use heiko's + use heiko_runtime::{Assets, Balances, Origin, PolkadotXcm, XTokens}; + + MockSibling::execute_with(|| { + assert_ok!(PolkadotXcm::reserve_transfer_assets( + Origin::signed(ALICE.into()).clone(), + Box::new(MultiLocation::new(1, X1(Parachain(2085))).into()), + Box::new( + Junction::AccountId32 { + id: BOB, + network: NetworkId::Any + } + .into() + .into() + ), + //just use hko to mock kar here + Box::new( + ( + X1(GeneralKey(WeakBoundedVec::>::force_from( + b"HKO".to_vec(), + None + ))), + heiko(10) + ) + .into() + ), + 0 + )); + }); + + // Rerun execute to actually send the egress message via XCM + MockSibling::execute_with(|| {}); + + Heiko::execute_with(|| { + assert_eq!(Assets::balance(KAR, &AccountId::from(BOB)), 9999982000000); + }); + Heiko::execute_with(|| { assert_ok!(XTokens::transfer( Origin::signed(ALICE.into()), diff --git a/primitives/src/tokens.rs b/primitives/src/tokens.rs index f3bacd45b..0e1cd85ef 100644 --- a/primitives/src/tokens.rs +++ b/primitives/src/tokens.rs @@ -44,6 +44,7 @@ pub const IBTC: CurrencyId = 122; pub const GENS: CurrencyId = 123; pub const EQ: CurrencyId = 124; pub const TUR: CurrencyId = 125; +pub const LIT: CurrencyId = 127; // Ethereum ecosystem pub const EUSDT: CurrencyId = 201; diff --git a/runtime/heiko/src/lib.rs b/runtime/heiko/src/lib.rs index e89b331fe..d8ae991af 100644 --- a/runtime/heiko/src/lib.rs +++ b/runtime/heiko/src/lib.rs @@ -1268,14 +1268,16 @@ parameter_types! { ).into(), ksm_per_second() * 400 ); - // Kintsugi + //Kintsugi:(1,X2(2092,0x000C)) pub KintPerSecond: (AssetId, u128) = ( MultiLocation::new( 1, X2(Parachain(paras::kintsugi::ID), GeneralKey(WeakBoundedVec::>::force_from(paras::kintsugi::KINT_KEY.to_vec(), None))), ).into(), + //~100 ksm_per_second() * 400 ); + //Kbtc:(1,X2(2092,0x000B)) pub KbtcPerSecond: (AssetId, u128) = ( MultiLocation::new( 1, @@ -1299,7 +1301,7 @@ parameter_types! { ).into(), ksm_per_second() * 260 ); - // Calamari + // Calamari(1,2084) pub KmaPerSecond: (AssetId, u128) = ( MultiLocation::new( 1, diff --git a/scripts/helper/.env.example b/scripts/helper/.env.example new file mode 100644 index 000000000..48c0399a0 --- /dev/null +++ b/scripts/helper/.env.example @@ -0,0 +1,2 @@ +#RELAY_CHAIN_TYPE:kusama|polkadot +RELAY_CHAIN_TYPE=kusama \ No newline at end of file diff --git a/scripts/helper/src/commands/get/xcm_units_per_second.ts b/scripts/helper/src/commands/get/xcm_units_per_second.ts new file mode 100644 index 000000000..d9e9cb1f4 --- /dev/null +++ b/scripts/helper/src/commands/get/xcm_units_per_second.ts @@ -0,0 +1,22 @@ +import { calcWeightPerSecond } from '../../utils' +import { Command, CreateCommandParameters, program } from '@caporal/core' + +export default function ({ createCommand }: CreateCommandParameters): Command { + return createCommand('calculate units_per_second for xcm reserved transfer') + .argument('', 'precision of asset', { + validator: program.NUMBER + }) + .argument('', 'price of asset', { + validator: program.NUMBER + }) + .action(actionParameters => { + const { + logger, + args: { precision, price } + } = actionParameters + const precision_num = precision.valueOf() as number + const price_num = price.valueOf() as number + const result = calcWeightPerSecond(precision_num, price_num) + logger.info(result.toString()) + }) +} diff --git a/scripts/helper/src/commands/hrmp/open.ts b/scripts/helper/src/commands/hrmp/open.ts index e2b14f67d..c83bf6336 100644 --- a/scripts/helper/src/commands/hrmp/open.ts +++ b/scripts/helper/src/commands/hrmp/open.ts @@ -1,9 +1,19 @@ -import { createXcm, getApi, getRelayApi, nextNonce, sovereignRelayOf } from '../../utils' +import { + createXcm, + getApi, + getRelayApi, + nextNonce, + sovereignRelayOf, + getDefaultRelayChainWsUrl, + getDefaultParachainWsUrl +} from '../../utils' import { Command, CreateCommandParameters, program } from '@caporal/core' import { Keyring } from '@polkadot/api' import { PolkadotRuntimeParachainsConfigurationHostConfiguration } from '@polkadot/types/lookup' export default function ({ createCommand }: CreateCommandParameters): Command { + const relayChainUrl: string = getDefaultRelayChainWsUrl() + const paraChainUrl: string = getDefaultParachainWsUrl() return createCommand('open hrmp channel to specific chain') .argument('', 'paraId of source chain', { validator: program.NUMBER @@ -12,10 +22,10 @@ export default function ({ createCommand }: CreateCommandParameters): Command { validator: program.NUMBER }) .option('-r, --relay-ws [url]', 'the relaychain API endpoint', { - default: 'wss://rpc.polkadot.io' + default: relayChainUrl }) .option('-p, --para-ws [url]', 'the parachain API endpoint', { - default: 'wss://rpc.parallel.fi' + default: paraChainUrl }) .option('-d, --dry-run [boolean]', 'whether to execute using PARA_CHAIN_SUDO_KEY', { validator: program.BOOLEAN, diff --git a/scripts/helper/src/utils.ts b/scripts/helper/src/utils.ts index 869e8833a..55781abba 100644 --- a/scripts/helper/src/utils.ts +++ b/scripts/helper/src/utils.ts @@ -10,7 +10,6 @@ import { Index } from '@polkadot/types/interfaces' import { promisify } from 'util' const EMPTY_U8A_32 = new Uint8Array(32) -const XCM_FEE = 2500000000 export const readFile = promisify(fs.readFile) @@ -78,7 +77,7 @@ export const createXcm = (encoded: string, refundAccount: string, originType = ' } }, fun: { - Fungible: XCM_FEE + Fungible: getDefaultXcmFee() } } ] @@ -93,7 +92,7 @@ export const createXcm = (encoded: string, refundAccount: string, originType = ' } }, fun: { - Fungible: XCM_FEE + Fungible: getDefaultXcmFee() } }, weightLimit: 'Unlimited' @@ -153,3 +152,33 @@ export const getRelayApi = async (endpoint: string): Promise => { provider: new WsProvider(endpoint) }) } + +export const calcWeightPerSecond = (precision: number, price: number): number => { + const WEIGHT_PER_SECOND = 10 ** 12 + // for fixed weigher always 600_000_000 + const weight = 600_000_000 + //assume we charge 0.02$ at most for each xcm reserved based transfer + const max_fee = 0.02 + /// max_fee = (weight_per_second * weight)/WEIGHT_PER_SECOND/(10**precision) * price + /// so weight_per_second = max_fee*WEIGHT_PER_SECOND*(10**precision)/weight/price + const weight_per_second = (((max_fee * WEIGHT_PER_SECOND) / weight) * 10 ** precision) / price + /// to avoid price sharply increased later so that we charge too much + /// just add some soft limit here + return Math.min(1000 * WEIGHT_PER_SECOND, Math.floor(weight_per_second)) +} + +export const getDefaultRelayChainWsUrl = (): string => { + return process.env['RELAY_CHAIN_TYPE'] === 'kusama' + ? 'wss://kusama-rpc.polkadot.io' + : 'wss://rpc.polkadot.io' +} + +export const getDefaultParachainWsUrl = (): string => { + return process.env['RELAY_CHAIN_TYPE'] === 'kusama' + ? 'wss://heiko-rpc.parallel.fi' + : 'wss://rpc.parallel.fi' +} + +export const getDefaultXcmFee = (): number => { + return process.env['RELAY_CHAIN_TYPE'] === 'kusama' ? 10_000_000_000 : 2_500_000_000 +}