Skip to content

BaseAppAccount#22

Merged
badjer merged 53 commits intomainfrom
dnr/base-app
Aug 26, 2025
Merged

BaseAppAccount#22
badjer merged 53 commits intomainfrom
dnr/base-app

Conversation

@badjer
Copy link
Copy Markdown
Contributor

@badjer badjer commented Aug 26, 2025

Introduces a new BaseAppAccount, which:

  • is compatible with Base MiniApps and their smart wallets
  • uses a paymaster to pay for gas, so user accounts don't require ETH for transactions
  • creates ephemeral wallets for the user for each application, asks the user to grant them a spend permission, and then makes transactions through that ephemeral wallet. This means the user is only prompted to allow a spend permission, not to confirm every transaction

Usage:

import { useAccount } from "wagmi";
import { BaseAppAccount } from "@atxp/base";

const { address } = useAccount();
// Base mini app API key from the Coinbase Developer Portal
const apiKey = process.env.NEXT_PUBLIC_ONCHAINKIT_API_KEY!;
...
const account = await BaseAppAccount.initialize({
  walletAddress: address,
  apiKey,
  appName: 'Mini App ATXP',
  allowance: BigInt('10000000'), // 10 USDC
  periodInDays: 30,
});

// To clear existing data:
BaseAppAccount.clearAllStoredData(address);

// In Node.js or other environments, use fetch as-is
return fetch;
};

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes the bug in the browser environment outlined in the comments above

protected logger: Logger;

constructor(baseRPCUrl: string, sourceSecretKey: Hex, logger?: Logger) {
constructor(baseRPCUrl: string, walletClient: WalletClient, logger?: Logger) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a slightly worse devex, since we're now requiring the caller to do privateKeyToAccount(sourceSecretKey), but the upside is that this now supports non-EOA wallets, so it seems worth the tradeoff. Generally speaking, external devs aren't going to instantiate this class directly anyways - they're going to create a BaseAccount, which still does take a secret key as the constructor arg.

@badjer badjer marked this pull request as ready for review August 26, 2025 17:51
}
});
const provider = sdk.getProvider();
await sdk.getProvider().request({ method: 'wallet_connect' });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be using the provider above or do we need to get it again?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good catch - will update


const DEFAULT_ALLOWANCE = 10n;
const DEFAULT_PERIOD_IN_DAYS = 7;
const PAYMASTER_URL = 'https://api.developer.coinbase.com/rpc/v1/base/snPdXqIzOGhRkGNJvEHM5bl9Hm3yRO3m';
Copy link
Copy Markdown
Contributor

@robdimarco-atxp robdimarco-atxp Aug 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be configurable via Env Vars? I'm wondering if we might want different dev / staging / production values?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're settable via params - eg miniapp-example sets them here. I think that's probably adequate?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PAYMASTER_URL is not settable. Maybe that's ok?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should be ok, at least for now. The paymaster is US, and we don't want devs to bring their own paymasters at this point.

calls: [{
to: smartWallet.address,
value: 0n,
data: '0x' as `0x${string}`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, packages/atxp-client/src/types.ts has a Hex type. Maybe we should use it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair - viem also defines a Hex type with the same format. Updated

import { prepareSpendCallData } from '@base-org/account/spend-permission';

// Helper function to convert to base64url that works in both Node.js and browsers
function toBase64Url(data: string): string {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, this isn't producing a URL, it's just the base64 string. Not-blocking...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It produces a 'base64url' encoded string; I thought the naming was evocative of toBase64

Copy link
Copy Markdown
Contributor

@robdimarco-atxp robdimarco-atxp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@badjer badjer merged commit 813dbc2 into main Aug 26, 2025
7 checks passed
@badjer badjer deleted the dnr/base-app branch August 26, 2025 19:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants