Jump to content

Best practices or guidelines for Web3 / Crypto Wallet Connect functionality in ProcessWire sites


protro
 Share

Recommended Posts

Greetings ProcessWire forums,

I was curious if anyone has built a crypto hot wallet connect / sign-in feature to their PW sites? I am interested in the possibilities of such an integration into one of our project's websites. The only thing I am finding is this, but it just seems to be marketing fluff and I find it not trustworthy: https://blockchain.miniorange.com/crypto-wallet-login-and-nft-token-gating/processwire/

I am interested in learning more how MetaMask and/or Phantom wallet could be managed from a ProcessWire perspective.

  • Like 1
Link to comment
Share on other sites

Hi,

I "don't get what you have in mind" when you say "managed by" but things are pretty easy. Just associate public wallet address(es) of an user in the system user template by adding a new field to it. You will need a custom module and/or some hooks to interact with ProcessWire's session, brainstorming needed there before going further.

The workflow then could be:

  1. the user land on the site
  2. he process to log in by connecting his wallet address
  3. if this address is known then proceed to log in after the user sign the transaction
  4. if there are no account associated with this address, create the account with user approbation (signing transaction)

The account creation will be only made after the user selected hs wallet, and signed the transaction you sent to it.

Then I highly suggest you to use a battle tested solution to interact with wallets as there are multiple way of interacting with them, knowing that all wallet do not use the same method. For example you will find different process between CoinbaseWallet, TrustWallet using WalletConnect and Metamask/Phantom, not to mention the various blockchains implementation, eg. Ripple.

So, about the lib to use, just use Web3Modal  made by WalletConnect or Web3-Onboard made by Blocknative.

Another solution which is good to know it exist, I used it in january when I built a desktop app wallet (this one is not the cheapest you will find and it's more focused for established companies), is WaaS (wallet as a service) by cryptoapis.io and using HD wallets (xPub, yPub, zPub), TSS and distributed key. More complex things.

Feel free to ask more infos, as I had planned to write a module for all this mess and it might be a good starting point while interacting with some users starting with Web3 and ProcessWire 👍

---

Edit:
About the connector/solution you posted above, it look legit, but I think we never heard about them here in the forum, it seem to be an indian company. You might want to contact them directly from the official website, note that the ProcessWire connector IS NOT listed there.

The SHA fingerprints of the GoDaddy certificate on both urls are the same.

 

Edited by flydev
note
  • Like 2
Link to comment
Share on other sites

Thank you @flydev for your response. Just to get it out of the way I am a big fan of your Duplicator PW module. It has made a world of difference in my development work. Thank you for releasing that.

What I am interested to do is less to authenticate users to sign-in to a backend, and moreso to successfully connect to their wallet, and then if they are in possession of one of our tokens, to display some pages and/or media on the front end that a non-token holder would be unable to view. I am not interested in cold wallets at this time, mostly curious about MetaMask because it is the most popular for Ethereum.

I had looked at Web3-Onboard which you mention. Will look into the other libraries you listed. Good starting place.

  • Thanks 1
Link to comment
Share on other sites

Glad to hear it, thanks for the kind of words., do not hesitate to try Duplicator integration in wire-cli.

To get back to the topic, understood, then you should be able to get started quickly, With both web3 you will get users/guest wallet connected. To interact with Ethereum and smart-contracts, the easier way is to use one of the cleanest API made by Alchemy through their alchemy-sdk. You will be able with something like ten lines of code to get the tokens (fungible or not) from the contract(s) of your choices and then send ajax request to your scripts/templates to set something in the user session and let user view the hiddens pages and/or medias.

Do you use a "vanilla" JS/PHP frontend or are you on React, Svelte or something?

  • Like 2
Link to comment
Share on other sites

I am using Vanilla JS/PHP on the frontend. It's interesting you recommend Alchemy, I'll look into their sdk again. From what I remember their documentation was based on React, which seems to be the framework of choice for a lot of web3. I've felt disinclined to learn / build with it based of off feedback from other developers that I know and respect. 

This is all promising to hear you think it's not too heavy a lift with to integrate this stuff into ProcessWire so I will begin again with a fresh set of eyes.
 

Link to comment
Share on other sites

  • 2 weeks later...

Well this certainly opened up a can of worms for me. Following some of the advice from this thread, it seems to be a preference of many PW Devs to not use package managers, so I decided this would be a good way to go because

* package managers' file structure conflict with ProcessWire's default permissions (irc only files in /site/ are accessible, so this would negate a node_modules directory in the root)

* I prefer a simple / manual approach as was described in the above thread with regard to package managers.

When it came to trying the alchemy-sdk, I was running into problems with ES6+ syntax / import statements. e.g. Uncaught SyntaxError: Cannot use import statement outside a module.

So I guess I'll back up and ask, how are people who do use package managers doing that with PW, given its strict permissions? Secondarily, do I need to also use something like Babel/Webpack to transpile the alchemy-sdk code for distribution ?

Feeling confused, and any help is appreciated.

 

Link to comment
Share on other sites

Hi @protro

I didn't read the thread linked, but I will try to give a small insight of how I am used to dev with ProcessWire, and a note of ES6+ modules, with the answer of the import statements error, I will give you a starter module too at the end of this thread. And sorry, I have to be quick, so I am posting screenshot instead of a good formatted post, see the setup image at the end.

First, there is nothing wrong about using a package manager like node/npm, but you should do it in order to make you the life easier. It's more true when working with all the crypto mess. A word on your previous message, almost all lib/packages are developed using JS (TypeScript) so it will work with quite every frameworks/libs (React, Svelte, Vue, whatever). Some implementation are specialized for React, not surprising, React is in JS world what Wordpress is in the PHP world (check the stats in the linked thread below, fellow members here seem to not used it, hooray, react syntax is weird and slow).

My setup of almost every app (stay tuned as the whole things are coming published for free):

About the ES6+ module, when working with them, you need to use JS and for production building the app, OR you can call them in your `<script></script>` by setting up the script as module by writing `<script type="module"></script>`. Keep in mind that writing calls like that in templates, make global objects, like window, not available until the document is ready making things like binding events to DOM a bit tiresome..

And a draft of a module. It should not work as is, but it's just to give you an "image" more than words and could be written in templates. Writing JS like that (module or template) is not the better way to do it, and should be avoided, it makes things complicated when they're actually quite simple, even more when speaking about Metamask. Check the method `writeWeb3ModalScript()`, you can see that libs can be used from a CDN when published (unpkg make automatically available dist files of any packages):

<?php namespace ProcessWire;

class Web3 extends WireData implements Module, ConfigurableModule
{
  const WEB3MODAL_PROJECT_ID = ''; // read from db or .env file
  const ALCHEMY_API_KEY = ''; // read from db or .env file

  public static function getModuleInfo()
  {
    return [
      'title' => 'Web3',
      'version' => '0.0.1',
      'summary' => 'Web3 for ProcessWire',
      'autoload' => false,
      'icon' => '',
      'requires' => [],
      'installs' => [],
    ];
  }

  public function writeWeb3ModalScript($buttonDomID) {
    $scriptTag  = <<<EOT
    <link rel="stylesheet" href="https://unpkg.com/@rainbow-me/rainbowkit@1.0.7/dist/index.css" />
    <script type="module">
      import Onboard from 'https://unpkg.com/@web3-onboard/core'
      import injected from 'https://unpkg.com/@web3-onboard/injected-wallets'

      window.onload = async function() {
                
        const MAINNET_RPC_URL = 'https://mainnet.infura.io/v3/[APIKEY-HERE]'


        const onboard = Onboard({
          wallets: [injected],
          chains: [
            {
              id: '0x1',
              token: 'ETH',
              label: 'Ethereum Mainnet',
              rpcUrl: MAINNET_RPC_URL
            }
          ]
        })

        const wallets = await onboard.connectWallet()

        console.log(wallets)

        const connectButton = document.getElementById("$buttonDomID");

        // 3. Sign In
        window.onSignIn = function() {
          console.log(connectButton);
          console.log(window, window.onSignIn);
        }
      }
    </script>
    EOT;
    
    return $scriptTag;
  }

  // wallet can be an ENS formatted address
  public function getTokensForWallet($wallet)
  {
    $url = "https://eth-mainnet.g.alchemy.com/nft/v3/" . self::ALCHEMY_API_KEY;
    $url .= "/getNFTsForOwner?owner=" . $wallet;

    // send get request to alchemy api 
    $http = new WireHttp();
    $response = $http->getJSON($url);

    return $response;
  }

  // two fields in the backend
  /**
	 * Config inputfields
	 *
	 * @param InputfieldWrapper $inputfields
	 */
	public function getModuleConfigInputfields($inputfields) {
		$modules = $this->wire()->modules;

		/** @var InputfieldFieldset $fs */
		$fs = $modules->get('InputfieldFieldset');
		$fs->label = $this->_('API Configuration');
		$inputfields->add($fs);
    
		/** @var InputfieldCheckbox $f */
		$f = $modules->InputfieldText;
		$f_name = 'web3modal_project_id';
		$f->name = $f_name;
		$f->label = $this->_('Web3Modal Project ID');
		$f->description = $this->_('Get Key there: https://cloud.walletconnect.com');
		$f->columnWidth = 50;
    $f->value = $this->web3modal_project_id;
		$fs->add($f);

		/** @var InputfieldText $f */
		$f = $modules->InputfieldText;
		$f_name = 'alchemy_api_key';
		$f->name = $f_name;
		$f->label = $this->_('Alchemy API Key');
    $f->description = $this->_('Get Key there: https://dashboard.alchemy.com');
		$f->columnWidth = 50;
    $f->value = $this->alchemy_api_key;
		$fs->add($f);
  }

}

 

image.thumb.png.67ce5fc511952ac66e203e20f35014e2.png

(The NPM package is still not available publicly, but not fully required)


I will come back later with a working example using a CDN and a small example of a built js app working with PW. In the meantime, I'll leave you to ponder.

 

Edited by flydev
setup screenshot
  • Like 1
  • Thanks 1
Link to comment
Share on other sites

@flydev, thank you for taking the time to demonstrate so thoroughly.

Right off the bat I can see that you Dev environment differs from my MAMP setup in that the PW core files are contained within wwwroot, which in my environment (with multiple sites) I have placed the PW core within their respective htdocs -> project_name_sub_directories, with no corresponding directory level above the PW core, whereas I see in your case you have wwwroot with all PW core, but then a structure above for node_modules, src, etc. I think this is getting to one of my main confusions in my own dev environment.

In which case, this might be the time to try our DDEV as @bernhard and others have documented nicely. Perhaps this will be more suitable to my situation.

With regards to the wallet connectivity module, many thanks for illustrating such a detailed example. I will be having a deeper look at this.

Link to comment
Share on other sites

Its just a matter of organizing my directory tree structure.

when I was using MAMP, WAMP and even now in Caddytron, I was used to put in every root site folder a wwwroot folder that was the root folder of the virtualhost, so I can keep related meta files, log files, backups, or whatever, on the same directory, without having it accessible from internet. It's basically the same setup as your.

To illustrate:

- htdocs  
     - wwwroot 
          - index.php
          - wire 
          …

or 

- /var/www/html
   - website1
        - readme.md
        - wwwroot

   - website1
        - readme.md
        - wwwroot

 

About the node_modules folder, just keep in mind that is a dev folder not uploaded on production. So it doesn’t matter where you put the folder as no scripts are linked or interfering with your pw files.

If you are working for example on a react app, svelte or vue or even a simple js/ta app, your app will be « talking » with your pw setup from Ajax call or static routes.

You only want the final built scripts to be shipped on your production (i mean your pw setup). They will be included the same way like any other script files you are used to do.


 

 

Link to comment
Share on other sites

Thanks @flydev … I just went on the proverbial deep-dive configuring my free version of MAMP to have multiple virtual hosts for the different sites I test, successfully getting my PW core into a wwwroot directory and freeing-up a directory level above it for a cleaner tree-structure similar to yours: now onto some ES6+ module testing.

  • Like 1
Link to comment
Share on other sites

  • 4 weeks later...

updating this topic for visibility. The best tutorials and working repo I have come across so far are from 0x3 Studio: https://blog.0x3.studio/a-very-simple-to-offer-a-connect-wallet-option-for-your-website-thanks-to-rainbowkit/

The project is bootstrapped using NextJS and RainbowKit. This leaves me with some questions as to whether or not I want to integrate the functionality into a pre-existing ProcessWire site or create a Next.js SPA on a subdomain that accomplishes the functionality I am trying to achieve. It seems like there is not much documentation on working with NextJS and PW at the moment, although these modules seem to be pointing in that direction:

Inertia.js for ProcessWire https://github.com/joyofpw/inertia
Vue with headless PW: https://medium.com/icf-church-developers/processwire-vue-js-a-lovestory-d4d5bca365

Currently it's beyond my understanding on the best marriage with a front-end framework and/or PW either as a headless CMS, API, or non-headless, but the above examples are leading me into interesting territory.

  • Like 1
Link to comment
Share on other sites

Hi @protro

Rainbowkit is a really good package but last time I checked it (some months ago) I could see that it's built on wagmi, which is only working with React and then didn't paid so much attention to it as I am only coding on Svelte. Recently I saw popped a port of wagmi on svelte but still not tested it.

FYI, the inertia module linked miss a little update, and the samples provided you will found are deprecated and are built using webpack. Did you have some experience with JS libs or frameworks (I mean vue, react or svelte) ? If not, I suggest you to start on Svelte as it's really the easier and natural frameworks to start on without experience.

Anyway, as you said it, links above will helps you for sure. With any app sample you can find, you just have to send an ajax request to your ProcessWire page/template to get an answer with the required api keys/tokens/ whatever you need. Example:
 

// 1. create a template called `web3` with a text field called `apikey` 
// 2. create php template in `site/web3.php` and leave it empty with no code
// 3. create a page called `web3` with template `web3`
// 4. in `init.php` write:

// this function will help you to fight CORS issue between your app and pw site
function cors() {
  // Allow from any origin
  if (isset($_SERVER['HTTP_ORIGIN'])) {
      // Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
      // you want to allow, and if so:
      header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
      header('Access-Control-Allow-Credentials: true');
      header('Access-Control-Max-Age: 86400');    // cache for 1 day
  }

  // Access-Control headers are received during OPTIONS requests
  if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
      if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
          // may also be using PUT, PATCH, HEAD etc
          header("Access-Control-Allow-Methods: GET, POST, OPTIONS");         
      if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
          header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
      exit(0);
    }
}

/**
 * Example of a simple router using ProcessWire's built-in URL hook system.
 * By appending /json to any page URL, you'll get a JSON representation of the page
 * 
 * Require ProcessWire 3.0.173 or newer.
 * see: https://processwire.com/blog/posts/pw-3.0.173/#outputting-json-data-about-any-page-when-the-last-part-of-the-url-is-json
 * 
 * Note that this is a very simple example. For more advanced routing, you might want to
 * use a Process module like AppApi made by @mauricio.
 * 
 */
$wire->addHook('(/.*)/json', function($event) {
  $page = $event->pages->findOne($event->arguments(1));

  // fight cors (for test purpose only)
  cors();

  if($page->viewable()) return [
    'id' => $page->id,
    'url' => $page->url,
    'title' => $page->title,
    'apikey' => $page->apikey
  ];
}); 
// from any javascript lib or framework, send a request and get an answer

const response = await fetch("https://localhost.local/web3/json");
const data = await response.json();
console.log(data); // <-- contain json answer
/**
{
  id: 1000,
  url: "https://mywebsite.local/web3",
  title: "web3 page",
  apikey: "API-ABCD-0123"
}
*/



I've fallen behind on the vite and inertia module release, but it's coming, it's a matter of days, I suggest you to wait for it and try the web3 sample coming.

 

  • Like 1
Link to comment
Share on other sites

Thank you @flydev for this example api / json request. I appreciate it because it is very clear what it is doing and it is helping me make sense of these capabilities that aren't as carefully documented in PW docs. So a huge thanks. I think a Ko-fi is in order!

On the case of Svelte, it seems to be the choice framework of some devs that I have spoken with and trust. I did not realize that the Rainbowkit is React only (I saw it does support Vite though). However, I think at this point, with the little interest I have devoted to React, I choose to go the Svelte route, as it does seem the most promising. I hope that there is further ambition within web3 wallet sdks to support it as well, as it seems this would be a fantastic expansion of the currently supported frameworks.

Good to know on the inertia modules being somewhat outdated. I was curious to see how some of it worked, and glad that it did. I look forward to your Vite module and what that will entail. Exciting stuff.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...