Write gate context to cart attributes
This is the fourth and final part of a tutorial series for building a tokengated storefront. Read the overview page before starting this tutorial.
In this tutorial, you'll create a function that generates a hash-based message authentication code (HMAC). The HMAC you create will be an encrypted version of the gateConfiguration.id
that your customer has unlocking tokens for. With this, you can leverage Shopify Functions at checkout to apply automatic discounts
What you'll learn
Anchor link to section titled "What you'll learn"In this tutorial, you'll learn how to do the following:
- Generate an HMAC using SubtleCrypto from the Web Crypto API.
- Write the generated HMAC to cart attributes in a stringified array to allow your customers to unlock many gates.
Requirements
Anchor link to section titled "Requirements"- A Shopify Function that applies automatic discounts to the cart. Refer to the creating a Shopify Function to apply the gated discount tutorial.
- You have followed the previous tutorials in this series:
Step 1: Generate an HMAC
Anchor link to section titled "Step 1: Generate an HMAC"In the last tutorial, you created an evaluateGate.server
JS or TS file to perform gate evaluation.
In that same file, you'll add additional functionality to the evaluateGate
function to create an HMAC when unlockingTokens
are present for a given gateConfiguration
.
Add a new environment variable named
SHOPIFY_FUNCTION_SECRET
to your ENV file. The value should match the secret defined in the Shopify Function you built for applying automatic discounts.At this point, your
.env
file should look similar to the one shown below:Open your
evaluateGate.server
JS or TS file.Add the following code to the bottom of the file:
Update the
evaluateGate
function by pasting the following code just below theunlockingTokens
variable:Add a
gateContext
object to theevaluateGate
function's return statement.Add the
GateContext
type (TypeScript only).Copy the following type definition into your
/app/lib/type.ts
file:Update the
EvaluateGateResponse
type to include theGateContext
type (TypeScript only).In your
evaluateGate.server
JS or TS file, update yourEvaluateGateResponse
to include theGateContext
type you just created by replacing yourEvaluateGateResponse
with the following code:
To see a representation of what your code might look like after following these steps, view the sample repository.
Step 2: Write the generated HMAC to cart attributes
Anchor link to section titled "Step 2: Write the generated HMAC to cart attributes"Now that you've written the functionality to generate the HMAC, you need to write this HMAC to the cart attributes.
To do this, you'll add logic to the loader
function defined in the $productHandle
route.
This function checks if a cart is present before writing the attributes. If a cart is present, then it mutates the attributes for the cart. If a cart isn't present, the function creates a new cart and updates the cart cookie.
Add cart attributes functions
Anchor link to section titled "Add cart attributes functions"The code in this file contains the business logic associated with creating and updating cart attributes.
In your project's
/app/lib
folder, create a new file calledattributes.server.js
, orattributes.server.ts
if you're using TypeScript.Add the following code:
Run cart attribute mutations
Anchor link to section titled "Run cart attribute mutations"With the added functions from your attributes.server
JS or TS file, you'll update your loader to write gateContext
values returned from evaluateGate
to the cart attributes.
Open your
/app/routes/($locale).products.$productHandle
JSX or TSX file.Add the following code to the top of the
loader
function:This will be the headers for the returned response from the loader. Using these headers, you'll set the cart ID in the response to ensure that there is only one cart for the session.
In the same file, add the following code below the
unlockingTokens
assignment:
Step 3: Handle disconnection events
Anchor link to section titled "Step 3: Handle disconnection events"When a customer disconnects their wallet, clear the gateContext
cart attributes. Doing this ensures that any gates which were previously unlocked are no longer unlocked.
Open your
/app/routes/($locale)._index.tsx
file.Add the following import statement:
Locate the
clearFunction
and add the following code just below theclear()
invocation:
Step 4: Test your storefront
Anchor link to section titled "Step 4: Test your storefront"Your custom storefront now reads gates bound to products, parses the gate configurations for reactions and requirements, stores your buyer's wallet in cookies, evaluates their gate eligibility, and writes gate context to their cart.
Test that your storefront is enforcing gates and applying automatic discounts using your Shopify Function by following these steps:
Start your development server using the
dev
command:Open a product that has gates.
You should see the
Tokengate
component with a list of requirements needed to unlock the discount.Connect a wallet that meets the unlocking criteria.
Your
Tokengate
component should now show that the discount is unlocked.Add the product to your cart.
Your cart should reflect the price of the item with the discount applied.
Navigate to your checkout.
Your discount should be applied to the product in your cart.
Go back to your storefront and disconnect your wallet.
The price for the item should update to reflect the non-discounted price.