Skip to content

Commit 3497135

Browse files
committed
Add DTK tutorial for creating an invite link
1 parent 3ae9489 commit 3497135

File tree

3 files changed

+214
-0
lines changed

3 files changed

+214
-0
lines changed

gator-sidebar.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ const sidebar = {
104104
label: "Create a custom caveat enforcer",
105105
href: "/tutorials/create-custom-caveat-enforcer"
106106
},
107+
{
108+
type: "link",
109+
label: "Create a custom caveat enforcer",
110+
href: "/tutorials/create-invite-link"
111+
},
107112
],
108113
},
109114
{
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
---
2+
title: Create a social invite link
3+
image: 'img/tutorials/tutorials-banners/create-invite-link.png'
4+
description: Allow users to refer their friends to your dapp using an invite link.
5+
tags: [delegation toolkit, social, invite, referral, link]
6+
date: Sep 8, 2025
7+
author: MetaMask Developer Relations
8+
---
9+
10+
This tutorial walks you through creating an invite link to enable users to refer their friends to your dapp with minimal friction.
11+
12+
For example, Alice (the inviter) wants Bob (the invitee) to try out your dapp.
13+
She sends him a link that allows him to claim 0.001 ETH from her wallet within a time limit.
14+
Bob can start using your dapp right away, without installing a wallet or paying gas fees.
15+
16+
You'll enable this by creating a [MetaMask smart account](/delegation-toolkit/concepts/smart-accounts) to represent the inviter, using a paymaster to abstract gas fees, and creating an [open delegation](/delegation-toolkit/concepts/delegation) to represent an invitation.
17+
This tutorial uses Pimlico's paymaster, but you can use any paymaster of your choice.
18+
19+
## Prerequisites
20+
21+
- Get an [Infura API key](/developer-tools/dashboard/get-started/create-api) from the MetaMask Developer dashboard.
22+
- [Create a Pimlico API key](https://docs.pimlico.io/guides/create-api-key#create-api-key).
23+
24+
## Steps
25+
26+
### 1. Install the Delegation Toolkit
27+
28+
Install the [MetaMask Delegation Toolkit](https://www.npmjs.com/package/@metamask/delegation-toolkit) in your project:
29+
30+
```bash npm2yarn
31+
npm install @metamask/delegation-toolkit
32+
```
33+
34+
### 2. Create a Public Client
35+
36+
Create a [Viem Public Client](https://viem.sh/docs/clients/public) using Viem's `createPublicClient` function.
37+
You will configure a smart account and Bundler Client with the Public Client, which you can use to query the signer's account state and interact with the blockchain network.
38+
39+
```typescript
40+
import { createPublicClient, http } from 'viem';
41+
import { sepolia as chain } from 'viem/chains';
42+
43+
const publicClient = createPublicClient({
44+
chain,
45+
transport: http(),
46+
});
47+
```
48+
49+
### 3. Create a Paymaster Client
50+
51+
Create a [Viem Paymaster Client](https://viem.sh/account-abstraction/clients/paymaster) using Viem's `createPaymasterClient` function.
52+
This client interacts with the paymaster service.
53+
54+
Replace `<YOUR-API-KEY>` with your Pimlico API key:
55+
56+
```typescript
57+
import { createPaymasterClient } from 'viem/account-abstraction';
58+
59+
const paymasterClient = createPaymasterClient({
60+
transport: http('https://api.pimlico.io/v2/11155111/rpc?apikey=<YOUR-API-KEY>'),
61+
});
62+
```
63+
64+
### 4. Create a Bundler Client
65+
66+
Create a [Viem Bundler Client](https://viem.sh/account-abstraction/clients/bundler) using Viem's `createBundlerClient` function.
67+
Pass the `paymasterClient` to the `paymaster` property.
68+
You can use the bundler service to estimate gas for user operations and submit transactions to the network.
69+
70+
```typescript
71+
import { createBundlerClient } from 'viem/account-abstraction';
72+
73+
const bundlerClient = createBundlerClient({
74+
client: publicClient,
75+
transport: http('https://your-bundler-rpc.com'),
76+
paymaster: paymasterClient,
77+
});
78+
```
79+
80+
### 5. Create and deploy an inviter account
81+
82+
Create an account to represent the inviter.
83+
This account will be creating a delegation, and must be a [MetaMask smart account](/delegation-toolkit/concepts/smart-accounts).
84+
This example uses a [Hybrid smart account](/delegation-toolkit/development/guides/smart-accounts/create-smart-account/#create-a-hybrid-smart-account), which is a flexible smart account implementation that supports both an externally owned account (EOA) owner and any number of passkey (WebAuthn) signers.
85+
86+
```typescript
87+
import { Implementation, toMetaMaskSmartAccount } from '@metamask/delegation-toolkit';
88+
import { privateKeyToAccount } from 'viem/accounts';
89+
90+
const account = privateKeyToAccount('0x...');
91+
92+
const smartAccount = await toMetaMaskSmartAccount({
93+
client: publicClient,
94+
implementation: Implementation.Hybrid,
95+
deployParams: [account.address, [], [], []],
96+
deploySalt: '0x',
97+
signatory: { account },
98+
});
99+
```
100+
101+
Deploy the smart account by sending a user operation:
102+
103+
```ts
104+
import { zeroAddress } from 'viem';
105+
106+
// Appropriate fee per gas must be determined for the specific bundler being used.
107+
const maxFeePerGas = 1n;
108+
const maxPriorityFeePerGas = 1n;
109+
110+
const userOperationHash = await bundlerClient.sendUserOperation({
111+
account: smartAccount,
112+
calls: [{ to: zeroAddress }],
113+
maxFeePerGas,
114+
maxPriorityFeePerGas,
115+
});
116+
```
117+
118+
Fund the deployed smart account with some Sepolia ETH to sponsor gas fees for the invitee.
119+
120+
:::note
121+
You can use the [MetaMask faucet](/developer-tools/faucet) to get Sepolia ETH.
122+
:::
123+
124+
### 6. Create and sign an invitation
125+
126+
Create an [open root delegation](/delegation-toolkit/concepts/delegation) to represent an invitiation.
127+
A root delegation is the first delegation in a chain of delegations, and an open root delegation grants permission to any account.
128+
In this example, the inviter creates an invitation that can be redeemed by any invitee, allowing the invitee to spend up to 0.001 ETH.
129+
130+
```ts
131+
import { createOpenDelegation, getDelegatorEnvironment } from '@metamask/delegation-toolkit';
132+
133+
const delegation = createOpenDelegation({
134+
from: smartAccount.address,
135+
environment: getDelegatorEnvironment(chain.id);
136+
scope: {
137+
type: 'nativeTokenTransferAmount',
138+
// 0.001 ETH in wei format.
139+
maxAmount: 1000000000000000n,
140+
},
141+
});
142+
```
143+
144+
Sign the delegation to enable the invitee to redeem it in the future:
145+
146+
```typescript
147+
const signature = await smartAccount.signDelegation({
148+
delegation,
149+
})
150+
151+
const signedDelegation = {
152+
...delegation,
153+
signature,
154+
}
155+
```
156+
157+
### 7. Create an invitee account
158+
159+
Create an account to represent the invitee.
160+
This account will be redeeming the delegation and can be a smart account or an externally owned account (EOA).
161+
This example uses an EOA:
162+
163+
```ts
164+
import { privateKeyToAccount } from 'viem/accounts';
165+
import { sepolia as chain } from 'viem/chains';
166+
import { createWalletClient, http } from 'viem';
167+
168+
const delegateAccount = privateKeyToAccount('0x...');
169+
170+
export const delegateWalletClient = createWalletClient({
171+
account: delegateAccount,
172+
chain,
173+
transport: http(),
174+
})
175+
```
176+
177+
### 8. Redeem the invitation
178+
179+
The invitee can redeem the invitation by submitting a transaction to the `DelegationManager` contract, which validates the delegation and executes delegated actions.
180+
In this case, the invitee can spend up to 0.001 ETH from the inviter when using your dapp.
181+
182+
```ts
183+
import { createExecution, getDeleGatorEnvironment } from '@metamask/delegation-toolkit'
184+
import { DelegationManager } from '@metamask/delegation-toolkit/contracts'
185+
import { SINGLE_DEFAULT_MODE } from '@metamask/delegation-toolkit/utils'
186+
import { zeroAddress } from 'viem'
187+
188+
const delegations = [signedDelegation]
189+
190+
const executions = createExecution({ target: zeroAddress })
191+
192+
const redeemDelegationCalldata = DelegationManager.encode.redeemDelegations({
193+
delegations: [delegations],
194+
modes: [SINGLE_DEFAULT_MODE],
195+
executions: [executions]
196+
});
197+
198+
const transactionHash = await delegateWalletClient.sendTransaction({
199+
to: getDeleGatorEnvironment(chain.id).DelegationManager,
200+
data: redeemDelegationCalldata,
201+
chain,
202+
})
203+
```
204+
205+
## Next steps
206+
207+
- Learn more about [smart account implementations](/delegation-toolkit/development/guides/smart-accounts/create-smart-account).
208+
- Learn more about [delegation types](/delegation-toolkit/development/concepts/delegation/#delegation-types).
209+
- Learn more about [using delegation scopes](/delegation-toolkit/development/guides/delegation/use-delegation-scopes).
187 KB
Loading

0 commit comments

Comments
 (0)