Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crosschain borrow automation #1992

Closed
annamehr opened this issue Feb 29, 2024 · 1 comment
Closed

Crosschain borrow automation #1992

annamehr opened this issue Feb 29, 2024 · 1 comment
Assignees

Comments

@annamehr
Copy link
Contributor

annamehr commented Feb 29, 2024

Protocol specs
UI specs

Background

Given the merge of remote account derivation via xcm users/pallets/on-chain accounts/etc. are now able to have safe remote accounts on all system parachains. This enables us to make interaction with these chains safer and easer for users

The overall goal is that issuers can on-ramp and off-ramp USDC from Polkadot AssetHub without directly interacting with AssetHub. All interactions MUST be triggered through XCMs send from Centrifuge.

The usual on-ramp flow includes three steps:

  • Wire USD to Circle; convert USD -> USDC
  • Send USDC to account on AssetHub
  • XCM-Transfer USDC to account on Centrifuge --- tx is signed on AssetHub

The last step will not be triggered on AssetHub but on Centrifuge. We can abstract away all complexity for the end-user, making it much safer than using polkadot.js.

The usual off-ramp flow includes x steps:

  • XCM-Transfer USDC to user controlled account on AssetHub --- tx is signed on Centrifuge
  • Local-Transfer USDC to off-ramp account on AssetHub --- tx is signed on AssetHub

:::info
💡 We can XCM-Transfer directly into the off-ramp account on AssetHub as Circle is rejecting those transfers, leading to a loss of funds.
:::

Requirements

  • Withdraw assets from a remote accounts holdings and transfer them to Centrifuge --- by dispatching the appropriate XCM from Centrifuge
  • Transact a call from a remote account on another chain --- by dispatching the appropriate XCM from Centrifuge
  • Transfer an assets from Centrifuge to another chain and transact a call from a remote account on said chain afterwards --- by dispatching the appropriate XCM from Centrifuge

Foreseable Obstacles

:::danger
⚠️ Testing is only possible via Fudge, Altair and on Centrifuge. Dev and Demo do not work well here.
:::

💻 Technical Spec

Option A - Preferred

Adapting the existing runtime configuration to allow a batch(xtokens::transfer(..), pallet_xcm::send(..)). Where the first generates an XCM that transfers the funds to the remote controlled account, and the second creates the actual transaction to send tokens.

:::info
💡 Generating the derived account on other chains is trivial by using our AccountConversionApi.conversionOf runtime api with the multilocation that the receiving chain will see.
:::

Adapt Runtime Configuration

  • Fix LocalOriginToLocation

    Current definition is:

    pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;

    but rather must be

    struct ByGenesis<T>(PhandomtData<T>)
    
    impl<T> Get<Option<NetworkId>> for ByGenesis<T> {
        fn get() -> OptionM<NetworkId> {
            // retrieve genesis hash here.
            let genesis_hash = todo!();
            Some(NetoworkId::ByGensis(genesis_hash))
        }
    }
    
    pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, ByGenesis>;

    Note: Only possible if Expose Genesis Hash to Runtime paritytech/polkadot-sdk#3344 is solved. Else use None.

  • Fix BasicCallFilter to allow pallet_xcm::send{..}

Option B

Creating correct XCM messages is hard - the orml-xtokens provides a good insight into how tedious it is to transfer assets with XCM. Unfortunately, most of the pallets method are private and not well suitable for composition.

:::success
📓 Proposal for...

  • copy-pasta the transfer XCM generation logic from the orml-xtokens pallet will be the fastest to get this live. Waiting for orml to adapt our changes and us being able to use them will take too long.

:::

pallet-restricted-xtokens Extension

Types
RemoteTransact

A type that allows to easily create the right Instruction.

pub struct RemoteTransact<T: Config> {
	call: BoundedVec<u8, T::MaxTransact>,
	require_weight_at_most: Weight,
}

impl<T: Config> Into<Instruction<()>> for RemoteTransact<T> {
	fn into(self) -> Instruction<()> {
		Instruction::Transact {
			origin_kind: OriginKind::SovereignAccount,
			require_weight_at_most: self.require_weight_at_most,
			call: From::<Vec<u8>>::from(self.call.into()),
		}
	}
}
Calls

The idea is to extend our pallet-restricted-xtokens with three additional calls:


fn remote_transact

:::info
💡 An extrinsics allows to create an XCM that is send to another chain and executes a transaction on behalf of the sender on Centrifuge via its remote account.
:::

  • Logical Requirements
    • Callable by all signed origins
    • MUST use Instruction::DescendOrigin(who) before the Instruction::Transact
  • Method Parameters
    origin: OriginFor<T>,
    remote_transact: RemoteTransact<T>,
    // NOTE: Type used for defining how much the user wants 
    //       to pay at most on the receiving side for the execution.
    dest_weight_limit: WeightLimit,

fn remote_deposit_transact

:::info
💡 An extrinsics allows to send assets to another account on another chain and in the same XCM processing to also execute a transaction on behalf of the sender on Centrifuge via its remote account.
:::
:::info
💡 NOTE: Needed for doing off-ramping in one step. Receiver of funds in this case will also be the remote account.
:::

  • Logical Requirements
    • Callable by all signed origins
    • MUST use Instruction::DescendOrigin(who) before the Instruction::Transact
  • Method Parameters
    origin: OriginFor<T>,
    // NOTE: Currency taken from out chain and send to the other chain
    currency_id: T::CurrencyId,
    amount: T::Balance,
    // NOTE: Receiver of the tokens
    remote_dest: Box<VersionedMultiLocation>,
    remote_transact: RemoteTransact<T>,
    // NOTE: Type used for defining how much the user wants 
    //       to pay at most on the receiving side for the execution.
    dest_weight_limit: WeightLimit,

fn remote_withdraw

:::info
💡 An extrinsics allows to withdraw funds from the origins remote account on another chain and sends it to Centrifuge/or possibly any other chain
:::

  • Logical Requirements
    • Callable by all signed origins
    • MUST use Instruction::DescendOrigin(who) before the XCM Transfer in order to take tokens out of the remote account holdings.
  • Method Parameters
    origin: OriginFor<T>,
    // NOTE: Currency taken from out chain and send to the other chain
    currency_id: T::CurrencyId,
    amount: T::Balance,
    // NOTE: Receiver of the tokens
    remote_dest: Box<VersionedMultiLocation>,
    // NOTE: Type used for defining how much the user wants 
    //       to pay at most on the receiving side for the execution.
    dest_weight_limit: WeightLimit,

🔗 Links

@mustermeiszer
Copy link
Contributor

Closing as we will have a new onramping flow that will be easier in handling that as we can use a simple transfer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants