Polyfills, Shims, and Native Modules: Lessons from Building a React Native Crypto Wallet
Preface: This article is about my experience building a crypto mobile wallet back in 2021. Intro Building a crypto wallet in React Native is a masterclass in edge-case architecture. Unlike standard mobile applications that simply fetch JSON from a REST API, a crypto wallet acts as an isolated cryptographic engine. It must generate entropy, derive keys, sign transactions, encode raw binary…
This article recounts the author's experience designing a crypto wallet application using React Native back in 2021. Creating a crypto wallet within React Native presents a unique challenge due to the nature of the application. Unlike traditional mobile apps that simply retrieve data from a REST API, a crypto wallet functions as an isolated cryptographic engine. Its responsibilities encompass generating entropy, deriving keys, signing transactions, encoding binary data, and engaging with decentralized networks.
When attempting to incorporate standard Web3 JavaScript libraries into a React Native environment, developers encounter a significant discrepancy. Most Web3 packages are developed with the assumption of either a Node.js runtime or a web browser environment. However, React Native's JavaScript engine, Hermes or JavaScriptCore, lacks these capabilities.
Consequently, building a mobile crypto wallet necessitates mastering three primary strategies: Polyfilling, Shimming, and Native Modules. Each strategy plays a crucial role in the wallet's architecture, when to employ them, and the evolution of the ecosystem.
Polyfilling involves restoring missing Web standards. It detects if a standard Web API exists within the JavaScript runtime. If absent, it dynamically incorporates a spec-compliant JS implementation into the global scope. In a wallet context, Web3 SDKs such as Ethers.js, Viem, or WalletConnect heavily depend on browser primitives for RPC formatting, address validation, and entropy generation. Without polyfills, functions relying on URL or TextEncoder would fail immediately.
Shimming, on the other hand, entails adapting Node.js ecosystem dependencies. This process intercepts API calls to either wrap, adapt, or alias non-standard environments, specifically Node.js built-ins, so they can operate within React Native. Core crypto primitives like bip39, ethereumjs-util, bs58, and hdkey were originally designed for Node.js.
They rely on built-ins such as Buffer, stream, and crypto. However, Metro, React Native's bundler, does not typically resolve these modules by default. Thus, shims and bundler aliases are required to map these Node-builtins to React Native-compatible browser/JS polyfill packages.
Lastly, Native Modules (TurboModules / JSI) pertain to the development of native code, utilizing Swift/Objective-C on iOS, Kotlin/Java on Android, or C++ via JSI. Native Modules expose native capabilities, security hardware, or compiled C/C++ libraries to JavaScript. In the context of a crypto wallet, relying solely on a JavaScript engine to handle heavy cryptographic routines can strain the single-threaded event loop, leading to suboptimal performance.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.