<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Julien Béranger</title>
    <description>The latest articles on DEV Community by Julien Béranger (@julienbrg).</description>
    <link>https://dev.to/julienbrg</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F836545%2Fb4258c1e-10a3-45a7-8e6a-dccfaa1df468.jpeg</url>
      <title>DEV Community: Julien Béranger</title>
      <link>https://dev.to/julienbrg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/julienbrg"/>
    <language>en</language>
    <item>
      <title>Getting Started with Genji: A Web3 App Starter with Passkey Authentication</title>
      <dc:creator>Julien Béranger</dc:creator>
      <pubDate>Tue, 03 Mar 2026 11:50:46 +0000</pubDate>
      <link>https://dev.to/julienbrg/getting-started-with-genji-your-web3-adventure-begins-here-3oec</link>
      <guid>https://dev.to/julienbrg/getting-started-with-genji-your-web3-adventure-begins-here-3oec</guid>
      <description>&lt;p&gt;Hello Anon!&lt;/p&gt;

&lt;p&gt;Genji is a Next.js starter template that makes it easy to build Web3 apps with passkey authentication. This template gives you a production-ready foundation that handles security and accessibility while keeping user privacy front and center.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in it?
&lt;/h2&gt;

&lt;p&gt;Genji integrates the following technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://w3pk.w3hc.org/" rel="noopener noreferrer"&gt;w3pk&lt;/a&gt;&lt;/strong&gt; — Passkey authentication framework&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;&lt;/strong&gt; — React framework for production apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://docs.ethers.org/" rel="noopener noreferrer"&gt;Ethers&lt;/a&gt;&lt;/strong&gt; — Web3 library for blockchain interaction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://chakra-ui.com/" rel="noopener noreferrer"&gt;Chakra UI&lt;/a&gt;&lt;/strong&gt; — Component library for user interface&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WCAG 2.1 AA compliance&lt;/strong&gt; — Ensures accessibility for everyone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out the live demo at &lt;a href="https://genji.w3hc.org" rel="noopener noreferrer"&gt;https://genji.w3hc.org&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Privacy-Friendly Architecture
&lt;/h2&gt;

&lt;p&gt;Genji takes a privacy-first approach to authentication:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No password storage&lt;/strong&gt;: Passkeys eliminate the need for password databases, removing a common attack vector&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Device-bound credentials&lt;/strong&gt;: Authentication credentials stay on the user's device and are never sent to servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No tracking&lt;/strong&gt;: No need for email addresses, phone numbers, or other personally identifiable information&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User control&lt;/strong&gt;: Users stay in full control of their credentials and can revoke access anytime&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal data collection&lt;/strong&gt;: The app only stores the public key for each account, keeping things private while staying secure&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation and Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Create Your Repository
&lt;/h3&gt;

&lt;p&gt;To create your own instance of the Genji template:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Head to the &lt;a href="https://github.com/w3hc/genji-passkey" rel="noopener noreferrer"&gt;Genji GitHub repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click "Use this template" to create a new repository&lt;/li&gt;
&lt;li&gt;Give your repository a name&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: Customize the Template
&lt;/h3&gt;

&lt;p&gt;After cloning your repository, run the customization script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm customize
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove default Genji branding&lt;/li&gt;
&lt;li&gt;Set up project-specific configurations&lt;/li&gt;
&lt;li&gt;Self-destruct when it's done&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: Install Dependencies
&lt;/h3&gt;

&lt;p&gt;Install the required packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Start the Development Server
&lt;/h3&gt;

&lt;p&gt;Fire up the dev server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your app will be running at &lt;code&gt;http://localhost:3000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now log in and try signing a message on the homepage. Once you're logged in, you don't need to confirm anything to sign the message: w3pk handles it seamlessly using your passkey-derived wallet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Configure Security Level
&lt;/h3&gt;

&lt;p&gt;w3pk offers four security levels for passkey authentication. We recommend &lt;strong&gt;STANDARD&lt;/strong&gt;, which balances security and user experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PRIMARY&lt;/strong&gt;: Requires authentication for every single action, including transaction confirmations. Maximum security but requires the most user interaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;STRICT&lt;/strong&gt;: Requires authentication for most operations. Good for high-security apps where user inconvenience is acceptable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;STANDARD&lt;/strong&gt; (recommended): Requires authentication for login but keeps the session active for what comes next. Users don't need to re-authenticate for each transaction. This gives you the best balance between security and usability for most apps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YOLO&lt;/strong&gt;: Minimal authentication requirements. Only for development or low-stakes apps where security isn't a primary concern.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;STANDARD is recommended because it cuts out repeated authentication while keeping solid security controls. Users can interact with your app smoothly without compromising account security.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are a few app examples &lt;a href="https://w3pk.w3hc.org/examples" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you need some inspiration. Genji can be used for all kinds of apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Passkey Authentication
&lt;/h2&gt;

&lt;p&gt;Passkeys are a modern authentication standard that use device-level security like biometric sensors (Face ID, fingerprint) or device PINs. This approach gets rid of traditional password management and seed phrase storage. The authentication process relies on public-key cryptography, where the private key stays securely on the user's device and is never transmitted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: Check out the &lt;code&gt;/docs&lt;/code&gt; folder for implementation context and design guidelines&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build Verification&lt;/strong&gt;: Set up &lt;a href="https://w3pk.w3hc.org/docs#build-verification" rel="noopener noreferrer"&gt;w3pk build verification&lt;/a&gt; to ensure code integrity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Inspection&lt;/strong&gt;: Enable &lt;a href="https://w3pk.w3hc.org/docs#security-inspection" rel="noopener noreferrer"&gt;security inspection&lt;/a&gt; so your users can verify what's happening in your app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: Keep WCAG 2.1 AA compliance throughout development&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Support and Resources
&lt;/h2&gt;

&lt;p&gt;Need help?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Submit issues on the &lt;a href="https://github.com/w3hc/genji-passkey" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Check the complete &lt;a href="https://w3pk.w3hc.org/docs" rel="noopener noreferrer"&gt;w3pk docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Contact &lt;a href="https://julienberanger.com/contact" rel="noopener noreferrer"&gt;Julien&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You now have everything you need to build Web3 apps using the Genji template with passkey authentication. The template gives you a privacy-focused, accessible, and secure foundation for building modern decentralized apps.&lt;/p&gt;

</description>
      <category>w3pk</category>
      <category>web3</category>
      <category>passkey</category>
      <category>ethereum</category>
    </item>
    <item>
      <title>Deploy a Next.js app to an Infomaniak Ubuntu VPS</title>
      <dc:creator>Julien Béranger</dc:creator>
      <pubDate>Mon, 20 Oct 2025 12:51:06 +0000</pubDate>
      <link>https://dev.to/julienbrg/deploy-a-nextjs-app-to-an-infomaniak-ubuntu-vps-2nod</link>
      <guid>https://dev.to/julienbrg/deploy-a-nextjs-app-to-an-infomaniak-ubuntu-vps-2nod</guid>
      <description>&lt;p&gt;This guide walks you through deploying a Next.js application to an Infomaniak Ubuntu VPS with automatic CI/CD using GitHub Actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A domain name with DNS access&lt;/li&gt;
&lt;li&gt;A GitHub account&lt;/li&gt;
&lt;li&gt;VS Code installed on your local machine (for remote development)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  0. Order Your Infomaniak VPS
&lt;/h2&gt;

&lt;h3&gt;
  
  
  0.1 Choose Your Plan
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://shop.infomaniak.com/order/select/vps_only" rel="noopener noreferrer"&gt;Infomaniak VPS Order Page&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recommended plan&lt;/strong&gt;: VPS Start at &lt;strong&gt;3.60 € / month&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;1 vCore&lt;/li&gt;
&lt;li&gt;2 GB RAM&lt;/li&gt;
&lt;li&gt;20 GB SSD&lt;/li&gt;
&lt;li&gt;Perfect for small to medium Next.js applications&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  0.2 VPS Configuration
&lt;/h3&gt;

&lt;p&gt;During the order process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Operating System&lt;/strong&gt;: Select &lt;strong&gt;Ubuntu 24.04 LTS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Datacenter&lt;/strong&gt;: Choose the location closest to your users (Geneva or Zurich recommended)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSH Key&lt;/strong&gt; (optional but recommended): Add your public SSH key for secure access&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hostname&lt;/strong&gt;: Give your VPS a meaningful name (e.g., &lt;code&gt;my-nextjs-app&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  0.3 Complete Your Order
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Review your configuration&lt;/li&gt;
&lt;li&gt;Complete the payment process&lt;/li&gt;
&lt;li&gt;You'll receive an email with:

&lt;ul&gt;
&lt;li&gt;VPS IP address&lt;/li&gt;
&lt;li&gt;Root password (if you didn't add an SSH key)&lt;/li&gt;
&lt;li&gt;Access to Infomaniak Manager&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  0.4 Access Infomaniak Manager
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Log in to &lt;a href="https://manager.infomaniak.com" rel="noopener noreferrer"&gt;manager.infomaniak.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Web &amp;amp; Domain&lt;/strong&gt; → &lt;strong&gt;VPS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select your newly created VPS&lt;/li&gt;
&lt;li&gt;Note your VPS IP address (you'll need it throughout this guide)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Infomaniak Firewall Configuration
&lt;/h2&gt;

&lt;p&gt;Before connecting to your VPS, configure the firewall in the Infomaniak Manager interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 Access Firewall Settings
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In Infomaniak Manager, go to your VPS&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;Firewall&lt;/strong&gt; in the left sidebar&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add Rule&lt;/strong&gt; to create new firewall rules&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1.2 Required Firewall Rules
&lt;/h3&gt;

&lt;p&gt;Create the following rules (in this order):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 1: SSH Access&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Protocol&lt;/strong&gt;: TCP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port&lt;/strong&gt;: 22&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source&lt;/strong&gt;: Your IP address (or 0.0.0.0/0 for access from anywhere)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action&lt;/strong&gt;: Accept&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt;: SSH access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rule 2: HTTP Access&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Protocol&lt;/strong&gt;: TCP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port&lt;/strong&gt;: 80&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source&lt;/strong&gt;: 0.0.0.0/0 (anywhere)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action&lt;/strong&gt;: Accept&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt;: HTTP traffic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rule 3: HTTPS Access&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Protocol&lt;/strong&gt;: TCP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port&lt;/strong&gt;: 443&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source&lt;/strong&gt;: 0.0.0.0/0 (anywhere)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action&lt;/strong&gt;: Accept&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt;: HTTPS traffic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rule 4: Ping/ICMP (optional)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Protocol&lt;/strong&gt;: ICMP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source&lt;/strong&gt;: 0.0.0.0/0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action&lt;/strong&gt;: Accept&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt;: Ping requests&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1.3 Verify Firewall Status
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ensure the firewall is &lt;strong&gt;Enabled&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Rules should be listed in order&lt;/li&gt;
&lt;li&gt;Save your configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The Infomaniak firewall works at the network level before your VPS. You'll also configure UFW (Ubuntu's firewall) later for an additional layer of security.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. VS Code SSH Configuration
&lt;/h2&gt;

&lt;p&gt;Configure VS Code for remote development on your VPS.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Install Remote SSH Extension
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open VS Code&lt;/li&gt;
&lt;li&gt;Go to Extensions (Ctrl+Shift+X or Cmd+Shift+X)&lt;/li&gt;
&lt;li&gt;Search for "Remote - SSH"&lt;/li&gt;
&lt;li&gt;Install the extension by Microsoft&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2.2 Generate SSH Key (if you don't have one)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;On macOS/Linux:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"your-email@example.com"&lt;/span&gt;
&lt;span class="c"&gt;# Press Enter to accept default location (~/.ssh/id_ed25519)&lt;/span&gt;
&lt;span class="c"&gt;# Set a passphrase (optional but recommended)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;On Windows (PowerShell):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ssh-keygen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ed25519&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-C&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-email@example.com"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# Press Enter to accept default location&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.3 Copy SSH Key to VPS
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;First-time connection:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-copy-id your-username@your-vps-ip
&lt;span class="c"&gt;# Enter the password provided by Infomaniak&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Alternative method (if ssh-copy-id is not available):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Display your public key&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_ed25519.pub

&lt;span class="c"&gt;# Then manually add it to your VPS:&lt;/span&gt;
ssh your-username@your-vps-ip
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.ssh
nano ~/.ssh/authorized_keys
&lt;span class="c"&gt;# Paste your public key, save and exit&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 ~/.ssh
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 ~/.ssh/authorized_keys
&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.4 Configure VS Code SSH
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In VS Code, press &lt;code&gt;Ctrl+Shift+P&lt;/code&gt; (or &lt;code&gt;Cmd+Shift+P&lt;/code&gt; on macOS)&lt;/li&gt;
&lt;li&gt;Type "Remote-SSH: Open SSH Configuration File"&lt;/li&gt;
&lt;li&gt;Select your SSH config file (usually &lt;code&gt;~/.ssh/config&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Add this configuration:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host infomaniak-vps
    HostName your-vps-ip
    User your-username
    Port 22
    IdentityFile ~/.ssh/id_ed25519
    ServerAliveInterval 60
    ServerAliveCountMax 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;your-vps-ip&lt;/code&gt; with your actual VPS IP address&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;your-username&lt;/code&gt; with your VPS username&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.5 Connect to VPS from VS Code
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Press &lt;code&gt;Ctrl+Shift+P&lt;/code&gt; (or &lt;code&gt;Cmd+Shift+P&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Type "Remote-SSH: Connect to Host"&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;infomaniak-vps&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;VS Code will open a new window connected to your VPS&lt;/li&gt;
&lt;li&gt;You can now browse files and use the integrated terminal&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2.6 VS Code Tips for Remote Development
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open folder&lt;/strong&gt;: Click "Open Folder" and select &lt;code&gt;~/w3pk-playground&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terminal&lt;/strong&gt;: Use &lt;code&gt;Ctrl+&lt;/code&gt; to open integrated terminal&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensions&lt;/strong&gt;: Install extensions on the remote server (Node.js, ESLint, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port forwarding&lt;/strong&gt;: VS Code automatically forwards ports - useful for testing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Fork the Repository
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://github.com/w3hc/w3pk-playground" rel="noopener noreferrer"&gt;https://github.com/w3hc/w3pk-playground&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Fork&lt;/strong&gt; button in the top right&lt;/li&gt;
&lt;li&gt;Clone your forked repository to your local machine:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/YOUR_USERNAME/w3pk-playground.git
&lt;span class="nb"&gt;cd &lt;/span&gt;w3pk-playground
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. VPS Initial Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Connect to your VPS
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Via VS Code (recommended):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the Remote-SSH connection you configured above&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Via terminal:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh your-username@your-vps-ip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2 Update System
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.3 Install Node.js via NVM
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install NVM&lt;/span&gt;
curl &lt;span class="nt"&gt;-o-&lt;/span&gt; https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

&lt;span class="c"&gt;# Reload shell configuration&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc

&lt;span class="c"&gt;# Install Node.js (latest LTS)&lt;/span&gt;
nvm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--lts&lt;/span&gt;

&lt;span class="c"&gt;# Verify installation&lt;/span&gt;
node &lt;span class="nt"&gt;-v&lt;/span&gt;
npm &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.4 Install pnpm
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; pnpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.5 Install PM2 (Process Manager)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add &lt;span class="nt"&gt;-g&lt;/span&gt; pm2

&lt;span class="c"&gt;# Setup PM2 to start on system reboot&lt;/span&gt;
pm2 startup
&lt;span class="c"&gt;# Follow the instructions provided by the command&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.6 Clone your repository on the VPS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~
git clone https://github.com/YOUR_USERNAME/w3pk-playground.git
&lt;span class="nb"&gt;cd &lt;/span&gt;w3pk-playground
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.7 Install dependencies and build
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.8 Start the app with PM2
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pm2 start pnpm &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"your-app-name"&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; start
pm2 save
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify it's running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pm2 list
pm2 logs your-app-name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Domain and DNS Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 Configure DNS
&lt;/h3&gt;

&lt;p&gt;In your domain provider's DNS settings (e.g., Infomaniak DNS panel):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add an &lt;strong&gt;A Record&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: &lt;code&gt;subdomain&lt;/code&gt; (e.g., &lt;code&gt;app&lt;/code&gt; for &lt;code&gt;app.yourdomain.com&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type&lt;/strong&gt;: A&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Value&lt;/strong&gt;: Your VPS IP address&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TTL&lt;/strong&gt;: 300 (or default)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Wait for DNS propagation (can take up to 24 hours, usually 5-15 minutes)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  7.2 Verify DNS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig subdomain.yourdomain.com +short
&lt;span class="c"&gt;# Should return your VPS IP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Nginx Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6.1 Install Nginx
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nginx &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.2 Create Nginx configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/nginx/sites-available/your-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="s"&gt;[::]:80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;subdomain.yourdomain.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_http_version&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Upgrade&lt;/span&gt; &lt;span class="nv"&gt;$http_upgrade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Connection&lt;/span&gt; &lt;span class="s"&gt;'upgrade'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt; &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_cache_bypass&lt;/span&gt; &lt;span class="nv"&gt;$http_upgrade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6.3 Enable the site
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create symbolic link&lt;/span&gt;
&lt;span class="nb"&gt;sudo ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /etc/nginx/sites-available/your-app /etc/nginx/sites-enabled/

&lt;span class="c"&gt;# Test configuration&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;

&lt;span class="c"&gt;# Reload Nginx&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  7. SSL Certificate Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  7.1 Install Certbot
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;certbot python3-certbot-nginx &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7.2 Obtain SSL certificate
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot &lt;span class="nt"&gt;--nginx&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; subdomain.yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the prompts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter your email address&lt;/li&gt;
&lt;li&gt;Agree to terms of service&lt;/li&gt;
&lt;li&gt;Choose to redirect HTTP to HTTPS (recommended)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  7.3 Verify SSL certificate
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check certificate status&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot certificates

&lt;span class="c"&gt;# Test auto-renewal&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot renew &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your site should now be accessible at &lt;code&gt;https://subdomain.yourdomain.com&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8. UFW Firewall Configuration (Additional Layer)
&lt;/h2&gt;

&lt;p&gt;Configure Ubuntu's UFW firewall for additional security.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install UFW (usually pre-installed)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;ufw &lt;span class="nt"&gt;-y&lt;/span&gt;

&lt;span class="c"&gt;# Allow SSH (IMPORTANT: do this first!)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 22/tcp

&lt;span class="c"&gt;# Allow HTTP and HTTPS&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 80/tcp
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 443/tcp

&lt;span class="c"&gt;# Enable UFW&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw &lt;span class="nb"&gt;enable&lt;/span&gt;

&lt;span class="c"&gt;# Check status&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw status verbose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: Always allow SSH (port 22) before enabling UFW, or you'll lose access to your VPS!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  9. GitHub Actions CI/CD Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  9.1 Create SSH key for GitHub Actions
&lt;/h3&gt;

&lt;p&gt;On your VPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Generate SSH key WITHOUT passphrase (important!)&lt;/span&gt;
ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"github-actions"&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ~/.ssh/github-actions &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;

&lt;span class="c"&gt;# Add public key to authorized_keys&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/github-actions.pub &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.ssh/authorized_keys

&lt;span class="c"&gt;# Set correct permissions&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 ~/.ssh
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 ~/.ssh/authorized_keys
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 ~/.ssh/github-actions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9.2 Copy the private key
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/github-actions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy the entire output including &lt;code&gt;-----BEGIN&lt;/code&gt; and &lt;code&gt;-----END&lt;/code&gt; lines.&lt;/p&gt;

&lt;h3&gt;
  
  
  9.3 Create GitHub workflow file
&lt;/h3&gt;

&lt;p&gt;In your local repository, create &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to VPS&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to VPS&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;appleboy/ssh-action@v1.0.0&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VPS_HOST }}&lt;/span&gt;
          &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VPS_USERNAME }}&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VPS_SSH_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;export NVM_DIR="$HOME/.nvm"&lt;/span&gt;
            &lt;span class="s"&gt;[ -s "$NVM_DIR/nvm.sh" ] &amp;amp;&amp;amp; \. "$NVM_DIR/nvm.sh"&lt;/span&gt;
            &lt;span class="s"&gt;export PATH="$HOME/.local/share/pnpm:$PATH"&lt;/span&gt;
            &lt;span class="s"&gt;cd ~/w3pk-playground&lt;/span&gt;
            &lt;span class="s"&gt;git pull origin main&lt;/span&gt;
            &lt;span class="s"&gt;pnpm install&lt;/span&gt;
            &lt;span class="s"&gt;pnpm build&lt;/span&gt;
            &lt;span class="s"&gt;pm2 restart your-app-name&lt;/span&gt;
            &lt;span class="s"&gt;pm2 save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9.4 Add GitHub Secrets
&lt;/h3&gt;

&lt;p&gt;Go to your GitHub repository:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Settings&lt;/strong&gt; → &lt;strong&gt;Secrets and variables&lt;/strong&gt; → &lt;strong&gt;Actions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New repository secret&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Add three secrets:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;VPS_HOST&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your-vps-ip-address
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;VPS_USERNAME&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your-vps-username
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;VPS_SSH_KEY&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(paste the entire private key from ~/.ssh/github-actions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  9.5 Commit and push
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add .github/workflows/deploy.yml
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add CI/CD workflow"&lt;/span&gt;
git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  10. Test Your Deployment
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Make a change to your code&lt;/li&gt;
&lt;li&gt;Commit and push to the &lt;code&gt;main&lt;/code&gt; branch&lt;/li&gt;
&lt;li&gt;Go to your GitHub repository → &lt;strong&gt;Actions&lt;/strong&gt; tab&lt;/li&gt;
&lt;li&gt;Watch the deployment workflow run&lt;/li&gt;
&lt;li&gt;Visit &lt;code&gt;https://subdomain.yourdomain.com&lt;/code&gt; to see your changes&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Useful Commands
&lt;/h2&gt;

&lt;h3&gt;
  
  
  PM2 Management
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pm2 list                    &lt;span class="c"&gt;# List all apps&lt;/span&gt;
pm2 logs your-app-name     &lt;span class="c"&gt;# View logs&lt;/span&gt;
pm2 restart your-app-name  &lt;span class="c"&gt;# Restart app&lt;/span&gt;
pm2 stop your-app-name     &lt;span class="c"&gt;# Stop app&lt;/span&gt;
pm2 delete your-app-name   &lt;span class="c"&gt;# Remove app&lt;/span&gt;
pm2 monit                  &lt;span class="c"&gt;# Monitor all apps&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Nginx Management
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;              &lt;span class="c"&gt;# Test configuration&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload nginx &lt;span class="c"&gt;# Reload configuration&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart nginx &lt;span class="c"&gt;# Restart Nginx&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status nginx &lt;span class="c"&gt;# Check status&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SSL Certificate Management
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot certificates  &lt;span class="c"&gt;# List all certificates&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot renew        &lt;span class="c"&gt;# Renew certificates&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot delete       &lt;span class="c"&gt;# Delete a certificate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Checking Open Ports
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ss &lt;span class="nt"&gt;-tulpn&lt;/span&gt;             &lt;span class="c"&gt;# Show all listening ports&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;lsof &lt;span class="nt"&gt;-i&lt;/span&gt; :3000        &lt;span class="c"&gt;# Check specific port&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Firewall Management
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Infomaniak Firewall: Manage via Infomaniak Manager web interface&lt;/span&gt;

&lt;span class="c"&gt;# UFW Firewall&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw status verbose    &lt;span class="c"&gt;# Check UFW status&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 3000/tcp   &lt;span class="c"&gt;# Allow specific port&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw deny 3000/tcp    &lt;span class="c"&gt;# Deny specific port&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw delete allow 3000/tcp  &lt;span class="c"&gt;# Remove rule&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw reset            &lt;span class="c"&gt;# Reset all rules (careful!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cannot Connect via SSH
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Check Infomaniak firewall&lt;/strong&gt;: Ensure port 22 is allowed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check UFW&lt;/strong&gt;: Run &lt;code&gt;sudo ufw allow 22/tcp&lt;/code&gt; if you have terminal access&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Infomaniak Console&lt;/strong&gt;: Access your VPS through the web console in Infomaniak Manager&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify IP&lt;/strong&gt;: Ensure you're using the correct VPS IP address&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  502 Bad Gateway
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Check if your app is running: &lt;code&gt;pm2 list&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check app logs: &lt;code&gt;pm2 logs your-app-name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Verify the port in Nginx config matches your app's port&lt;/li&gt;
&lt;li&gt;Restart the app: &lt;code&gt;pm2 restart your-app-name&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Build Fails in CI/CD
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Check GitHub Actions logs for specific errors&lt;/li&gt;
&lt;li&gt;Verify SSH key is correct in GitHub secrets&lt;/li&gt;
&lt;li&gt;Ensure NVM and pnpm paths are correct in workflow&lt;/li&gt;
&lt;li&gt;Test commands manually on VPS first&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  SSL Certificate Issues
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Verify DNS is pointing to your VPS: &lt;code&gt;dig subdomain.yourdomain.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check if port 80 and 443 are open in both Infomaniak firewall and UFW&lt;/li&gt;
&lt;li&gt;Review Certbot logs: &lt;code&gt;sudo cat /var/log/letsencrypt/letsencrypt.log&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Permission Denied Errors
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fix SSH permissions&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;700 ~/.ssh
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 ~/.ssh/authorized_keys
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 ~/.ssh/github-actions

&lt;span class="c"&gt;# Fix file ownership&lt;/span&gt;
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; your-username:your-username ~/w3pk-playground
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Port Already in Use
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check what's using the port&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;lsof &lt;span class="nt"&gt;-i&lt;/span&gt; :3000

&lt;span class="c"&gt;# Kill the process if needed&lt;/span&gt;
&lt;span class="nb"&gt;sudo kill&lt;/span&gt; &lt;span class="nt"&gt;-9&lt;/span&gt; PID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Security Best Practices
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Two-Layer Firewall&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Infomaniak firewall (network level)&lt;/li&gt;
&lt;li&gt;UFW firewall (system level)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SSH Security&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/ssh/sshd_config
   &lt;span class="c"&gt;# Set: PasswordAuthentication no&lt;/span&gt;
   &lt;span class="c"&gt;# Set: PermitRootLogin no&lt;/span&gt;
   &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart sshd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Regular Updates&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fail2Ban&lt;/strong&gt; (optional but recommended):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;fail2ban &lt;span class="nt"&gt;-y&lt;/span&gt;
   &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;fail2ban
   &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start fail2ban
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Backups&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Infomaniak's backup service&lt;/li&gt;
&lt;li&gt;Regularly backup your application and database&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Monitoring&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check Infomaniak Manager for resource usage&lt;/li&gt;
&lt;li&gt;Monitor PM2 logs regularly&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Infomaniak-Specific Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  VPS Snapshots
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to Infomaniak Manager → Your VPS&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Snapshots&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Create snapshots before major changes&lt;/li&gt;
&lt;li&gt;Restore from snapshots if needed&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Resource Monitoring
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;View CPU, RAM, and disk usage in Infomaniak Manager&lt;/li&gt;
&lt;li&gt;Set up alerts for resource thresholds&lt;/li&gt;
&lt;li&gt;Upgrade your VPS plan if needed&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Support
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Infomaniak provides 24/7 support&lt;/li&gt;
&lt;li&gt;Access support through the Manager interface&lt;/li&gt;
&lt;li&gt;Community forum: &lt;a href="https://community.infomaniak.com" rel="noopener noreferrer"&gt;community.infomaniak.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Set up monitoring with tools like UptimeRobot&lt;/li&gt;
&lt;li&gt;Configure database backups&lt;/li&gt;
&lt;li&gt;Add staging environment&lt;/li&gt;
&lt;li&gt;Implement health checks in your workflow&lt;/li&gt;
&lt;li&gt;Set up logging with a service like Logtail or Papertrail&lt;/li&gt;
&lt;li&gt;Consider using Infomaniak's CDN for static assets&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cost Estimation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;VPS Start Plan (3.60 € / month):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Suitable for: 1-3 small Next.js apps&lt;/li&gt;
&lt;li&gt;Traffic: Up to moderate traffic levels&lt;/li&gt;
&lt;li&gt;Storage: 20 GB (sufficient for code and small databases)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to upgrade:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High traffic (&amp;gt; 10,000 monthly visitors per app)&lt;/li&gt;
&lt;li&gt;Resource-intensive applications&lt;/li&gt;
&lt;li&gt;Multiple production applications&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.infomaniak.com/en/support/faq" rel="noopener noreferrer"&gt;Infomaniak VPS Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs" rel="noopener noreferrer"&gt;Next.js Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pm2.keymetrics.io/" rel="noopener noreferrer"&gt;PM2 Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nginx.org/en/docs/" rel="noopener noreferrer"&gt;Nginx Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://letsencrypt.org/docs/" rel="noopener noreferrer"&gt;Let's Encrypt Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions" rel="noopener noreferrer"&gt;GitHub Actions Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Congratulations!&lt;/strong&gt; 🎉 Your Next.js app is now deployed on Infomaniak VPS with automatic CI/CD!&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>vp</category>
      <category>cicd</category>
    </item>
    <item>
      <title>How to deploy to Arthera Mainnet</title>
      <dc:creator>Julien Béranger</dc:creator>
      <pubDate>Fri, 01 Mar 2024 17:07:04 +0000</pubDate>
      <link>https://dev.to/julienbrg/how-to-deploy-to-arthera-mainnet-110f</link>
      <guid>https://dev.to/julienbrg/how-to-deploy-to-arthera-mainnet-110f</guid>
      <description>&lt;p&gt;Arthera Mainnet is &lt;a href="https://explorer.arthera.net"&gt;live&lt;/a&gt; and it’s time to deploy!&lt;/p&gt;

&lt;p&gt;In this tutorial, we’ll learn how to deploy your Solidity contracts to Arthera. We’ll first deploy to the Testnet, and then deploy to Arthera Mainnet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy to Testnet
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Go to the &lt;a href="https://faucet-test.arthera.net/"&gt;subscription faucet&lt;/a&gt; (Testnet), paste your wallet address there: you will get a subscription NFT, it is needed since there’s no AA (native currency of Arthera) in circulation on the network yet. You will deploy your contracts using this address &lt;strong&gt;even if the balance is zero&lt;/strong&gt;, that’s part of the magic of Arthera.&lt;/li&gt;
&lt;li&gt;Deploy your Solidity contracts using your favourite tool (Hardhat, Foundry,...) and you can check if everything went well on the &lt;a href="https://explorer-test.arthera.net/"&gt;explorer&lt;/a&gt; (Testnet). Sourcify supports Arthera, so you can verify your contracts both manually and programmatically (you can learn more about this in our docs).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, when I deployed a simple NFT contract (&lt;a href="https://github.com/artheranet/whitepaper-nft-contracts"&gt;view the source code here&lt;/a&gt;), the output looked like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6e3242ehye3y4qd53i78.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6e3242ehye3y4qd53i78.png" alt="output screenshot" width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Optional steps
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If you want to offer your users a gas-less experience, you can add these few lines of code in your contract following &lt;a href="https://docs.arthera.net/build/tutorials/use-subscriptions"&gt;this tutorial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Configure the (Testnet) SMP (Subscription Management Platform): &lt;a href="https://smp-test.arthera.net/"&gt;https://smp-test.arthera.net/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Add the checkout links to your app or website.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deploy to Mainnet
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Go to the &lt;a href="https://faucet.arthera.net/"&gt;subscription faucet&lt;/a&gt; (Mainnet) to get your subscription NFT. For more complex deployments, feel free to reach out to the team. &lt;/li&gt;
&lt;li&gt;Deploy your contracts from this address. It should be visible on the &lt;a href="https://explorer-test.arthera.net/"&gt;explorer&lt;/a&gt; (Mainnet)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Optional steps
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If you want to offer your users a gas-less experience, you can add these few lines of code in your contract following &lt;a href="https://docs.arthera.net/build/tutorials/use-subscriptions"&gt;this tutorial&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Configure the (Mainnet) SMP (Subscription Management Platform): &lt;a href="https://smp.arthera.net/"&gt;https://smp.arthera.net/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Add the checkout links to your app or website.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Congrats: &lt;strong&gt;you're on mainnet&lt;/strong&gt;! 🎉&lt;/p&gt;




&lt;p&gt;The full dev documentation for Arthera is here: &lt;strong&gt;&lt;a href="https://docs.arthera.net/"&gt;https://docs.arthera.net/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And if you need any help or have questions, feel free to contact me directly via &lt;a href="https://matrix.to/#/@julienbrg:matrix.org"&gt;Element&lt;/a&gt;, &lt;a href="https://t.me/julienbrg"&gt;Telegram&lt;/a&gt;, &lt;a href="https://twitter.com/julienbrg"&gt;Twitter&lt;/a&gt;, &lt;a href="https://discord.com/users/julienbrg"&gt;Discord&lt;/a&gt;, or &lt;a href="https://www.linkedin.com/in/julienberanger/"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>solidity</category>
      <category>web3</category>
      <category>blockchain</category>
      <category>arthera</category>
    </item>
    <item>
      <title>How to handle your Arthera Lifetime Subscription NFTs</title>
      <dc:creator>Julien Béranger</dc:creator>
      <pubDate>Tue, 21 Nov 2023 16:31:59 +0000</pubDate>
      <link>https://dev.to/julienbrg/how-to-handle-your-arthera-lifetime-subscription-nfts-db9</link>
      <guid>https://dev.to/julienbrg/how-to-handle-your-arthera-lifetime-subscription-nfts-db9</guid>
      <description>&lt;p&gt;&lt;a href="https://www.arthera.net/"&gt;Arthera&lt;/a&gt; is a Layer 1 EVM-compatible blockchain, improved by DAG-based technology. Testnet is live and Mainnet launches on December 25th 2023.&lt;/p&gt;

&lt;p&gt;With a dual model offering both pay-as-you-go and subscription options, Arthera's Lifetime Subscriptions (LTS) provide unparalleled access to our evolving ecosystem. On Arthera you subscribe and &lt;strong&gt;forget gas fees - for life&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get yours &lt;a href="https://lifetime.arthera.net/"&gt;here&lt;/a&gt;&lt;/strong&gt;, and/or create your own referral link &lt;a href="https://lifetime.arthera.net/"&gt;there&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can get your limited edition of Arthera Lifetime Subscription (LTS) on seven different networks: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Arbitrum (222)&lt;/li&gt;
&lt;li&gt;Avalanche (111)&lt;/li&gt;
&lt;li&gt;Base (111)&lt;/li&gt;
&lt;li&gt;BNB Chain (333)&lt;/li&gt;
&lt;li&gt;Ethererum (444)&lt;/li&gt;
&lt;li&gt;Optimism (111)&lt;/li&gt;
&lt;li&gt;Polygon (333)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to add your NFT to your wallet?
&lt;/h2&gt;

&lt;p&gt;The easiest way to add your NFT to your wallet is to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the explorer of the network/blockchain you selected&lt;/li&gt;
&lt;li&gt;Paste your wallet address in the search bar&lt;/li&gt;
&lt;li&gt;Find your NFT, in most of explorers there's an "NFT transfers" or "ERC721 Token Txns"&lt;/li&gt;
&lt;li&gt;Copy-paste the NFT contract address, and keep the NFT ID in mind&lt;/li&gt;
&lt;li&gt;Open MetaMask, and click on the "NFTs" tab&lt;/li&gt;
&lt;li&gt;Click on "Import NFT"&lt;/li&gt;
&lt;li&gt;Paste the NFT contract address and NFT ID&lt;/li&gt;
&lt;li&gt;Click on "confirm"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Voilà! 🎉&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcebk3l20m94pv6oe9fgo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcebk3l20m94pv6oe9fgo.png" alt="julien-LTS-NFT" width="714" height="1206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can now transfer your NFT using MetaMask wallet. &lt;/p&gt;

&lt;p&gt;If you're using any other wallet, there should be some way to add it to your wallet.&lt;/p&gt;

&lt;h2&gt;
  
  
  View your NFT
&lt;/h2&gt;

&lt;p&gt;You can also view your NFT in a lot of different NFT marketplaces depending on which network you have claimed it. &lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;In a near future, you'll be able to use this NFT to activate your lifetime subscription, forget gas fees, and make up to 30 daily transactions on Arthera at no cost at all. For Life. &lt;/p&gt;

</description>
      <category>arthera</category>
      <category>nfts</category>
      <category>subscription</category>
    </item>
    <item>
      <title>Get started with Arthera</title>
      <dc:creator>Julien Béranger</dc:creator>
      <pubDate>Tue, 17 Oct 2023 07:49:04 +0000</pubDate>
      <link>https://dev.to/julienbrg/get-started-with-arthera-3fg5</link>
      <guid>https://dev.to/julienbrg/get-started-with-arthera-3fg5</guid>
      <description>&lt;p&gt;&lt;a href="https://www.arthera.net/"&gt;Arthera&lt;/a&gt; is a new L1 in town. It's EVM-compatible, so if you're already familiar with EVM tooling and Solidity, you'll feel right X I'm at home.&lt;/p&gt;

&lt;p&gt;We just sealed a partnership with a service called &lt;a href="https://solidityscan.com/home"&gt;SolidityScan&lt;/a&gt;, and it's part of the whole security workflow we're setting up for our own system contracts. But we're also giving access to all applications building on Arthera. To date, there are already more than 80 apps committed to building on Arthera.&lt;/p&gt;

&lt;p&gt;I strongly recommend you have a look at our White Paper and &lt;a href="https://whitepaper.arthera.net/"&gt;mint the NFT&lt;/a&gt; that goes with it.&lt;/p&gt;

&lt;p&gt;If you're as lazy (efficient) as a good dev should be, or a beginner in Solidity, you can just fork this &lt;a href="https://github.com/artheranet/arthera-hardhat-template"&gt;Hardhat template&lt;/a&gt; and build what you want to build from there.&lt;/p&gt;

&lt;p&gt;Here are the &lt;a href="https://docs.arthera.net/"&gt;docs&lt;/a&gt; where you'll find answers to all your questions. Whether you're using Hardhat, Foundry, Truffle, Alchemy, Embark, or something else, you can easily add Arthera Testnet to your project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;RPC Endpoint: &lt;strong&gt;&lt;a href="https://rpc-test.arthera.net"&gt;https://rpc-test.arthera.net&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;WebSocket Endpoint (Optional): &lt;strong&gt;wss://ws-test.arthera.net&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Chain ID: &lt;strong&gt;10243&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And of course, you're invited to &lt;a href="https://t.me/artherachain"&gt;join us in Telegram&lt;/a&gt; and get in touch with us!&lt;/p&gt;

&lt;p&gt;This is our &lt;a href="https://store.arthera.net/"&gt;app store&lt;/a&gt;, feel free to submit your app &lt;a href="https://docs.google.com/forms/d/e/1FAIpQLSdEzTThOjuQwYPfS8L9Hrf3boxumolQP7lo4hySpbQPasVFsg/viewform"&gt;here&lt;/a&gt;, we'll be delighted to welcome you.&lt;/p&gt;

</description>
      <category>arthera</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>How to add Arthera subscriptions to your Solidity contracts</title>
      <dc:creator>Julien Béranger</dc:creator>
      <pubDate>Wed, 11 Oct 2023 14:12:15 +0000</pubDate>
      <link>https://dev.to/julienbrg/how-to-add-arthera-subscriptions-to-your-solidity-contracts-43do</link>
      <guid>https://dev.to/julienbrg/how-to-add-arthera-subscriptions-to-your-solidity-contracts-43do</guid>
      <description>&lt;p&gt;Forcing users to buy a handful of ETH before they can interact with your contract often makes it unpleasant for them to use your service. It's a classic issue in the crypto space and we all know this kind of friction can make your beloved users leave, never to return again.&lt;/p&gt;

&lt;p&gt;Teams like &lt;a href="https://www.biconomy.io/"&gt;Biconomy&lt;/a&gt;, &lt;a href="https://www.gelato.network/"&gt;Gelato&lt;/a&gt; and others have been working hard to create solutions that remove this friction, mainly by allowing your app to sponsor the transaction fees.&lt;/p&gt;

&lt;p&gt;On &lt;a href="https://bitpushnews.medium.com/eip-4337-will-account-abstraction-bring-mass-adoption-to-ethereum-2293c1a28137"&gt;March 1st, 2023&lt;/a&gt;, the Ethereum community collectively &lt;a href="https://eips.ethereum.org/EIPS/eip-4337"&gt;decided&lt;/a&gt; to natively support what we now call &lt;em&gt;smart wallets&lt;/em&gt; or &lt;em&gt;on-chain wallets&lt;/em&gt;, referring to account abstraction implementations. &lt;a href="https://etherspot.io/"&gt;Etherspot&lt;/a&gt;, &lt;a href="https://docs.cometh.io/connect/quickstart/what-is-connect"&gt;Cometh Connect&lt;/a&gt; or &lt;a href="https://safe.global/core"&gt;Safe&lt;/a&gt;, and several others are making it easier for devs to integrate with account abstraction to improve the UX for their own app. At &lt;a href="https://docs.arthera.net/build/intro"&gt;Arthera&lt;/a&gt; we will hopefully work with all of them. However, as Fabian Vogelsteller mentioned in a &lt;a href="https://twitter.com/lukso_io/status/1685255791777869825"&gt;recent interview&lt;/a&gt;, account abstraction can be pretty complex.&lt;/p&gt;

&lt;p&gt;Arthera's approach to fix the &lt;em&gt;classical Web3 UX issue&lt;/em&gt; is pretty straight forward. If you want to pay for your gas fees you can: we call it "pay-as-you-go" and it can be useful in some cases. But one of the key features of Arthera is the built-in subscription model where, as an individual, you can purchase a $1 USD monthly subscription and then just &lt;strong&gt;forget about gas fees&lt;/strong&gt;. Moreover, As an app provider, you can present a gas-less service to your users and that's the part I will cover in this tutorial.&lt;/p&gt;

&lt;p&gt;Enough talking for today... let’s build!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz36km0w64bx4l49uy05h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz36km0w64bx4l49uy05h.png" alt="Image description" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;When you get a subscription plan for your app, you can then whitelist your users so they can use your service even if they have zero AA (the native currency of Arthera) in their wallet.&lt;/p&gt;

&lt;p&gt;In addition to that, the SMP (&lt;a href="https://smp-dev.arthera.net/"&gt;Subscription Management Platform&lt;/a&gt;) will allow you to customise certain things, and also &lt;strong&gt;create a subscription widget that supports fiat payments&lt;/strong&gt;. This widget can be easily integrated into your app. To my knowledge this is a world first. &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1
&lt;/h3&gt;

&lt;p&gt;Go to &lt;a href="https://wallet-test.arthera.net/"&gt;Arthera Wallet UI v1&lt;/a&gt; and export the private key to your smart contract development environment (Hardhat, Foundry, etc).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2
&lt;/h3&gt;

&lt;p&gt;Add the &lt;code&gt;ISubscriptionOwner.sol&lt;/code&gt; contract interface to your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SPDX-License-Identifier: GPL-3.0&lt;/span&gt;
&lt;span class="nx"&gt;pragma&lt;/span&gt; &lt;span class="nx"&gt;solidity&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ISubscriptionOwner&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getSubscriptionOwner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;external&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="nf"&gt;returns &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: you can also directly add this contract in your contract file.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3
&lt;/h3&gt;

&lt;p&gt;Add the following imports at the top of your Solidity contract file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./ISubscriptionOwner.sol&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@openzeppelin/contracts/utils/introspection/ERC165.sol&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4
&lt;/h3&gt;

&lt;p&gt;Make your contract inherit from both &lt;code&gt;ISubscriptionOwner&lt;/code&gt; and &lt;code&gt;ERC165&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;contract&lt;/span&gt; &lt;span class="nx"&gt;YourContract&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;ISubscriptionOwner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ERC165&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5
&lt;/h3&gt;

&lt;p&gt;Add the &lt;code&gt;getSubscriptionOwner()&lt;/code&gt; and &lt;code&gt;supportsInterface()&lt;/code&gt; functions at the end of your contract:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getSubscriptionOwner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;external&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="nf"&gt;returns &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ADDRESS_OF_THE_SUBSCRIPTION_OWNER&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;supportsInterface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes4&lt;/span&gt; &lt;span class="nx"&gt;interfaceId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="nf"&gt;override&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ERC165&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;returns &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;interfaceId&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ISubscriptionOwner&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;interfaceId&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;supportsInterface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interfaceId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The address &lt;code&gt;&amp;lt;ADDRESS_OF_THE_SUBSCRIPTION_OWNER&amp;gt;&lt;/code&gt; must be the account you created in the beginning of this tutorial (step 1).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ISubscriptionOwner&lt;/code&gt; interface allows Arthera to determine the owner of the subscription, which must be an EOA account (it can't be a contract).&lt;/p&gt;

&lt;p&gt;If your contract is ownable, your &lt;code&gt;getSubscriptionOwner()&lt;/code&gt; function would eventually look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getSubscriptionOwner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;external&lt;/span&gt; &lt;span class="nx"&gt;view&lt;/span&gt; &lt;span class="nf"&gt;returns &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your contracts inherit from other contracts, you must ensure the order of inheritances is correct; keep in mind that the ERC165 often goes first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6
&lt;/h3&gt;

&lt;p&gt;Deploy your contract to Arthera Testnet. &lt;/p&gt;

&lt;p&gt;Here is the network info: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RPC Endpoint: &lt;strong&gt;&lt;a href="https://rpc-test.arthera.net"&gt;https://rpc-test.arthera.net&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Chain ID: &lt;strong&gt;10243&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 7
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to the Arthera &lt;a href="https://smp-test.arthera.net"&gt;SMP&lt;/a&gt; (Subscription Management Platform)&lt;/li&gt;
&lt;li&gt;In the left menu, click on the "On-Chain" tab&lt;/li&gt;
&lt;li&gt;Connect with the subscription owner wallet&lt;/li&gt;
&lt;li&gt;Click on "Subscribe" (&lt;strong&gt;DApp Plan&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Paste your contract address in the field&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should always use the same account, it's what we call the &lt;code&gt;subscriptionOwner&lt;/code&gt;. Get a dApp subscription, then paste the address of your newly deployed contract in the field.&lt;/p&gt;

&lt;p&gt;Done! 🎉&lt;/p&gt;

&lt;p&gt;At this stage, you're ready to whitelist your users so they can interact with your app without paying any gas fees.&lt;/p&gt;

&lt;p&gt;Welcome to Arthera: Enjoy Web3, forget gas fees.&lt;/p&gt;




&lt;h2&gt;
  
  
  Useful links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://t.me/artherachain/8"&gt;Tech support TG group&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.arthera.net/build/intro"&gt;Arthera documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.arthera.net/build/intro"&gt;Integration recommendations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.arthera.net/"&gt;Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://store.arthera.net/"&gt;App Store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://whitepaper.arthera.net/"&gt;Arthera White Paper NFT&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>solidity</category>
      <category>arthera</category>
      <category>dsaas</category>
    </item>
    <item>
      <title>Deploy an ERC-20 on Aurora using Hardhat</title>
      <dc:creator>Julien Béranger</dc:creator>
      <pubDate>Tue, 08 Nov 2022 16:38:52 +0000</pubDate>
      <link>https://dev.to/julienbrg/deploy-an-erc-20-on-aurora-using-hardhat-4ldh</link>
      <guid>https://dev.to/julienbrg/deploy-an-erc-20-on-aurora-using-hardhat-4ldh</guid>
      <description>&lt;p&gt;&lt;a href="https://aurora.dev/"&gt;Aurora&lt;/a&gt; is an EVM-based network that benefits from the security and scalability of NEAR. Technically, Aurora is a shard of NEAR that supports &lt;a href="https://soliditylang.org/"&gt;Solidity&lt;/a&gt;. There's nothing as simple as deploying an ERC-20 token on Aurora Testnet. &lt;/p&gt;

&lt;h2&gt;
  
  
  Aurora Testnet setup
&lt;/h2&gt;

&lt;p&gt;Go to &lt;a href="https://aurora.dev/start"&gt;https://aurora.dev/start&lt;/a&gt;, in the &lt;code&gt;Aurora Network&lt;/code&gt; section, select the &lt;code&gt;testnet&lt;/code&gt; tab and click on &lt;code&gt;Add Network&lt;/code&gt;: this will add Aurora Testnet as a new network in your MetaMask wallet.&lt;/p&gt;

&lt;p&gt;Head to &lt;a href="https://aurora.dev/faucet"&gt;Aurora Testnet faucet&lt;/a&gt; and click on the &lt;code&gt;testnet&lt;/code&gt; button. Now you can just click on the &lt;code&gt;Connect to Aurora Testnet&lt;/code&gt; button, it will turn into a &lt;code&gt;Request 0.001 ETH from faucet&lt;/code&gt; button: just click it to get 0.001 ETH. That will be more than enough to deploy your ERC-20 token contract.&lt;/p&gt;

&lt;p&gt;If you need more, you can use the &lt;a href="https://testnet.rainbowbridge.app/"&gt;Testnet Rainbow Bridge&lt;/a&gt; to transfer some Goerli ETH to Aurora Testnet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hardhat config
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Clone this repository: &lt;a href="https://github.com/julienbrg/dune-erc20"&gt;https://github.com/julienbrg/dune-erc20&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Copy the &lt;code&gt;.env.example&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Rename it &lt;code&gt;.env&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;In MetaMask, export the private key of the wallet holding the Aurora Testnet ETH, copy-paste it after the equal sign (line 3)&lt;/li&gt;
&lt;li&gt;In your terminal (in your root directory):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The ERC-20 contract
&lt;/h2&gt;

&lt;p&gt;This is a very basic ERC-20 token that's using open Zeppelin Solidity contracts library. There's only one function: the &lt;code&gt;mint()&lt;/code&gt; function. The visibility is set to public, meaning that anyone can call this function and mint as many units as he/she wants (we're in an 'open bar' mode, so to speak):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract Dune is ERC20 {
    constructor() ERC20("Dune", "DUNE") {}

    function mint(address to, uint256 amount) public {
        _mint(to, amount);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can test this contract with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx hardhat test 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then just deploy it to Aurora Testnet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx hardhat run scripts/deploy.ts --network aurora_testnet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERC-20 deployed at 0x51723295B6E50d94D887Bbc70c1AE0ab1Fa3a469 ✅
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On &lt;a href="https://testnet.aurorascan.dev/tx/0x375eaf92f4b4629968e5e3c622a96c00da0d610edf380e5e87d5ea8f98a94e52"&gt;Aurorascan&lt;/a&gt;, your deployment transaction will look like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fer6hpx7cknok1sj6lpa6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fer6hpx7cknok1sj6lpa6.png" alt="Aurorascan tx" width="800" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congrats, you just deployed a Solidity contract to Aurora Testnet! 🎉&lt;/p&gt;

&lt;p&gt;To mint and transfer a handful of DUNE to yourself (or to a friend of yours), you can use this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx hardhat run scripts/transfer.ts --network aurora_testnet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For info, there's even a frontend available if you want to mint some Dune tokens: &lt;a href="https://dune-aurora.netlify.app/"&gt;https://dune-aurora.netlify.app/&lt;/a&gt;. It was made using React, &lt;a href="https://web3auth.io/"&gt;Web3Auth&lt;/a&gt; and a builder called &lt;a href="https://www.plasmic.app/"&gt;Plasmic&lt;/a&gt;. The Github repo is &lt;a href="https://github.com/julienbrg/my-little-central-bank/tree/dune"&gt;here&lt;/a&gt; (there's a &lt;code&gt;dune&lt;/code&gt; branch) if you want to have a look.&lt;/p&gt;

&lt;p&gt;Now let's deploy to Mainnet... &lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy to Aurora Mainnet
&lt;/h2&gt;

&lt;p&gt;We're going to use a tool called Aurora+. Please head to &lt;a href="https://aurora.plus"&gt;https://aurora.plus&lt;/a&gt;, and sign up to get your 50 free tx per months. Once you've done that, you have your personalized RPC endpoint URL that is waiting for you (top-right menu):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk0ztre8yxynm0l1yv2gm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk0ztre8yxynm0l1yv2gm.png" alt="personalized endpoint" width="800" height="775"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can copy-paste that URL into your &lt;code&gt;.env&lt;/code&gt; file (line 1).&lt;/p&gt;

&lt;p&gt;Then you want to export your wallet's private key into your &lt;code&gt;.env&lt;/code&gt; file as well.&lt;/p&gt;

&lt;p&gt;Something is missing in that &lt;code&gt;.env&lt;/code&gt; file and it's the Aurorascan API key. You're going to need it to make it easy for everyone to read the source code of your contract, you can use Aurorascan API: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://aurorascan.dev/myapikey"&gt;https://aurorascan.dev/myapikey&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can sign up there, click on API-key in the left menu, then click on &lt;code&gt;add&lt;/code&gt; to create an API key. Copy-paste it in the &lt;code&gt;.env&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;deploy.ts&lt;/code&gt; file uncomment the lines 15, 16 and 17, and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx hardhat run scripts/deploy.ts --network aurora_mainnet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congrats! 🎉&lt;/p&gt;

&lt;p&gt;Your ERC-20 is deployed to Aurora Mainnet, you paid nothing, the source code is available for everyone to verify what's going on, and people can even trigger the mint function directly from &lt;a href="https://aurorascan.dev/address/0x1692787eF1044d9De9c1b60886891C5b7e33a7C4#code"&gt;Aurorascan&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7igbuygk5s5o0n45nvkx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7igbuygk5s5o0n45nvkx.png" alt="aurorascan" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you can also use the &lt;a href="https://github.com/julienbrg/dune-erc20/blob/main/scripts/transfer.ts"&gt;&lt;code&gt;transfer.ts&lt;/code&gt;&lt;/a&gt; script to mint some DUNE:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx hardhat run scripts/transfer.ts --network aurora_mainnet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks for your read!&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@heitmannj?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Henrik Heitmann&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Feel free to contact me via &lt;a href="https://matrix.to/#/@julienbrg:matrix.org"&gt;Element&lt;/a&gt;, &lt;a href="https://t.me/julienbrg"&gt;Telegram&lt;/a&gt;, &lt;a href="https://twitter.com/julienbrg"&gt;Twitter&lt;/a&gt;, &lt;a href="https://discord.gg/pfkJpEb4xn"&gt;Discord&lt;/a&gt;, or &lt;a href="https://www.linkedin.com/in/julienberanger/"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aurora</category>
      <category>hardhat</category>
      <category>tutorial</category>
      <category>solidity</category>
    </item>
    <item>
      <title>Mint an NFT on zkSync 2.0</title>
      <dc:creator>Julien Béranger</dc:creator>
      <pubDate>Sun, 10 Jul 2022 09:41:57 +0000</pubDate>
      <link>https://dev.to/julienbrg/mint-an-nft-on-zksync-20-4bi0</link>
      <guid>https://dev.to/julienbrg/mint-an-nft-on-zksync-20-4bi0</guid>
      <description>&lt;p&gt;As we now live in a &lt;a href="https://www.youtube.com/watch?v=XoQUc3rnKPM"&gt;rollup-centric world&lt;/a&gt;, minting an NFT on  Ethereum Mainnet (L1) is getting less and less relevant. &lt;a href="https://blog.matter-labs.io/zksync-2-0-public-testnet-is-live-de870ba9632a"&gt;zkSync 2.0&lt;/a&gt; public testnet went live in February 2022, so let's just give it a try! &lt;/p&gt;

&lt;p&gt;Please note that zkSync 2.0 &lt;em&gt;Mainnet&lt;/em&gt; is not available yet, but the whole community is waiting for the announcement. When it's out, you'll be ready to deploy your NFT contract. &lt;/p&gt;

&lt;p&gt;We'll work with this Github repository, you can go ahead and clone or fork it: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/julienbrg/zksync-minter"&gt;https://github.com/julienbrg/zksync-minter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I mainly used &lt;a href="https://v2-docs.zksync.io/api/hardhat/getting-started.html"&gt;zkSync 2.0 quickstart&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Please make sure you have the two following tools in place: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://classic.yarnpkg.com/lang/en/docs/install"&gt;Yarn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/get-started/"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Add your own keys
&lt;/h2&gt;

&lt;p&gt;Rename the &lt;code&gt;.env.example&lt;/code&gt; to &lt;code&gt;.env&lt;/code&gt;. To run the app, you need these three keys to be valid. &lt;/p&gt;

&lt;h3&gt;
  
  
  Web3 Storage
&lt;/h3&gt;

&lt;p&gt;As you might know, Web3 Storage uses IPFS and Filecoin. We'll use that to store the metadata of our NFT in a rather persistent way. &lt;/p&gt;

&lt;h3&gt;
  
  
  Infura
&lt;/h3&gt;

&lt;p&gt;You can signup and get a project ID directly on Infura's website: &lt;a href="https://infura.io/"&gt;https://infura.io/&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Wallet private key
&lt;/h3&gt;

&lt;p&gt;From your ArgentX browser wallet, you can export one of your accounts' private key. Make sure you have a handful of Goerli ETH on this wallet. &lt;/p&gt;

&lt;p&gt;Now you can&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Edit the NFT smart contract
&lt;/h2&gt;

&lt;p&gt;In case if your new, an NFT is just a unique digital object. Wether it's a gaming asset, a ticket to a party or an artwork, it most often can be transferred, that's the main feature of an NFT.&lt;/p&gt;

&lt;p&gt;I used the &lt;a href="https://wizard.openzeppelin.com/#erc721"&gt;Contracts Wizard&lt;/a&gt; provided by the all mighty OpenZeppelin team.&lt;/p&gt;

&lt;p&gt;It's a very basic ERC-721 contract. In the constructor, you attach the NFT metadata, mint the ID 1, transfer it to yourself and then revoke the ownership of the contract so that absolutely nobody can mint another NFT with this contract (including yourself).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract Thistle is ERC721, ERC721URIStorage, ERC721Burnable, Ownable {

    constructor(string memory uri) ERC721("Thistle", "THISTLE") {
        safeMint(msg.sender, 1, uri);
        renounceOwnership();
    }

    function _baseURI() internal pure override returns (string memory) {
        return "https://ipfs.io/ipfs/";
    }

    function safeMint(
        address to,
        uint256 tokenId,
        string memory uri
    ) public onlyOwner {
        _safeMint(to, tokenId);
        _setTokenURI(tokenId, uri);
    }

    function _burn(uint256 tokenId)
        internal
        override(ERC721, ERC721URIStorage)
    {
        super._burn(tokenId);
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can change the name of the contract (&lt;code&gt;Thistle&lt;/code&gt;), and also the name and symbol of the NFT in &lt;code&gt;ERC721("Thistle", "THISTLE")&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Once you've done that, your contract is ready. &lt;/p&gt;

&lt;p&gt;You can:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn hardhat compile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Edit the NFT metadata
&lt;/h2&gt;

&lt;p&gt;In the &lt;code&gt;nft&lt;/code&gt; directory, open the &lt;code&gt;metadata.json&lt;/code&gt; file and edit this file exactly like you want. You can use &lt;a href="https://web3.storage/account/"&gt;Web3.Storage&lt;/a&gt; to store an image and paste the url as the value of &lt;code&gt;image&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn hardhat deploy-zksync
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get something like this: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3u8kdgxplij7hb7s6g38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3u8kdgxplij7hb7s6g38.png" alt="deployment" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can copy the address of your contract and paste in the search bar of the &lt;a href="https://zksync2-testnet.zkscan.io/"&gt;zkSync 2.0 explorer&lt;/a&gt;. Here's my deployment transaction: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://zksync2-testnet.zkscan.io/tx/0x567037335a70bb01c02bb5f5f6ee2a777f37fc3a3b0c13bae62165e1dbc24c92/token-transfers"&gt;https://zksync2-testnet.zkscan.io/tx/0x567037335a70bb01c02bb5f5f6ee2a777f37fc3a3b0c13bae62165e1dbc24c92/token-transfers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2q2uzk9xyjsprhiccfon.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2q2uzk9xyjsprhiccfon.png" alt="tx screenshot" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have deployed your NFT contract to zkSync 2.0 testnet and minted 1 NFT! 🎉&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://ato.network/ZkSync/0xccA0521D453cA8C84Cb0b56936A4B764992b2F12/1"&gt;View this NFT on Āto&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You now hold this NFT in your wallet. The tx was confirmed within 3 seconds. If we were on Mainnet it would have costed less than 0.02 USD equivalent.&lt;/p&gt;

&lt;p&gt;When the time's right, you'll be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;move your NFT to Ethereum Mainnet (L1)&lt;/li&gt;
&lt;li&gt;move it to another L2&lt;/li&gt;
&lt;li&gt;build an interface to sell it using the &lt;a href="https://v2-docs.zksync.io/dev/guide/hello-world.html"&gt;zkSync development toolbox&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;add a personalized IP license using &lt;a href="https://ato.network/license"&gt;Āto&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;store it safely using &lt;a href="https://www.argent.xyz/"&gt;Argent&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have any question, feel free to &lt;a href="https://meetings-eu1.hubspot.com/julien-beranger"&gt;call me&lt;/a&gt; or &lt;a href="https://github.com/julienbrg/zksync-minter/issues"&gt;file an issue&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Thanks for reading! &lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@jaymantri?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Jay Mantri&lt;/a&gt;&lt;/p&gt;

</description>
      <category>zksync</category>
      <category>nft</category>
      <category>hardhat</category>
      <category>ethereum</category>
    </item>
  </channel>
</rss>
