diff --git a/REDIRECTS_GUIDE.md b/REDIRECTS_GUIDE.md index 1f3a50a40..eb1fb5a58 100644 --- a/REDIRECTS_GUIDE.md +++ b/REDIRECTS_GUIDE.md @@ -16,6 +16,7 @@ A comprehensive guide for managing redirects in Mintlify documentation (migrated ## Overview Redirects are essential when restructuring documentation (IA refactor) to ensure: + - Old links don't break - Search engine rankings are preserved - User bookmarks continue to work @@ -67,7 +68,7 @@ Add a new object to the array: ```bash # Run the dev server -mintlify dev +mint dev # Test the redirect # Navigate to http://localhost:3000/old-page-path @@ -150,11 +151,13 @@ mintlify dev ### No Wildcard support **Nextra** (supported): + ``` /docs/* /tutorials/:splat 301 ``` **Mintlify** (NOT supported): + ```json { "source": "/docs/*", @@ -167,10 +170,9 @@ mintlify dev ```json { "redirects": [ - {"source": "/docs/page1", "destination": "/tutorials/page1"}, - {"source": "/docs/page2", "destination": "/tutorials/page2"}, - {"source": "/docs/page3", "destination": "/tutorials/page3"} + { "source": "/docs/page1", "destination": "/tutorials/page1" }, + { "source": "/docs/page2", "destination": "/tutorials/page2" }, + { "source": "/docs/page3", "destination": "/tutorials/page3" } ] } ``` - diff --git a/app-developers/quickstarts/actions.mdx b/app-developers/quickstarts/actions.mdx new file mode 100644 index 000000000..4f494dea8 --- /dev/null +++ b/app-developers/quickstarts/actions.mdx @@ -0,0 +1,530 @@ +--- +title: Integrating DeFi with Actions SDK +description: Perform DeFi actions with lightweight, composable, and type-safe modules. +--- + + + Actions SDK is still under construction and not ready for production use! This guide is meant for early testing purposes only. + + +The [Actions SDK](https://actions.money/) is an open source Typescript development toolkit that simplifies the act of integrating DeFi into your application. + +## How it works + +Here's a breakdown of what's under the hood: + +- **Modular Providers**: Actions is built with a set of core adapters called "Providers". Providers let you to pick an choose the right services and protocols for your use-case. + +- **Embedded Wallets**: Actions supports popular embedded [wallet providers](https://actions.money/#wallet), allowing your users to access DeFi with email authentication flows alone. + +- **Configure Actions**: Extend your embedded wallet with DeFi actions like Lend, Borrow, Swap, and Pay. Set multiple providers for each Action to choose the best markets across DeFi. + +- **Customize assets & chains**: Allow and block assets, markets, chains, and protocols from your application from a single config. + + +## Installation + +Install the Actions SDK in your project: + + +```bash npm +npm install @eth-optimism/actions-sdk +``` + +```bash pnpm +pnpm add @eth-optimism/actions-sdk +``` + +```bash yarn +yarn add @eth-optimism/actions-sdk +``` + +```bash bun +bun add @eth-optimism/actions-sdk +``` + +```bash deno +deno add @eth-optimism/actions-sdk +``` + + +## Choose a Wallet Provider + +Actions works with both frontend and backend wallets depending on your needs: + + + + Select a wallet provider: + + + + Install and setup [Privy](https://docs.privy.io/basics/react/installation). + + **Configure Wallet Provider** + + Give your embedded wallets the ability to take Action: + + ```typescript + import { actions } from './config' + import { useWallets } from '@privy-io/react-auth' + + // PRIVY: Fetch wallet + const { wallets } = useWallets() + const embeddedWallet = wallets.find( + (wallet) => wallet.walletClientType === 'privy', + ) + + // ACTIONS: Let wallet make onchain Actions + const wallet = await actions.wallet.toActionsWallet({ + connectedWallet: embeddedWallet, + }) + ``` + + **Configure Smart Wallets** + + Optionally, create signers for smart wallets you control: + + ```typescript + import { actions } from './config' + import { useWallets } from '@privy-io/react-auth' + + // PRIVY: Fetch wallet + const { wallets } = useWallets() + const embeddedWallet = wallets.find( + (wallet) => wallet.walletClientType === 'privy', + ) + + // ACTIONS: Create signer from hosted wallet + const signer = await actions.wallet.createSigner({ + connectedWallet: embeddedWallet, + }) + + // ACTIONS: Create smart wallet + const { wallet } = await actions.wallet.createSmartWallet({ + signer: signer + }) + ``` + + + + Install and setup [Turnkey](https://docs.turnkey.com/sdks/react/getting-started). + + **Configure Wallet Provider** + + Give your embedded wallets the ability to take Action: + + ```typescript + import { useTurnkey, WalletSource } from "@turnkey/react-wallet-kit" + import { actions, USDC, ExampleMarket } from './config' + + // Fetch Turnkey wallet + const { wallets, httpClient, session } = useTurnkey() + const embeddedWallet = wallets.find( + (wallet) => + wallet.accounts.some( + (account) => account.addressFormat === 'ADDRESS_FORMAT_ETHEREUM', + ) && wallet.source === WalletSource.Embedded, + ) + + const walletAddress = embeddedWallet.accounts[0].address + + // Convert to Actions wallet + const wallet = await actions.wallet.toActionsWallet({ + client: httpClient, + organizationId: session.organizationId, + signWith: walletAddress, + }) + + // Wallet can now take action + const receipt = await wallet.lend.openPosition({ + amount: 100, + asset: USDC, + ...ExampleMarket + }) + ``` + + **Configure Smart Wallets** + + Optionally, create signers for smart wallets you control: + + ```typescript + import { useTurnkey, WalletSource } from "@turnkey/react-wallet-kit" + import { actions } from './config' + + // Fetch Turnkey wallet + const { wallets, httpClient, session } = useTurnkey() + const embeddedWallet = wallets.find( + (wallet) => + wallet.accounts.some( + (account) => account.addressFormat === 'ADDRESS_FORMAT_ETHEREUM', + ) && wallet.source === WalletSource.Embedded, + ) + const walletAddress = embeddedWallet.accounts[0].address + + // Create signer + const signer = await actions.wallet.createSigner({ + client: httpClient, + organizationId: session.organizationId, + signWith: walletAddress, + }) + + // Create smart wallet + const { wallet } = await actions.wallet.createSmartWallet({ + signer: signer + }) + ``` + + + + Install and setup [Dynamic](https://www.dynamic.xyz/docs/wallets/embedded-wallets/mpc/setup). + + **Configure Wallet Provider** + + Give your embedded wallets the ability to take Action: + + ```typescript + import { useDynamicContext } from "@dynamic-labs/sdk-react-core" + import { actions, USDC, ExampleMarket } from './config' + + // Fetch Dynamic wallet + const { primaryWallet } = useDynamicContext() + + // Convert to Actions wallet + const wallet = await actions.wallet.toActionsWallet({ + wallet: primaryWallet, + }) + + // Wallet can now take action + const receipt = await wallet.lend.openPosition({ + amount: 100, + asset: USDC, + ...ExampleMarket + }) + ``` + + **Configure Smart Wallets** + + Optionally, create signers for smart wallets you control: + + ```typescript + import { useDynamicContext } from "@dynamic-labs/sdk-react-core" + import { actions } from './config' + + // Fetch Dynamic wallet + const { primaryWallet } = useDynamicContext() + + // Create signer + const signer = await actions.wallet.createSigner({ + wallet: primaryWallet + }) + + // Create smart wallet + const { wallet } = await actions.wallet.createSmartWallet({ + signer: signer + }) + ``` + + + + + + Select a wallet provider: + + + + Install and setup [Privy](https://docs.privy.io/basics/nodeJS/installation). + + **Configure Wallet Provider** + + Give your embedded wallets the ability to take Action: + + ```typescript + import { actions } from './config' + import { PrivyClient } from '@privy-io/node' + + // PRIVY: Create wallet + const privyClient = new PrivyClient(env.PRIVY_APP_ID, env.PRIVY_APP_SECRET) + + const privyWallet = await privyClient.wallets().create({ + chain_type: 'ethereum', + owner: { user_id: 'privy:did:xxxxx' }, + }) + + // ACTIONS: Let wallet make onchain Actions + const wallet = await actions.wallet.toActionsWallet({ + walletId: privyWallet.id, + address: privyWallet.address, + }) + ``` + + **Configure Smart Wallets** + + Optionally, create signers for smart wallets you control: + + ```typescript + import { actions } from './config' + import { PrivyClient } from '@privy-io/node' + import { getAddress } from 'viem' + + const privyClient = new PrivyClient(env.PRIVY_APP_ID, env.PRIVY_APP_SECRET) + + // PRIVY: Create wallet + const privyWallet = await privyClient.wallets().create({ + chain_type: 'ethereum', + owner: { user_id: 'privy:did:xxxxx' }, + }) + + // ACTIONS: Create signer + const signer = await actions.wallet.createSigner({ + walletId: privyWallet.id, + address: getAddress(privyWallet.address), + }) + + // ACTIONS: Create smart wallet + const { wallet } = await actions.wallet.createSmartWallet({ + signer: signer + }) + ``` + + + + Install and setup [Turnkey](https://docs.turnkey.com/sdks/javascript-server). + + **Configure Wallet Provider** + + Give your embedded wallets the ability to take Action: + + ```typescript + import { Turnkey } from '@turnkey/sdk-server' + import { actions, USDC, ExampleMarket } from './config' + + const turnkeyClient = new Turnkey({ + apiBaseUrl: 'https://api.turnkey.com', + apiPublicKey: process.env.TURNKEY_API_KEY, + apiPrivateKey: process.env.TURNKEY_API_SECRET, + defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, + }) + + // Create Turnkey wallet + const turnkeyWallet = await turnkeyClient.apiClient().createWallet({ + walletName: 'ETH Wallet', + accounts: [{ + curve: 'CURVE_SECP256K1', + pathFormat: 'PATH_FORMAT_BIP32', + path: "m/44'/60'/0'/0/0", + addressFormat: 'ADDRESS_FORMAT_ETHEREUM', + }], + }) + + // Convert to Actions wallet + const wallet = await actions.wallet.toActionsWallet({ + organizationId: turnkeyWallet.activity.organizationId, + signWith: turnkeyWallet.addresses[0], + }) + + // Wallet can now take action + const receipt = await wallet.lend.openPosition({ + amount: 100, + asset: USDC, + ...ExampleMarket + }) + ``` + + **Configure Smart Wallets** + + Optionally, create signers for smart wallets you control: + + ```typescript + import { Turnkey } from '@turnkey/sdk-server' + import { actions } from './config' + + const turnkeyClient = new Turnkey({ + apiBaseUrl: 'https://api.turnkey.com', + apiPublicKey: process.env.TURNKEY_API_KEY, + apiPrivateKey: process.env.TURNKEY_API_SECRET, + defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID, + }) + + // Create Turnkey wallet + const turnkeyWallet = await turnkeyClient.apiClient().createWallet({ + walletName: 'ETH Wallet', + accounts: [{ + curve: 'CURVE_SECP256K1', + pathFormat: 'PATH_FORMAT_BIP32', + path: "m/44'/60'/0'/0/0", + addressFormat: 'ADDRESS_FORMAT_ETHEREUM', + }], + }) + + // Create signer + const signer = await actions.wallet.createSigner({ + organizationId: turnkeyWallet.activity.organizationId, + signWith: turnkeyWallet.addresses[0], + }) + + // Create smart wallet + const { wallet } = await actions.wallet.createSmartWallet({ + signer: signer + }) + ``` + + + + + +## Create your ActionsConfig + +Create your Actions configuration to define which protocols, chains, and assets to support. + +Configure a wallet provider: + +```typescript +import type { WalletConfig } from '@eth-optimism/actions-sdk' + +const walletConfig: WalletConfig = { + hostedWalletConfig: { + provider: { + type: 'privy', // your provider chosen in previous step + }, + }, + smartWalletConfig: { + provider: { + type: 'default', + attributionSuffix: 'actions', + }, + }, +} +``` + +Configure a lend provider with `LendConfig`: + +```typescript +import type { LendConfig } from '@eth-optimism/actions-sdk' +import { USDC, ETH, WBTC } from '@eth-optimism/actions-sdk/assets' +import { USDCMorphoMarket } from './actions/markets' + +const lendConfig: LendConfig = { + type: 'morpho', + assetAllowlist: [USDC, ETH, WBTC], + assetBlocklist: [], + marketAllowlist: [USDCMorphoMarket], + marketBlocklist: [], +} +``` + +Configure a borrow provider with `BorrowConfig`: + +```typescript +import type { BorrowConfig } from '@eth-optimism/actions-sdk' +import { USDC, ETH, WBTC } from '@eth-optimism/actions-sdk/assets' +import { USDCMorphoMarket } from './actions/markets' + +const borrowConfig: BorrowConfig = { + type: 'morpho', + assetAllowlist: [USDC, ETH, WBTC], + assetBlocklist: [], + marketAllowlist: [USDCMorphoMarket], + marketBlocklist: [], +} +``` + +Configure a swap provider with `SwapConfig`: + +```typescript +import type { SwapConfig } from '@eth-optimism/actions-sdk' +import { USDC, ETH, WBTC } from '@eth-optimism/actions-sdk/assets' + +const swapConfig: SwapConfig = { + type: 'uniswap', + defaultSlippage: 100, // 100 bips or 1% + assetAllowList: [USDC, ETH, WBTC], + assetBlocklist: [], +} +``` + +Configure supported chains: + +```typescript +import { optimism, base } from 'viem/chains' + +// Define any EVM chain +const OPTIMISM = { + chainId: optimism.id, + rpcUrls: env.OPTIMISM_RPC_URL, + bundler: { // Bundle and sponsor txs with a gas paymaster + type: 'simple' as const, + url: env.OPTIMISM_BUNDLER_URL, + }, +} + +const BASE = { + chainId: base.id, + rpcUrls: env.BASE_RPC_URL, + bundler: { // Bundle and sponsor txs with a gas paymaster + type: 'simple' as const, + url: env.BASE_BUNDLER_URL, + }, +} + +const chains = [OPTIMISM, BASE] +``` + +Finally, bring it all together and initialize Actions: + +```typescript +export const actions = createActions({ + wallet: walletConfig, + lend: lendConfig, + borrow: borrowConfig, + swap: swapConfig, + chains, +}) +``` + +## Using Actions + +Once configured, you can use Actions to perform DeFi operations: + +```typescript +import { USDC, ETH, USDT } from '@eth-optimism/actions-sdk/assets' +import { ExampleMarket } from '@/actions/markets' + +// Enable asset lending in DeFi +const lendReceipt = await wallet.lend.openPosition({ + amount: 1, + asset: USDC, + ...ExampleMarket +}) + +// Manage user market positions +const lendPosition = await wallet.lend.getPosition(market) + +// Fetch wallet balance +const balance = await wallet.getBalance() + +// ⚠️ COMING SOON +const borrowReceipt = await wallet.borrow.openPosition({ + amount: 1, + asset: USDT, + ...market +}) + +// ⚠️ COMING SOON +const swapReceipt = await wallet.swap.execute({ + amountIn: 1, + assetIn: USDC, + assetOut: ETH, +}) + +// ⚠️ COMING SOON +const sendReceipt = await wallet.send({ + amount: 1, + asset: USDC, + to: 'vitalik.eth', +}) +``` + +## Next Steps + +- Check out the [Actions demo](https://actions.money/earn) for a complete example application +- Join the [Optimism Discord](https://discord.optimism.io) for support and updates diff --git a/docs.json b/docs.json index d0e483f18..af751602d 100644 --- a/docs.json +++ b/docs.json @@ -1646,7 +1646,8 @@ { "group": "Quickstarts", "pages": [ - "app-developers/quickstarts/starter-kit" + "app-developers/quickstarts/starter-kit", + "app-developers/quickstarts/actions" ] }, { diff --git a/package.json b/package.json index 80852de65..d743c47e2 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "Optimism Documentation", "main": "index.js", "scripts": { - "dev": "mintlify dev", - "build": "mintlify build" + "dev": "mint dev", + "build": "mint build" }, "dependencies": { "toml": "^3.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 000000000..bae195950 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,115 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + react: + specifier: ^18.0.0 + version: 18.2.0 + react-dom: + specifier: ^18.0.0 + version: 18.2.0(react@18.2.0) + toml: + specifier: ^3.0.0 + version: 3.0.0 + devDependencies: + '@types/react': + specifier: ^18.0.0 + version: 18.2.36 + '@types/react-dom': + specifier: ^18.0.0 + version: 18.2.16 + typescript: + specifier: ^5.0.0 + version: 5.3.2 + +packages: + + '@types/prop-types@15.7.9': + resolution: {integrity: sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==} + + '@types/react-dom@18.2.16': + resolution: {integrity: sha512-766c37araZ9vxtYs25gvY2wNdFWsT2ZiUvOd0zMhTaoGj6B911N8CKQWgXXJoPMLF3J82thpRqQA7Rf3rBwyJw==} + + '@types/react@18.2.36': + resolution: {integrity: sha512-o9XFsHYLLZ4+sb9CWUYwHqFVoG61SesydF353vFMMsQziiyRu8np4n2OYMUSDZ8XuImxDr9c5tR7gidlH29Vnw==} + + '@types/scheduler@0.16.5': + resolution: {integrity: sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==} + + csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + react-dom@18.2.0: + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + peerDependencies: + react: ^18.2.0 + + react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} + + scheduler@0.23.0: + resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} + + toml@3.0.0: + resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + + typescript@5.3.2: + resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==} + engines: {node: '>=14.17'} + hasBin: true + +snapshots: + + '@types/prop-types@15.7.9': {} + + '@types/react-dom@18.2.16': + dependencies: + '@types/react': 18.2.36 + + '@types/react@18.2.36': + dependencies: + '@types/prop-types': 15.7.9 + '@types/scheduler': 0.16.5 + csstype: 3.1.2 + + '@types/scheduler@0.16.5': {} + + csstype@3.1.2: {} + + js-tokens@4.0.0: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + react-dom@18.2.0(react@18.2.0): + dependencies: + loose-envify: 1.4.0 + react: 18.2.0 + scheduler: 0.23.0 + + react@18.2.0: + dependencies: + loose-envify: 1.4.0 + + scheduler@0.23.0: + dependencies: + loose-envify: 1.4.0 + + toml@3.0.0: {} + + typescript@5.3.2: {}