Files
pezkuwi-fellows/stale/0011-add-new-path-to-account-creation-on-asset-hubs.html
T
2024-01-15 00:55:24 +00:00

393 lines
26 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="polkadot" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>RFC-0011: Add New Path to Account Creation on Asset Hubs - Polkadot Fellowship RFCs</title>
<!-- Custom HTML head -->
<meta name="description" content="An online book of RFCs approved or proposed within the Polkadot Fellowship.">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../favicon.svg">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<link rel="stylesheet" href="../theme/polkadot.css">
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "polkadot" : "polkadot";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('polkadot')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="../introduction.html">Introduction</a></li><li class="spacer"></li><li class="chapter-item expanded affix "><li class="part-title">Approved</li><li class="chapter-item expanded "><a href="../approved/0001-agile-coretime.html">RFC-1: Agile Coretime</a></li><li class="chapter-item expanded "><a href="../approved/0005-coretime-interface.html">RFC-5: Coretime Interface</a></li><li class="chapter-item expanded "><a href="../approved/0007-system-collator-selection.html">RFC-0007: System Collator Selection</a></li><li class="chapter-item expanded "><a href="../approved/0008-parachain-bootnodes-dht.html">RFC-0008: Store parachain bootnodes in relay chain DHT</a></li><li class="chapter-item expanded "><a href="../approved/0012-process-for-adding-new-collectives.html">RFC-0012: Process for Adding New System Collectives</a></li><li class="chapter-item expanded "><a href="../approved/0014-improve-locking-mechanism-for-parachains.html">RFC-0014: Improve locking mechanism for parachains</a></li><li class="chapter-item expanded "><a href="../approved/0022-adopt-encointer-runtime.html">RFC-0022: Adopt Encointer Runtime</a></li><li class="chapter-item expanded "><a href="../approved/0032-minimal-relay.html">RFC-0032: Minimal Relay</a></li><li class="chapter-item expanded "><a href="../approved/0050-fellowship-salaries.html">RFC-0050: Fellowship Salaries</a></li><li class="chapter-item expanded "><a href="../approved/0056-one-transaction-per-notification.html">RFC-0056: Enforce only one transaction per notification</a></li><li class="spacer"></li><li class="chapter-item expanded affix "><li class="part-title">Newly Proposed</li><li class="chapter-item expanded "><a href="../new/0066-add-smartcontracts-to-assethub.html">RFC-0066: Add EVM+ink! Contracts Pallets to Asset Hub for Polkadot</a></li><li class="spacer"></li><li class="chapter-item expanded affix "><li class="part-title">Proposed</li><li class="chapter-item expanded "><a href="../proposed/000x-lowering-deposits-assethub.html">RFC-0000: Lowering NFT Deposits on Polkadot and Kusama Asset Hubs</a></li><li class="chapter-item expanded "><a href="../proposed/0026-sassafras-consensus.html">RFC-0026: Sassafras Consensus Protocol</a></li><li class="chapter-item expanded "><a href="../proposed/0034-xcm-absolute-location-account-derivation.html">RFC-34: XCM Absolute Location Account Derivation</a></li><li class="chapter-item expanded "><a href="../proposed/0044-rent-based-registration.html">RFC-0044: Rent based registration model</a></li><li class="chapter-item expanded "><a href="../proposed/0046-metadata-for-offline-signers.html">RFC-0000: Metadata for offline signers</a></li><li class="chapter-item expanded "><a href="../proposed/0047-assignment-of-availability-chunks.html">RFC-0047: Assignment of availability chunks to validators</a></li><li class="chapter-item expanded "><a href="../proposed/0059-nodes-capabilities-discovery.html">RFC-0059: Add a discovery mechanism for nodes based on their capabilities</a></li><li class="chapter-item expanded "><a href="../proposed/0061-allocator-inside-of-runtime.html">RFC-0061: Support allocator inside of runtime</a></li><li class="spacer"></li><li class="chapter-item expanded affix "><li class="part-title">Stale</li><li class="chapter-item expanded "><a href="../stale/0004-remove-unnecessary-allocator-usage.html">RFC-0004: Remove the host-side runtime memory allocator</a></li><li class="chapter-item expanded "><a href="../stale/0006-dynamic-pricing-for-bulk-coretime-sales.html">RFC-0006: Dynamic Pricing for Bulk Coretime Sales</a></li><li class="chapter-item expanded "><a href="../stale/0009-improved-net-light-client-requests.html">RFC-0009: Improved light client requests networking protocol</a></li><li class="chapter-item expanded "><a href="../stale/0010-burn-coretime-revenue.html">RFC-0010: Burn Coretime Revenue</a></li><li class="chapter-item expanded "><a href="../stale/0011-add-new-path-to-account-creation-on-asset-hubs.html" class="active">RFC-0011: Add New Path to Account Creation on Asset Hubs</a></li><li class="chapter-item expanded "><a href="../stale/0013-prepare-blockbuilder-and-core-runtime-apis-for-mbms.html">RFC-0013: Prepare BlockBuilder and Core runtime APIs for MBMs</a></li><li class="chapter-item expanded "><a href="../stale/0015-market-design-revisit.html">RFC-0015: Market Design Revisit</a></li><li class="chapter-item expanded "><a href="../stale/0020-treasurer-track-confirmation-period-duration-modification.html">RFC-0020: Treasurer Track Confirmation Period Duration Modification</a></li><li class="chapter-item expanded "><a href="../stale/0035-conviction-voting-delegation-modifications.html"> RFC-0035: Conviction Voting Delegation Modifications</a></li><li class="chapter-item expanded "><a href="../stale/0042-extrinsics-state-version.html">RFC-0042: Add System version that replaces StateVersion on RuntimeVersion</a></li><li class="chapter-item expanded "><a href="../stale/0043-storage-proof-size-hostfunction.html">RFC-0043: Introduce storage_proof_size Host Function for Improved Parachain Block Utilization</a></li><li class="chapter-item expanded "><a href="../stale/0048-session-keys-runtime-api.html">RFC-0048: Generate ownership proof for SessionKeys</a></li><li class="chapter-item expanded "><a href="../stale/0054-remove-heap-pages.html">RFC-0054: Remove the concept of "heap pages" from the client</a></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="polkadot">Polkadot</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Polkadot Fellowship RFCs</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<p><a href="https://github.com/polkadot-fellows/RFCs/pull/11">(source)</a></p>
<p><strong>Table of Contents</strong></p>
<ul>
<li><a href="#rfc-0011-add-new-path-to-account-creation-on-asset-hubs">RFC-0011: Add New Path to Account Creation on Asset Hubs</a>
<ul>
<li><a href="#summary">Summary</a></li>
<li><a href="#motivation">Motivation</a>
<ul>
<li><a href="#requirements">Requirements</a></li>
</ul>
</li>
<li><a href="#stakeholders">Stakeholders</a></li>
<li><a href="#explanation">Explanation</a></li>
<li><a href="#drawbacks">Drawbacks</a></li>
<li><a href="#testing-security-and-privacy">Testing, Security, and Privacy</a></li>
<li><a href="#performance-ergonomics-and-compatibility">Performance, Ergonomics, and Compatibility</a>
<ul>
<li><a href="#performance">Performance</a></li>
<li><a href="#ergonomics">Ergonomics</a></li>
<li><a href="#compatibility">Compatibility</a></li>
</ul>
</li>
<li><a href="#prior-art-and-references">Prior Art and References</a></li>
<li><a href="#unresolved-questions">Unresolved Questions</a></li>
<li><a href="#future-directions-and-related-material">Future Directions and Related Material</a></li>
</ul>
</li>
</ul>
<h1 id="rfc-0011-add-new-path-to-account-creation-on-asset-hubs"><a class="header" href="#rfc-0011-add-new-path-to-account-creation-on-asset-hubs">RFC-0011: Add New Path to Account Creation on Asset Hubs</a></h1>
<div class="table-wrapper"><table><thead><tr><th></th><th></th></tr></thead><tbody>
<tr><td><strong>Start Date</strong></td><td>19 July 2023</td></tr>
<tr><td><strong>Description</strong></td><td>Proposal for a new secure means of creating an account on Asset Hub.</td></tr>
<tr><td><strong>Authors</strong></td><td>Joe Petrowski</td></tr>
</tbody></table>
</div>
<h2 id="summary"><a class="header" href="#summary">Summary</a></h2>
<p>The Assets pallet includes a notion of asset &quot;sufficiency&quot;. Sufficient assets, when transferred to
a non-existent account, will provide a sufficient reference that creates the account. That is, the
asset is <em>sufficient</em> to justify an account's existence, even in lieu of the existential deposit of
DOT.</p>
<p>While convenient for sufficient assets, the vast majority of assets are not sufficient. This RFC
proposes an opt-in means for users to create accounts from non-sufficient assets by swapping a
portion of the first transfer to acquire the existential deposit of DOT.</p>
<h2 id="motivation"><a class="header" href="#motivation">Motivation</a></h2>
<p>The network can make an asset &quot;sufficient&quot; via governance call. However, the network is still
placing trust in the asset's administrator (which may be a third-party account or a protocol). The
asset's administrator could mint the asset and create many accounts without paying an adequate
storage deposit. For this reason, governance has been extremely strict in granting sufficiency, so
far only doing so to one asset (USDT).</p>
<p>With the introduction of the Asset Conversion pallet, the Asset Hub can offer a new path to account
creation. The current paths are:</p>
<ol>
<li>An account can have the existential deposit of DOT;</li>
<li>An account can have the minimum balance of a sufficient asset;</li>
<li>Someone else can create an account in the context of an asset class by placing a deposit in DOT.
This path is only available to the asset class's <code>Admin</code> or <code>Freezer</code>.</li>
</ol>
<p>This RFC proposes a fourth path that does not introduce prior steps for either the sender or
receiver of the asset.</p>
<h3 id="requirements"><a class="header" href="#requirements">Requirements</a></h3>
<ul>
<li>The system MUST be secure against economic attacks that allow an attacker to create a virtually
unlimited number of accounts.</li>
<li>The system SHOULD allow users to hold and transact in any asset without <em>separately and priorly</em>
acquiring DOT.</li>
</ul>
<h2 id="stakeholders"><a class="header" href="#stakeholders">Stakeholders</a></h2>
<ul>
<li>Polkadot users</li>
<li>Wallet and UI/UX developers</li>
</ul>
<h2 id="explanation"><a class="header" href="#explanation">Explanation</a></h2>
<p>By using the Asset Conversion protocol, the system can convert any asset to DOT as long as there is
a path from that asset to DOT. As such, we can rely on the economic security provided by the
existential deposit of DOT by simply converting some amount of the asset being transferred to the
existential deposit.</p>
<p>This conversion only need happen when the account does not yet exist. When the destination account
does exist, the full amount of the asset can be transferred. This would mean that only the first
asset transfer to an account has some amount debited to acquire the DOT to create the account, but
subsequent transfers would always be in full.</p>
<p>The main benefit of this approach is that it removes the sender's need to know about the
desination's existence and the recipient's need to &quot;prepare&quot; an account by endowing it.</p>
<p>The primary tradeoff, of course, is that transactions like &quot;send 10 USDT&quot; could result in fewer
than 10 USDT arriving in the destination account. This can be solved by having the conversion be
opt-in for the sender.</p>
<p>Because the existential deposit is small (0.1 DOT on Asset Hub), and the user need not interact
with the DOT in any way -- because transaction fee payment can also be handled via Asset Conversion
-- many users may find this path convenient in avoiding transfer errors due to non-existent
accounts or asset insufficiency.</p>
<p>Stripping out all other asset transfer-associated logic, this RFC proposes the following logic:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn transfer(
origin: OriginFor,
asset: AssetId,
destination: AccountId,
amount: Balance,
create_destination: bool,
..
) -&gt; DispatchResult {
let from = ensure_signed(origin)?;
let details = Asset::&lt;T, I&gt;::get(&amp;id).ok_or(Error::&lt;T, I&gt;::Unknown)?;
if destination.exists() || !create_destination || details.sufficient {
// Either the destination already exists (holds ED of DOT), the user does not want to create
// the destination account, or the asset class is sufficient. We can just transfer the
// asset as normal.
Self::do_transfer(asset, from, destination, amount, ..)?;
} else {
// The destination does not exist and the user has opted in to create it via a swap.
//
// We will try to swap the asset provided for the existential deposit, depositing the ED in
// the destination account. If the asset does not have an Asset Conversion pair with DOT or
// the asset amount isn't enough to acquire the existential deposit, this will fail. But we
// generally think (a) pairs will exist, and (b) the ED is small and UIs can easily verify
// that this should succeed, so failures should be rare.
//
// The swap returns the amount of the asset consumed to acquire the ED.
let consumed = Swap::swap_tokens_for_exact_tokens(
from, // sender
vec![asset, dot], // path, where `dot` is Multilocation {parents: 1, interior: Here}
existential_deposit, // amount_out, we need the ED for the account
destination, // send_to
..
)?;
// We used some asset for the swap, so we have to subtract that from the amount.
let remaining_asset_amount = amount.saturating_sub(consumed);
// Now we transfer whatever amount is left, knowing that the destination account exists.
// This could still fail if the remaining amount is less than the minimum balance required
// by the asset class.
Self::do_transfer(asset, from, destination, remaining_asset_amount, ..)?;
}
}
<span class="boring">}</span></code></pre></pre>
<h2 id="drawbacks"><a class="header" href="#drawbacks">Drawbacks</a></h2>
<p>This solution would automatically convert some amount of another asset to DOT when acquiring DOT
was perhaps not the recipient's intent. However, this is opt-in.</p>
<h2 id="testing-security-and-privacy"><a class="header" href="#testing-security-and-privacy">Testing, Security, and Privacy</a></h2>
<p>An attacker that wanted to bloat state by sending worthless assets to many new accounts would need
to put the DOT into an Asset Conversion pool with the asset (thereby making the asset <em>not</em>
worthless with respect to DOT). This would provide the same cost and economic security as just
sending the existential deposit of DOT to all the new accounts. This approach is no less secure
than the DOT-only existential deposit system.</p>
<p>This proposal introduces no privacy enhancements or reductions.</p>
<h2 id="performance-ergonomics-and-compatibility"><a class="header" href="#performance-ergonomics-and-compatibility">Performance, Ergonomics, and Compatibility</a></h2>
<h3 id="performance"><a class="header" href="#performance">Performance</a></h3>
<p>The function to transfer assets will need to charge a larger weight at dispatch to account for the
possibility of needing to perform a swap for DOT. It could return any unused weight.</p>
<p>The implementation could also include witness data as to the destination account's existence so
that the block builder can appropriately budget for the weight.</p>
<h3 id="ergonomics"><a class="header" href="#ergonomics">Ergonomics</a></h3>
<p>This proposal would benefit the ergonomics of the system for end users by allowing all assets to
create destination accounts when needed.</p>
<h3 id="compatibility"><a class="header" href="#compatibility">Compatibility</a></h3>
<p>This change would require changes to the Assets pallet to add the new account creation path.</p>
<h2 id="prior-art-and-references"><a class="header" href="#prior-art-and-references">Prior Art and References</a></h2>
<p>Discussions with:</p>
<ul>
<li>SR Labs auditors, in particular Jakob Lell and Louis Merlin</li>
<li>The monthly Asset Conversion ecosystem call, particular inspiration from Jakub Gregus</li>
</ul>
<h2 id="unresolved-questions"><a class="header" href="#unresolved-questions">Unresolved Questions</a></h2>
<p>None at this time.</p>
<h2 id="future-directions-and-related-material"><a class="header" href="#future-directions-and-related-material">Future Directions and Related Material</a></h2>
<p>Not applicable.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../stale/0010-burn-coretime-revenue.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../stale/0013-prepare-blockbuilder-and-core-runtime-apis-for-mbms.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../stale/0010-burn-coretime-revenue.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../stale/0013-prepare-blockbuilder-and-core-runtime-apis-for-mbms.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>