diff --git a/docs/build/getting-started/capacity-credits.md b/docs/build/getting-started/capacity-credits.md new file mode 100644 index 00000000..c1344b4c --- /dev/null +++ b/docs/build/getting-started/capacity-credits.md @@ -0,0 +1,27 @@ +--- +description: Learn about capacity credits and how to use them +sidebar_label: Capacity Credits +--- + +# Capacity Credits + +:::info +Capacity Credits are the form of payment for usage of the Lit network. They are required when making decryption requests, PKP signing requests, and when executing Lit Actions. +::: + +## Overview + +Capacity Credits are the form of payment for usage of the Lit network. They are required when making decryption requests, PKP signing requests, and when executing Lit Actions. + +While credits are initially restricted to the account that minted them, you can delegate them to allow other Ethereum addresses to utilize your credits. This is particularly useful when building dApps where you want to cover the usage costs for your users. + +## Next Steps + +To learn more about Capacity Credits, please explore the following guides: + +- **Minting a Credit** + - [Via the Lit Explorer](./capacity-credits/minting/via-lit-explorer.md) + - [Via the Lit Contracts SDK](./capacity-credits/minting/via-lit-contracts-sdk.md) +- **Delegating a Credit** + - [Delegate a Credit](./capacity-credits/delegating/delegate-a-credit.md) + - [Use a Delegated Credit](./capacity-credits/delegating/use-delegated-credit.md) \ No newline at end of file diff --git a/docs/build/getting-started/capacity-credits/delegating/delegate-a-credit.md b/docs/build/getting-started/capacity-credits/delegating/delegate-a-credit.md new file mode 100644 index 00000000..95927710 --- /dev/null +++ b/docs/build/getting-started/capacity-credits/delegating/delegate-a-credit.md @@ -0,0 +1,165 @@ +--- +description: Learn how to delegate a capacity credit to an ETH address +sidebar_label: Delegate a Credit +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Delegating a Capacity Credit to an ETH Address + +:::info +Capacity Credits are the form of payment for usage of the Lit network. They are required when making decryption requests, PKP signing requests, and when executing Lit Actions. + +To learn more about what a Capacity Credit is, and how they're used, please go [here](../../../../learn/paying-for-lit/capacity-credits). +::: + +While credits are initially restricted to the account that minted them, you can delegate them to allow other Ethereum addresses to utilize your credits. This is particularly useful when building dApps where you want to cover the usage costs for your users. + +To delegate a credit, you'll need to create a _Capacity Delegation Auth Sig_. This Auth Sig is used as proof that an address has authorization to use a specific Capacity Credit to pay for their requests to a Lit network. + +This guide will demonstrate how to create a Capacity Delegation Auth Sig using the Lit Contracts SDK. + +:::info +The full implementation of the code used in this guide can be found [here](https://github.com/LIT-Protocol/developer-guides-code/tree/v2/capacity-credits/delegating/use-delegated-credit). +::: + +## Prerequisites + +- An Ethereum wallet with [Lit test tokens](../../../../learn/overview/how-it-works/overview#the-lit-protocol-token) on the Chronicle Yellowstone blockchain + - Test tokens can be obtained using the [faucet](https://chronicle-yellowstone-faucet.getlit.dev/) +- A Lit Capacity Credit + - If you don't have a credit, you can mint one using the [Lit Explorer](../minting/via-lit-explorer.md) or the [Lit Contracts SDK](../minting/via-lit-contracts-sdk.md) + +### Required Packages + +- `@lit-protocol/constants` +- `@lit-protocol/lit-node-client` +- `ethers@v5` + + + + +```bash +npm install \ +@lit-protocol/constants \ +@lit-protocol/lit-node-client \ +ethers@v5 +``` + + + + + +```bash +yarn add \ +@lit-protocol/constants \ +@lit-protocol/lit-node-client \ +ethers@v5 +``` + + + + +## The Code Example + +### Instantiating an Ethers Signer + +To delegate a Capacity Credit to another Ethereum address, you'll need to create a Capacity Delegation Auth Sig. The following code uses Ethers.js to create a signer from an Ethereum private key, but any other Ethereum wallet library can be used. + +The address corresponding to `process.env.ETHEREUM_PRIVATE_KEY` **needs** to be the owner of the Capacity Credit. This wallet will be used to produce a [ERC-5573](https://eips.ethereum.org/EIPS/eip-5573) message that authorizes usage of the credit later in the guide. + +```ts +import ethers from "ethers"; +import { LIT_RPC } from "@lit-protocol/constants"; + +const ethersSigner = new ethers.Wallet( + process.env.ETHEREUM_PRIVATE_KEY, + new ethers.providers.JsonRpcProvider(LIT_RPC.CHRONICLE_YELLOWSTONE) +); +``` + +### Instantiating a `LitNodeClient` Instance + +Next we'll instantiate and connect a `LitNodeClient` client specifying the Lit network the Capacity Credit has been minted for. In this case we'll be delegating a credit that was minted for the [DatilTest](../../../../learn/overview/how-it-works/lit-networks/testnets#the-datil-test-network) network. + +```ts +import { LitNodeClient } from "@lit-protocol/lit-node-client"; +import { LIT_NETWORK } from "@lit-protocol/constants"; + +litNodeClient = new LitNodeClient({ + litNetwork: LIT_NETWORK.DatilTest, + debug: false, +}); +await litNodeClient.connect(); +``` + +:::note +You can learn more about the `@lit-protocol/lit-node-client` package and what it offers using the [API reference docs](https://v7-api-doc-lit-js-sdk.vercel.app/classes/lit_node_client_src.LitNodeClient.html). +::: + +## Generating the Capacity Delegation Auth Sig + +On the instance of the `LitNodeClient` client, we can call the `createCapacityDelegationAuthSig` method to generate the Auth Sig. This method will create the ERC-5573 message based on the parameters you provide, sign it with the `dAppOwnerWallet`, and return an object containing the `capacityDelegationAuthSig`. + +```ts +const { capacityDelegationAuthSig } = + await litNodeClient.createCapacityDelegationAuthSig({ + dAppOwnerWallet: ethersSigner, + capacityTokenId, + delegateeAddresses: [delegateeAddress], + uses: "1", + expiration: new Date(Date.now() + 1000 * 60 * 10).toISOString(), // 10 minutes + }); +``` + +### Parameters + +When calling `createCapacityDelegationAuthSig`, the following parameters are required: + +#### `dAppOwnerWallet` + +This is the Ethereum wallet that will be used to sign the ERC-5573 message. This wallet must be the owner of the Capacity Credit you're delegating. + +#### `capacityTokenId` + +This is the ID of the Capacity Credit you're delegating. This is returned to you as `capacityTokenId` when you minted the Capacity Credit. + +:::note +You can find a list of Capacity Credits owned by your address by connecting your wallet to the Lit Explorer and navigating to the [Profile page](https://explorer.litprotocol.com/profile). +::: + +#### `delegateeAddresses` + +This is an array of Ethereum addresses you're delegating the Capacity Credit to. + +#### `uses` + +Specifies the total number of requests allowed across all delegated addresses. When this limit is reached, the Auth Sig becomes invalid for all delegatees. For example, with `uses: "10"`, if one address uses all 10 requests, no other delegated addresses can use the Auth Sig. + +#### `expiration` + +This parameter sets a time limit, represented as a UTC timestamp in seconds, for the Auth Sig. It specifies when the Auth Sig will become invalid and can no longer be used. + +In the above code, this Auth Sig is being set to expire `10 minutes` after it's created. + +### Return Value + +`createCapacityDelegationAuthSig` will return an object with the `capacityDelegationAuthSig` property. This Auth Sig object is what you'll attach to your/your users' Session Signatures when making requests to a Lit network. + +### Summary + +:::info +The full implementation of the code used in this guide can be found [here](https://github.com/LIT-Protocol/developer-guides-code/tree/v2/capacity-credits/delegating/use-delegated-credit). +::: + +After running the above code, you will have created a Capacity Delegation Auth Sig that can be used to pay for a Lit network request on behalf of the delegatee addresses. + +## Next Steps + +- Learn how to [use the Capacity Delegation Auth Sig](./use-delegated-credit) to pay for requests to a Lit network. diff --git a/docs/build/getting-started/capacity-credits/delegating/use-delegated-credit.md b/docs/build/getting-started/capacity-credits/delegating/use-delegated-credit.md new file mode 100644 index 00000000..fdbc88ce --- /dev/null +++ b/docs/build/getting-started/capacity-credits/delegating/use-delegated-credit.md @@ -0,0 +1,180 @@ +--- +description: Learn how to use a delegated credit to make requests to a Lit network +sidebar_label: Use a Delegated Credit +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Using a Delegated Credit to Make Requests + +:::info +Capacity Credits are the form of payment for usage of the Lit network. They are required when making decryption requests, PKP signing requests, and when executing Lit Actions. + +To learn more about what a Capacity Credit is, and how they're used, please go [here](../../../../learn/paying-for-lit/capacity-credits). + +To learn more about how to delegate a Capacity Credit to an ETH address, go [here](./delegate-a-credit). +::: + +When making requests to the Lit network, you must provide [Session Signatures](../../../../learn/authentication/session-sigs). When making requests to the network that require payment, you must also attach a _Capacity Delegation Auth Signature_ to your Session Signatures. This Auth Sig tells the Lit network which Capacity Credit to use for paying for your network usage, and also acts as proof that you have permission to use the Capacity Credit for payment. + +This guide will demonstrate how to attach a Capacity Delegation Auth Signature to Session Signatures when making a request to a Lit network. + +:::info +The full implementation of the code used in this guide can be found [here](https://github.com/LIT-Protocol/developer-guides-code/tree/v2/capacity-credits/delegating/use-delegated-credit). +::: + +## Prerequisites + +- An understanding of [Session Signatures](../../../../learn/authentication/session-sigs) +- An understanding of [Capacity Credits](../../../../learn/paying-for-lit/capacity-credits) and what type of Lit network requests require payment +- A Capacity Delegation Auth Sig + - If you don't have a Capacity Delegation Auth Sig, you can create one by following the instructions [here](./delegate-a-credit). + +### Required Packages + +- `@lit-protocol/constants` +- `@lit-protocol/lit-node-client` +- `@lit-protocol/auth-helpers` +- `ethers@v5` + + + + +```bash +npm install \ +@lit-protocol/constants \ +@lit-protocol/lit-node-client \ +@lit-protocol/auth-helpers \ +ethers@v5 +``` + + + + + +```bash +yarn add \ +@lit-protocol/constants \ +@lit-protocol/lit-node-client \ +@lit-protocol/auth-helpers \ +ethers@v5 +``` + + + + +## The Code Example + +### Instantiating an Ethers Signer + +This `ethersSigner` will be used to sign the Auth Sig as apart of generating the Session Signatures that the Capacity Delegation Auth Sig will be attached to. + +The address corresponding to `process.env.ETHEREUM_PRIVATE_KEY` **needs** to be one of the addresses that the Capacity Delegation Auth Sig authorizes (i.e. the address was included in the `delegateeAddresses` array when the Capacity Delegation Auth Sig was created). + +```ts +import ethers from "ethers"; +import { LIT_RPC } from "@lit-protocol/constants"; + +const ethersSigner = new ethers.Wallet( + process.env.ETHEREUM_PRIVATE_KEY, + new ethers.providers.JsonRpcProvider(LIT_RPC.CHRONICLE_YELLOWSTONE) +); +``` + +### Instantiating a `LitNodeClient` Instance + +Next we'll instantiate and connect a `LitNodeClient` client specifying the Lit network the Capacity Credit has been minted for. In this case we'll be using a credit that was minted for the [DatilTest](../../../../learn/overview/how-it-works/lit-networks/testnets#the-datil-test-network) network. + +```ts +import { LitNodeClient } from "@lit-protocol/lit-node-client"; +import { LIT_NETWORK } from "@lit-protocol/constants"; + +litNodeClient = new LitNodeClient({ + litNetwork: LIT_NETWORK.DatilTest, + debug: false, +}); +await litNodeClient.connect(); +``` + +:::note +You can learn more about the `@lit-protocol/lit-node-client` package and what it offers using the [API reference docs](https://v7-api-doc-lit-js-sdk.vercel.app/classes/lit_node_client_src.LitNodeClient.html). +::: + +### Generating Session Sigs with the Delegation Auth Sig + +Using the [getSessionSigs](https://v7-api-doc-lit-js-sdk.vercel.app/classes/lit_node_client_src.LitNodeClient.html#getSessionSigs) method, we can generate Session Signatures that contain the Capacity Delegation Auth Sig: + +```ts +const sessionSigs = await litNodeClient.getSessionSigs({ + chain: "ethereum", + expiration: new Date(Date.now() + 1000 * 60 * 10).toISOString(), + capabilityAuthSigs: [capacityDelegationAuthSig], // <--- Here is where we + // attach the Capacity Delegation Auth Sig to the Session Signatures + resourceAbilityRequests: [ + { + resource: new LitActionResource("*"), + ability: LIT_ABILITY.LitActionExecution, + }, + ], + authNeededCallback: async ({ + resourceAbilityRequests, + expiration, + uri, + }) => { + const toSign = await createSiweMessageWithRecaps({ + uri: uri!, + expiration: expiration!, + resources: resourceAbilityRequests!, + walletAddress: ethersSigner.address, + nonce: await litNodeClient.getLatestBlockhash(), + litNodeClient, + }); + + return await generateAuthSig({ + signer: ethersSigner, + toSign, + }); + }, +}); +``` + +This line from the above code is how we're specifying the Capacity Delegation Auth Sig (that's delegating credit usage to `ethersSigner.address`) to pay for our request later in this guide: + +```ts +capabilityAuthSigs: [capacityDelegationAuthSig] +``` + +:::note +This guide assumes that you've already created a Capacity Delegation Auth Sig and assigned it to a variable with the name: `capacityDelegationAuthSig`. + +If you don't have a Capacity Delegation Auth Sig, you can create one by following the instructions [here](./delegate-a-credit). +::: + +## Making a Request + +After executing the above code, you will now have Session Signatures that contain a Capacity Delegation Auth Signature. These Session Signatures can be used to make any requests to the Lit network that require payment. + +Here is an example of using the Session Signatures to execute a simple Lit Action: + +```ts +await litNodeClient.executeJs({ + sessionSigs, + code: `(() => console.log("It works!"))();`, +}); +``` + +## Summary + +:::info +The full implementation of the code used in this guide can be found [here](https://github.com/LIT-Protocol/developer-guides-code/tree/v2/capacity-credits/delegating/use-delegated-credit). +::: + +This guide has demonstrated how to attach a Capacity Delegation Auth Signature to Session Signatures, and use those Session Signatures to make a request to the Lit network that requires payment. + +## Next Steps diff --git a/docs/build/getting-started/capacity-credits/minting/via-lit-contracts-sdk.md b/docs/build/getting-started/capacity-credits/minting/via-lit-contracts-sdk.md new file mode 100644 index 00000000..b84806cd --- /dev/null +++ b/docs/build/getting-started/capacity-credits/minting/via-lit-contracts-sdk.md @@ -0,0 +1,173 @@ +--- +description: Learn how to mint capacity credits via the Lit Explorer +sidebar_label: Via the Lit Contracts SDK +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Minting Capacity Credits via the Lit Contracts SDK + +:::info +Capacity Credits are the form of payment for usage of the Lit network. They are required when making decryption requests, PKP signing requests, and when executing Lit Actions. + +To learn more about what a Capacity Credit is, and how they're used, please go [here](../../../../learn/paying-for-lit/capacity-credits). +::: + +Capacity Credits can be minted by making requests to the NFT contract that is deployed on the [Chronicle Yellowstone](../../../../learn/overview/how-it-works/lit-blockchains/chronicle-yellowstone) rollup blockchain. The following code will demonstrate how to connect to Chronicle Yellowstone via the Lit RPC URL, and send a transaction to the blockchain to mint a new Capacity Credit. + +:::info +The full implementation of the code used in this guide can be found [here](https://github.com/LIT-Protocol/developer-guides-code/tree/v2/capacity-credits/minting/via-contracts-sdk). +::: + +## Prerequisites + +- An Ethereum wallet with [Lit test tokens](../../../../learn/overview/how-it-works/overview#the-lit-protocol-token) on the Chronicle Yellowstone blockchain + - Test tokens can be obtained using the [faucet](https://chronicle-yellowstone-faucet.getlit.dev/) + +### Required Packages + +- `@lit-protocol/constants` +- `@lit-protocol/contracts-sdk` +- `ethers@v5` + + + + +```bash +npm install \ +@lit-protocol/constants \ +@lit-protocol/contracts-sdk \ +ethers@v5 +``` + + + + + +```bash +yarn add \ +@lit-protocol/constants \ +@lit-protocol/contracts-sdk \ +ethers@v5 +``` + + + + +## The Code Example + +### Instantiating an Ethers Signer + +To mint the Capacity Credit you'll need to sign a transaction with an Ethereum wallet that holds Lit test tokens. The following code uses Ethers.js to create a signer from an Ethereum private key, but any other Ethereum wallet library can be used. + +Along with the private key, we'll also need to specify the RPC URL for the Chronicle Yellowstone network, so that the wallet knows which blockchain to send the transaction to. + +```ts +import ethers from "ethers"; +import { LIT_RPC } from "@lit-protocol/constants"; + +const ethersSigner = new ethers.Wallet( + process.env.ETHEREUM_PRIVATE_KEY, + new ethers.providers.JsonRpcProvider(LIT_RPC.CHRONICLE_YELLOWSTONE) +); +``` + +### Instantiating a `LitContracts` Client + +Next we'll instantiate and connect a `LitContracts` client using the signer we created above, specifying the Lit network we'd like to mint the Capacity Credit for. In this case we'll be minting the credit to be used on the [DatilTest](../../../../learn/overview/how-it-works/lit-networks/testnets#the-datil-test-network) network. + +```ts +import { LitContracts } from "@lit-protocol/contracts-sdk"; +import { LIT_NETWORK } from "@lit-protocol/constants"; + +const litContractClient = new LitContracts({ + signer: ethersSigner, + network: LIT_NETWORK.DatilTest, +}); +await litContractClient.connect(); +``` + +:::note +You can learn more about the `@lit-protocol/contracts-sdk` package and what is offers using the [API reference docs](https://v7-api-doc-lit-js-sdk.vercel.app/classes/contracts_sdk_src.LitContracts.html). +::: + +## Minting a Capacity Credit + +On the instance of the `LitContracts` client, we can call the `mintCapacityCreditsNFT` method to mint a new Capacity Credit. Calling this method will create and sign a transaction to the Chronicle Yellowstone blockchain, paying for both the mint cost of the Capacity Credit and transaction gas in the Lit test token. + +```ts +const capacityCreditInfo = await litContractClient.mintCapacityCreditsNFT({ + requestsPerKilosecond: 80, + // requestsPerSecond: 10, + // requestsPerDay: 14400, + daysUntilUTCMidnightExpiration: 1, +}); +``` + +### Parameters + +When minting a credit, the following parameters are required: + +#### `requestsPerX` + +This parameter is the capacity you're reserving on the Lit network. This value is the maximum number of requests your Capacity Credit can be used for in a given day. Once your credit has been used for this number of requests, you will receive a Rate Limit error if it's used again before midnight UTC time. + +For convenience, any one of the following properties can be used: + +- `requestsPerKilosecond` +- `requestsPerSecond` +- `requestsPerDay` + +:::note +The Lit contracts SDK also contains several [helper methods](https://v7-api-doc-lit-js-sdk.vercel.app/modules/contracts_sdk_src.html) to convert between these different units. + +For example, [requestsToDay](https://v7-api-doc-lit-js-sdk.vercel.app/functions/contracts_sdk_src.requestsToDay.html) will convert the number of requests per `second` or `kilosecond` to the equivalent number of requests per day. +::: + +#### `daysUntilUTCMidnightExpiration` + +This parameter sets the date the Capacity Credit will expire. The credit expires at `12:00 AM (midnight) Coordinated Universal Time (UTC)` on the specified date. + +:::note +The actual expiration time in your local timezone may be different due to the UTC conversion. + +For example, if you're in New York (ET), a credit set to expire on June 1st will actually expire on May 31st at 8:00 PM ET. +::: + +### Return Value + +After the transaction is processed and included in a block, you will be returned the following Capacity Credit object: + +``` +{ + rliTxHash: string; + capacityTokenId: number; + capacityTokenIdStr: string; +} +``` + +Where: + +- `rliTxHash` Is the transaction hash of the transaction that minted the credit. +- `capacityTokenId` Is the generated ID for the new credit as a `number`. +- `capacityTokenIdStr` Is the generated ID for the new credit as a `string`. + +You will use either `capacityTokenId` or `capacityTokenIdStr` to identify the Capacity Credit you would like use when paying for request to the Lit network. + +## Summary + +:::info +The full implementation of the code used in this guide can be found [here](https://github.com/LIT-Protocol/developer-guides-code/tree/v2/capacity-credits/minting/via-contracts-sdk). +::: + +After running the above code, you will have minted a new Capacity Credit that can be used to pay for usage of the Lit network. The credit can be used `requestsPerX` numbers of times a day, and will expire `daysUntilUTCMidnightExpiration` days from now at `12:00 AM (midnight) Coordinated Universal Time (UTC)`. + +## Next Steps + +- If you want to allow others (such as your users) to use your minted capacity credits, you'll need to [delegate the credit](../delegating/to-an-eth-address) to them so that you can pay for their network usage on their behalf. diff --git a/docs/build/getting-started/capacity-credits/minting/via-lit-explorer.md b/docs/build/getting-started/capacity-credits/minting/via-lit-explorer.md new file mode 100644 index 00000000..06e6920b --- /dev/null +++ b/docs/build/getting-started/capacity-credits/minting/via-lit-explorer.md @@ -0,0 +1,103 @@ +--- +description: Learn how to mint capacity credits via the Lit Explorer +sidebar_label: Via the Lit Explorer +--- + +# Minting Capacity Credits via the Lit Explorer + +:::info +Capacity Credits are the form of payment for usage of the Lit network. They are required when making decryption requests, PKP signing requests, and when executing Lit Actions. + +To learn more about what a Capacity Credit is, and how they're used, please go [here](../../../../learn/paying-for-lit/capacity-credits). +::: + +The [Lit Explorer](https://explorer.litprotocol.com/) streamlines the process of minting Capacity Credits, along with other common Lit functionalities such as minting PKPs and creating Lit Actions. This guide will demonstrate how to mint a new Capacity Credit using the Lit Explorer. + +## Prerequisites + +- An Ethereum wallet with [Lit test tokens](../../../../learn/overview/how-it-works/overview#the-lit-protocol-token) on the Chronicle Yellowstone blockchain + - Test tokens can be obtained using the [faucet](https://chronicle-yellowstone-faucet.getlit.dev/) +- You'll also need to add the Chronicle Yellowstone [chain facts](../../../../learn/overview/how-it-works/lit-blockchains/chronicle-yellowstone#connecting-to-chronicle-yellowstone) to your wallet, so that you can send transaction to the network + +## Setup + +1. Navigate to the [Lit Explorer](https://explorer.litprotocol.com/) dApp. + +![The Lit Explorer](/build/capacity-credits/minting/via-lit-explorer/lit-explorer.png) + +2. Connect your wallet to the explorer by clicking the `Connect Wallet` button. + +![Connecting Wallet](/build/capacity-credits/minting/via-lit-explorer/connecting-wallet.png) + +3. Select the Lit network you'd like to mint the Capacity Credit for. + +This is done using the network dropdown next to the previously clicked `Connect Wallet` button. By default, the `Datil` network is selected - the Datil network is the decentralized mainnet beta Lit network. For an overview of the available Lit networks, go [here](../../../connecting-to-a-lit-network/connecting.md). + +For this guide, we're going to select the `DatilTest` network: + +![Selecting Network](/build/capacity-credits/minting/via-lit-explorer/selecting-datil-test.png) + +## Minting a Capacity Credit + +The following UI is how we'll mint a new Capacity Credit: + +![Minting Credit](/build/capacity-credits/minting/via-lit-explorer/minting-credit.png) + +### Requests Per Kilosecond + +This parameter is the capacity you're reserving on the Lit network measured in requests per kilosecond. This value is the maximum number of requests your Capacity Credit can be used for in a given day. Once your credit has been used for this number of requests, you will receive a Rate Limit error if it's used again before midnight UTC time. + +For convenience, the number inputted is converted to the number of requests per day. By default, this value is set to `14` requests per kilosecond which is also `1,204` request per day. + +### UTC Midnight Expiration Date + +This parameter sets the date the Capacity Credit will expire. The credit expires at 12:00 AM (midnight) Coordinated Universal Time (UTC) on the specified date. + +:::note +The actual expiration time in your local timezone may be different due to the UTC conversion. For example, if you're in New York (ET), a credit set to expire on June 1st will actually expire on May 31st at 8:00 PM ET. +::: + +### Estimated Cost + +This is the estimated cost, in Lit test tokens, to mint the Capacity Credit with the parameters you have selected. + +:::note +Important considerations: + +- The estimated cost does not include the gas fee for the transaction. +- The actual cost may fluctuate depending on network usage: + - It may increase as more users reserve network capacity. + - It may decrease as previously reserved network capacity expires. +::: + +### Buying the Credit + +After selecting your credit parameters, click the `Buy Capacity Credits` button to create the transaction to the Chronicle Yellowstone blockchain to purchase your credit. + +You should be prompted by your Ethereum wallet to sign and submit the transaction to the blockchain: + +![Sign Tx](/build/capacity-credits/minting/via-lit-explorer/sign-tx.png) + +After signing and submitting the transaction to the network, you will receive a confirmation notification similar to: + +![Confirmation Notification](/build/capacity-credits/minting/via-lit-explorer/confirmation-notification.png) + +You can click the transaction hash in the notification to be taken to the Lit block explorer to view the transaction details. + +### Getting the Credit Info + +In order to use your new Capacity Credit to pay for the usage of the Lit network, you need to know the `Token ID` of the credit. You find this for the new credit, as well as all other credits minted by your account, by navigating the the [Profile](https://explorer.litprotocol.com/profile) page. + +On this page you will see all of the PKPs and RLI (Capacity Credit) tokens that are associated with your account. + +![Profile](/build/capacity-credits/minting/via-lit-explorer/profile.png) + +In the `Your RLI Tokens` table, you will see the info for the Capacity Credit you just minted. The `Token ID` (in the screenshot that's `751`) is the identifier for your credit, and the value you will use when when making requests to the Lit network. + +## Summary + +After running the above code, you will have minted a new Capacity Credit that can be used to pay for usage of the Lit network. The credit can be used the specified number of times a day, and will expire on the selected date at `12:00 AM (midnight) Coordinated Universal Time (UTC)`. + +## Next Steps + +- If you want to allow others (such as your users) to use your minted capacity credits, you'll need to [delegate the credit](../delegating/to-an-eth-address) to them so that you can pay for their network usage on their behalf. diff --git a/docs/build/lit-actions/broadcast-and-collect.md b/docs/build/lit-actions/broadcast-and-collect.md index 3bf156a5..1f37edd6 100644 --- a/docs/build/lit-actions/broadcast-and-collect.md +++ b/docs/build/lit-actions/broadcast-and-collect.md @@ -1 +1,32 @@ -# Broadcast a Request to all Lit Nodes and Collect Their Responses \ No newline at end of file +# Broadcast and Collect Within an Action + +## Overview + +The `broadcastAndCollect` function let's you run an operation on every node in the Lit network, collect their responses, and aggregate them into a single data set. This is useful if you'd like to perform additional operations over their responses, such as calculating a median or average. + +When you call this function, the responses from each node will be grouped together before being returned back to each node for further processing. + +TODO: Full Code example link + +# Broadcasting and Collecting a fetch response + +The following Lit Action uses `broadcastAndCollect` to fetch the forecast using the weather.gov API before combining the responses from each Lit node into a single array. + +```js +async () => { + const url = "https://api.weather.gov/gridpoints/TOP/31,80/forecast"; + const resp = await fetch(url).then((response) => response.json()); + const temp = resp.properties.periods[0].temperature; + + const temperatures = await Lit.Actions.broadcastAndCollect({ + name: "temperature", + value: temp, + }); + + // at this point, temperatures is an array of all the values that all the nodes got + const median = temperatures.sort()[Math.floor(temperatures.length / 2)]; + Lit.Actions.setResponse({response: median}); +})(); +``` + + diff --git a/docs/build/lit-actions/conditional-signing.md b/docs/build/lit-actions/conditional-signing.md index 0aaaaee7..9b149026 100644 --- a/docs/build/lit-actions/conditional-signing.md +++ b/docs/build/lit-actions/conditional-signing.md @@ -1 +1,66 @@ -# Conditionally Sign with a PKP \ No newline at end of file +# Conditional Signing + +## Overview +Lit Actions inherit the powerful condition checking ability that Lit Protocol utilizes for [access control](../access-control/intro). You can easily check on or off-chain conditions inside of Lit Actions to generate proofs and condition-based transaction automations. + +The below example will check if the user has at least 1 Wei on Ethereum, only returning a signature if they do. + +## Code Example + +The complete code example is available in the [Lit Developer Guides Code Repository](https://github.com/LIT-Protocol/developer-guides-code/tree/master/conditional-signing). There is both a browser and Node.js implementation of the code. + +### Example Lit Action + +This function performs a condition check on the authenticated user's Ethereum balance (the user who signed the Sign-in With Ethereum [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) message to create the `AuthSig`), returning a boolean. This is then used to determine whether or not the PKP will sign `dataToSign` or not. + +The below example will check if the user has at least 1 Wei on Ethereum, only returning a signature if they do. It uses the [`checkConditions`](https://actions-docs.litprotocol.com/#checkconditions) function from the [Lit Actions SDK](https://actions-docs.litprotocol.com/). This performs a conditional check on the user's Ethereum balance, checking the balance of the wallet address that signed the Sign-in With Ethereum [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) when creating the `AuthSig`, which is passed in as an argument to the Lit Action. The boolean returned will be used to determine whether the wallet will be used to sign `dataToSign` or not. + +:::note +The `toSign` data is required to be an array of 8-bit integers. An example of this is shown below: + +```ts +dataToSign: ethers.utils.arrayify(ethers.utils.keccak256([1, 2, 3, 4, 5])), +``` +::: + +:::info +In the below code example, `sigShare` is a magic value within a Lit Action that will be automatically returned for you. +::: + +```jsx +async () => { + try { + // test an access control condition + const testResult = await Lit.Actions.checkConditions({ + conditions, + authSig, + chain, + }); + + if (!testResult) { + LitActions.setResponse({ response: "address does not have 1 or more Wei on Ethereum Mainnet" }); + return; + } + + const sigShare = await LitActions.signEcdsa({ + toSign: dataToSign, + publicKey, + sigName: "sig", + }); + } catch (error) { + LitActions.setResponse({ response: error.message }); + } +}; +``` +## Prerequisites + +- Knowlege of [SessionSigs](../authentication/session-sigs/intro) +- Knowledge of how to [generate an AuthSig](../migrations/6.0.0.md#generate-an-authsig) +- Basic understanding of [Lit Actions](../serverless-signing/quick-start) + +## Summary +This guide demonstrates how to use Lit Actions to conditionally sign a message or transaction. + +If you'd like to learn more about Lit Actions, check out the [Lit Actions SDK](https://actions-docs.litprotocol.com/), or our [Advanced Topics](https://developer.litprotocol.com/category/advanced-topics-1) section on Lit Actions. + + diff --git a/docs/build/lit-actions/decryption.md b/docs/build/lit-actions/decryption.md index 0e940d73..bc8e200f 100644 --- a/docs/build/lit-actions/decryption.md +++ b/docs/build/lit-actions/decryption.md @@ -1 +1,91 @@ -# Decrypt within a Lit Action \ No newline at end of file +# Decrypting within a Lit Action + +## Overview + +Decryption with Lit is typically performed client-side by an authorized user at the time of access. This process is documented [here](../access-control/quick-start.md). However, an alternative method of decryption is supported using Lit Actions. Specifically, the `decryptAndCombine` function can be used to decrypt data within a Lit Action. This is useful for performing operations over sensitive data, where the data itself remains private within the confines of each Lit node's Trusted Execution Environment (TEE). You can learn more about Lit's architecture [here](../../resources/how-it-works#sealed-and-confidential-hardware.md). + +When you call `decryptAndCombine`, each Lit node's decryption shares are collected and combined on a single node and used to decrypt the given content. + +The following doc will provide a complete walkthrough of using `decryptAndCombine`. We'll start by encrypting a string client-side before using a Lit Action to decrypt it. At the bottom of the page you'll find a complete example that demonstrates how you can use this functionality to decrypt an API key and perform a remote API call from within an Action. + +TODO: Full Code example link + +# Encrypting content +The first step is to encrypt your data. The encryption operation will be performed client-side *outside* of your Lit Action using the `LitNodeClient`: + +```js + const chain = 'ethereum'; + const accessControlConditions = [ + { + contractAddress: '', + standardContractType: '', + chain, + method: 'eth_getBalance', + parameters: [':userAddress', 'latest'], + returnValueTest: { + comparator: '>=', + value: '0', + }, + }, + ]; + const message = 'Hello world'; + const client = new LitNodeClient({ + litNetwork: "datil-dev" + }); + await client.connect(); + const { ciphertext, dataToEncryptHash } = await LitJsSdk.encryptString( + { + accessControlConditions, + sessionSigs: {}, // your session + chain, + dataToEncrypt: message, + }, + client + ); + + console.log("cipher text:", ciphertext, "hash:", dataToEncryptHash); +``` +Let's break this down. The first step was creating your Access Control Condition (ACC), which is used to specify who or under what conditions your data should be able to be decrypted. + +The second step was actually encrypting the static content (string, file, zip, etc...) using the `encryptString` function. This returns a `ciphertext` and `dataToEncryptHash`. The `ciphertext`, `dataToEncryptHash`, chain data, and any other metadata (such as your `accessControlConditions`) should be stored on your storage provider of choice. A solid choice is IPFS. + +## Using IPFS CID as an Access Control Parameter +For this example, you can set your Access Control parameter as `currentActionIpfsId` which can be accomplished using the snippet below. This will mean that only a specific Lit Action (based on the IPFS CID where it has been deployed) will be able to decrypt your data. No other party will ever have access. This is useful for situations where you want to restrict access to sensitive information, like an API key, so that it can only be decrypted by a specific Lit Action. + +```js +{ + contractAddress: '', + standardContractType: '', + chain: 'ethereum', + method: '', + parameters: [':currentActionIpfsId'], + returnValueTest: { + comparator: '=', + value: '', + }, +} +``` + +## Using decryptAndCombine + +We can now use the `ciphertext` and `dataToEncryptHash` that we got earlier during the encryption step and pass it into our Lit Action. + +In the below example we set the `authSig` to `null` as a way to tell the Lit Action runtime to use the `authSig` which was provided to the node when you call `executeJs` which returns `sessionSigs`. If you wish you may provide a different Auth Signature if the one provided from the session is not relevant to your use case. You can learn more about authentication and creating session signatures using these [docs](../authentication/session-sigs/intro.md). + +```js +async () => { + const resp = await Lit.Actions.decryptAndCombine({ + accessControlConditions, + ciphertext, + dataToEncryptHash, + authSig: null, + chain: 'ethereum', + }); + + Lit.Actions.setResponse({ response: resp }); +} + +``` + +## Complete Example: Decrypting an API Key From Within an Action +The following example demonstrates how you can decrypt an API key within a Lit Action. Once decrypted, the API key can be used to perform a remote API call. Check out the complete code example [here](https://github.com/LIT-Protocol/developer-guides-code/tree/master/decrypt-api-key-in-action). diff --git a/docs/build/lit-actions/eip-191-signing.md b/docs/build/lit-actions/eip-191-signing.md index 8a819177..4891c4ce 100644 --- a/docs/build/lit-actions/eip-191-signing.md +++ b/docs/build/lit-actions/eip-191-signing.md @@ -1 +1,43 @@ -# Sign with EIP-191 \ No newline at end of file +# Signing within a Lit Action using EIP-191 + +## Overview + +Lit Actions offer the ability to use [EIP-191](https://eips.ethereum.org/EIPS/eip-191?ref=blog.spruceid.com) to sign a message instead of a transaction or raw signature. This is done with the Lit Actions method [ethPersonalSignMessageEcdsa](https://actions-docs.litprotocol.com/#ethpersonalsignmessageecdsa). + +It will prepend to your message: `"\x19Ethereum Signed Message:\n"` and the length of the message, then hash and sign it according to the EIP-191 standard. + +## Code Example + +The complete code example is available in the [Lit Developer Guides Code Repository](https://github.com/LIT-Protocol/developer-guides-code/tree/master/eip-191-signing). There you can find a Node.js and browser implementation of this example code. + +### Example Lit Action + +The return value of `ethPersonalSignMessageEcdsa` (the `sigShare` variable in this example) is set to a boolean value of `true` if the signature was successfully generated, and `false` otherwise. The Lit Action will also return the complete signature as an object under the `sigName` key. + +```jsx +const _litActionCode = async () => { + try { + const sigShare = await LitActions.ethPersonalSignMessageEcdsa({ + message: dataToSign, + publicKey, + sigName, + }); + LitActions.setResponse({ response: sigShare }); + } catch (error) { + LitActions.setResponse({ response: error.message }); + } +}; + +export const litActionCode = `(${_litActionCode.toString()})();`; +``` +## Prerequisites + +- Basic understanding of [PKPs](../../../user-wallets/pkps/overview) +- Basic understanding of [Lit Actions](../serverless-signing/quick-start) + +## Summary +This guide demonstrates how to sign an EIP-191 message using Lit Actions. + +If you'd like to learn more about Lit Actions, check out the [Lit Actions SDK](https://actions-docs.litprotocol.com/), or our [Advanced Topics](https://developer.litprotocol.com/category/advanced-topics-1) section on Lit Actions. + + diff --git a/docs/build/lit-actions/get-rpc-urls.md b/docs/build/lit-actions/get-rpc-urls.md index 3b5a5d0b..06bbfb28 100644 --- a/docs/build/lit-actions/get-rpc-urls.md +++ b/docs/build/lit-actions/get-rpc-urls.md @@ -1 +1,37 @@ -# Get Blockchain RPC URLs within a Lit Action \ No newline at end of file +# Get Blockchain RPC URLs within a Lit Action + +## Overview + +You can use the `getRpcUrl` function within a Lit Action to call make an RPC call to a given blockchain. This can be useful for sending transactions, calling contract methods, pulling block data, and other related use cases. + +By default, this RPC call will be made by all the nodes in parallel. You can check out an example of making this call on a single node below. + +TODO: Full Code example link + +## Getting the RPC context from all nodes +```js +async () => { + const rpcUrl = await Lit.Actions.getRpcUrl({ chain: "ethereum" }); + const blockByNumber = await provider.send("eth_getBlockByNumber", ["latest", false]); + const transactions = blockByNumber.transactions; + Lit.Actions.setResponse(JSON.stringify(transactions)); +} +``` +In the above example we are requesting every node to use their `rpcUrl` for the `ethereum` main net to pull the `lastest` block which has settled and return the transactions which it contained. This operation will be performed by all nodes. + +## Getting the RPC context from a single node + +```js +async () => { + let res = await Lit.Actions.runOnce({ waitForResponse: true, name: "txnSender" }, async () => { + const rpcUrl = await Lit.Actions.getRpcUrl({ chain: "ethereum" }); + const blockByNumber = await provider.send("eth_getBlockByNumber", ["latest", false]); + const transactions = blockByNumber.transactions; + return res; + }); + // get the broadcast result from the single node which executed the block query and return it from all clients. + Lit.Actions.setResponse(res); +} +``` + +For information on `runOnce` see [here](./run-once.md) diff --git a/docs/build/lit-actions/http-requests.md b/docs/build/lit-actions/http-requests.md index b6ef3045..1d4f9daf 100644 --- a/docs/build/lit-actions/http-requests.md +++ b/docs/build/lit-actions/http-requests.md @@ -1 +1,105 @@ -# Make HTTP Requests Using Fetch \ No newline at end of file +# Using Fetch + +## Overview +Unlike traditional smart contract ecosystems, Lit Actions can natively talk to the external world. This is useful for things like fetching data from the web, or sending API requests to other services. + +The Lit Action below will get the current temperature from the [National Weather Service](https://www.weather.gov/) API, and ONLY sign a txn if the temperature is forecast to be **above 60 degrees F**. Since you can put this HTTP request and logic that uses the response directly in your Lit Action, you don't have to worry about using a 3rd party oracle to pull data in. + +### How it works + +The HTTP request will be sent out by all the Lit Nodes in parallel, and consensus is based on at least 2/3 of the nodes getting the same response. If less than 2/3 nodes get the same response, then the user can not collect the signature shares above the threshold and therefore cannot produce the final signature. Note that your HTTP request will be sent N times where N is the number of nodes in the Lit Network, because it's sent from every Lit Node in parallel. + +:::warning +Be careful about how many requests you're making and note that running a request on all the Lit Nodes may trigger rate limiting issues on some servers. If you'd like to make a request for a single time per Lit action, try [runOnce](./run-on-single-node.md) +::: + +## Example + +TODO: Full Code example link + +### Lit Action code + +:::note +`toSign` data is required to be in 32 byte format. + +The `ethers.utils.arrayify(ethers.utils.keccak256(...)` can be used to convert the `toSign` data to the correct format. +::: + +```jsx +async () => { + const url = "https://api.weather.gov/gridpoints/TOP/31,80/forecast"; + const resp = await fetch(url).then((response) => response.json()); + const temp = resp.properties.periods[0].temperature; + + // only sign if the temperature is above 60. if it's below 60, exit. + if (temp < 60) { + return; + } + + // this requests a signature share from the Lit Node + // the signature share will be automatically returned in the HTTP response from the node + // all the params (toSign, publicKey, sigName) are passed in from the LitJsSdk.executeJs() function + const sigShare = await LitActions.signEcdsa({ toSign, publicKey , sigName }); +}; +``` + +### Execute Lit Action code on Lit nodes + +```jsx +const runLitAction = async () => { + const message = new Uint8Array( + await crypto.subtle.digest('SHA-256', new TextEncoder().encode('Hello world')) + ); + + const litNodeClient = new LitJsSdk.LitNodeClient({ + alertWhenUnauthorized: false, + litNetwork: "datil-dev", + debug: true, + }); + await litNodeClient.connect(); + const signatures = await litNodeClient.executeJs({ + code: litActionCode, + sessionSigs, + // all jsParams can be used anywhere in your litActionCode + jsParams: { + toSign: message, + publicKey: + "0x02e5896d70c1bc4b4844458748fe0f936c7919d7968341e391fb6d82c258192e64", + sigName: "sig1", + }, + }); + console.log("signatures: ", signatures); +}; + +runLitAction(); +``` + +## Using fetch() to write data +You can also use fetch() inside a Lit Action to write data, but you **must be careful** (because the HTTP request will be run N times where N is the number of Lit Nodes). On Datil networks, N is 10, so any fetch() request will be sent to the server 10 times. + +**This is safe**, however, if the place you're writing the data to is *idempotent*. Idempotent means that applying the same operation over and over will not change the result. So for example, a SQL Insert is not idempotent, becuase if you run it 10 times, it will create 10 rows. On the other hand, a SQL Update is idempotent, because if you run it 10 times, it will only update the row once. So if you're using fetch() to write data, make sure the server you're writing to is idempotent. + +### Lit Action code + +```jsx +const fetchWeatherApiResponse = async () => { + const url = "https://api.weather.gov/gridpoints/LWX/97,71/forecast"; + let toSign; + try { + const response = await fetch(url).then((res) => res.json()); + const forecast = response.properties.periods[day]; + toSign = { temp: forecast.temperature + " " + forecast.temperatureUnit, shortForecast: forecast.shortForecast }; + const sigShare = await LitActions.signEcdsa({ toSign, publicKey, sigName }); + } catch(e) { + console.log(e); + } + LitActions.setResponse({ response: JSON.stringify(toSign) }); +}; + +fetchWeatherApiResponse(); +``` +## Prerequisites + +- Familiarity with JavaScript +- Basic understanding of [serverless signing](../serverless-signing/quick-start.md) + diff --git a/docs/build/lit-actions/overview.md b/docs/build/lit-actions/overview.md index ed9fcdca..c5b8350f 100644 --- a/docs/build/lit-actions/overview.md +++ b/docs/build/lit-actions/overview.md @@ -1 +1,69 @@ -# Lit Actions (Decentralized Compute) \ No newline at end of file +# Decentralized Compute with Lit Actions + +Lit Actions are immutable JavaScript programs that run on a decentralized Lit network. They enable powerful, blockchain-agnostic applications with built-in cryptographic capabilities like signing and encryption. + +## What Makes Lit Actions Different + +Lit Actions are a paradigm shift in decentralized computation, offering a flexible and powerful tool for creating sophisticated decentralized applications. Here's some of what makes them unique: + +- **JavaScript-Based**: They're written in JavaScript, executed in a secure Deno environment, and support the importing of third-party libraries such as [@solana/web3.js](https://github.com/solana-labs/solana-web3.js). +- **Built-in Ethers.js and Lit SDK Support**: Lit Actions have built-in support for Ethers.js (`v5.7.0`) and the Lit SDK, making it easy to interact with Ethereum, other EVM based blockchains, and the Lit Network. +- **Blockchain Agnostic**: Unlike traditional smart contracts, Lit Actions can interact with multiple blockchains, allowing for cross-chain applications and broader interoperability. +- **Off-Chain Capabilities**: Lit Actions can make HTTP requests and interact directly with off-chain APIs, eliminating the need for complex oracle systems. +- **Programmable Signing**: Through integration with [Programmable Key Pairs (PKPs)](../../user-wallets/pkps/overview.md), Lit Actions enable custom and automated, condition-based signing. +- **Decentralized Execution**: Lit Actions run on the distributed Lit Network, ensuring high availability and resistance to censorship. +- **Stateless but Stateful**: While Lit Actions themselves are stateless, they can interact with both on-chain and off-chain state, enabling new application designs not available using existing blockchains like Ethereum. + +## Example Lit Action Implementation + +To illustrate the power and flexibility of Lit Actions, let's consider a practical example: + + > A Lit Action that signs a transaction only if the reported temperature for a specific area is below a defined threshold. + +###### How it would work: + +1. The Lit Action fetches temperature data from three different weather APIs. + - The choice of using three APIs is arbitrary, but demonstrates how data from multiple sources can be fetched from within a single Lit Action. +2. It calculates the average temperature from the these sources. +3. If the average temperature is below a predefined threshold, the Lit Action uses a [Programmable Key Pair (PKP)](../../user-wallets/pkps/overview.md) to sign a transaction that transfers tokens on a blockchain. +4. The signed transaction can be broadcasted to the blockchain network immediately, or returned for later submission. + +###### This example showcases how Lit Actions can: + +- Interact with on and off-chain APIs/RPCs +- Perform computations and make decisions using fetched data +- Use PKPs for [conditional signing](./conditional-signing.md) + +## Use Cases + +Below are a couple examples of how Lit Actions can be leveraged: + +- **Cross-Chain DeFi:** Automate trades or manage portfolios across multiple blockchains. +- **Decentralized Access Control**: Create dynamic, condition-based access to digital assets or data. +- **Automated Governance**: Implement complex voting mechanisms or proposal execution across DAOs. +- **Decentralized Oracles**: Fetch, process, and provide verified off-chain data to smart contracts. +- **NFT Utilities**: Create dynamic NFT metadata or automate royalty distributions. +- **Privacy-Preserving Computations**: Perform computation without exposing sensitive data. + +## Getting Started + +You can create your first Lit Action by following this [Quick Start](../serverless-signing/quick-start.md) guide. Below, you'll find some additional resources and example implementations: + +### Starter Examples + +- [Conditional signing](../serverless-signing/conditional-signing.md): Return a signature when your pre-defined conditions are met. +- [Using fetch](../serverless-signing/fetch.md): Fetch data from other chains or off-chain sources in your Lit Action. +- [Access control](../access-control/lit-action-conditions.md): Create Lit Action Conditions to permit decryption using off-chain data. +- [Importing dependencies](../serverless-signing/dependencies.md): Use external packages in your Lit Action. + +### Advanced Examples + +- [Combining signatures within a Lit Action](../serverless-signing/combining-signatures.md): Sign a message or transaction from within a Lit Action. +- [Decrypting within a Lit Action](../serverless-signing/combining-decryption-shares.md): Decrypt data for processing within a Lit Action. +- [Executing a Lit Action on a single node](../serverless-signing/run-once.md): Execute a Lit Action on a single node instead of across the entire network. +- [Broadcast and collect](../serverless-signing/broadcast-and-collect.md): Execute a Lit Action on each Lit node and aggregate their responses. Useful for performing operations over the return values, such as calculating an average or median. + +### Resources + +- [Lit Actions API docs](https://actions-docs.litprotocol.com/): An overview of all available functionality offered by Lit Actions. +- [Developer Guides](https://github.com/LIT-Protocol/developer-guides-code/tree/master): Quick examples to get you started. diff --git a/docs/build/lit-actions/run-on-single-node.md b/docs/build/lit-actions/run-on-single-node.md index ccc60a02..3c84a587 100644 --- a/docs/build/lit-actions/run-on-single-node.md +++ b/docs/build/lit-actions/run-on-single-node.md @@ -1 +1,79 @@ -# Run a Lit Action on a Single Lit Node \ No newline at end of file +# Running a Lit Action on a single node + +## Overview + +Typically, when a Lit Action is called it is executed across every Lit node in parallel. With `runOnce`, you have the ability to perform specified operations on a single node, versus all of them at once. + +The `runOnce` function takes another function as a parameter and a deterministic algorithm is used to select the Lit node that it will be executed on. The selected node will run the function and broadcast the result to all of the other Lit nodes. + +The following code example uses the `runOnce` function to send a signed Ethereum transaction to chain. + +TODO: Full Code example link + +## Using a Single Node to Send a Transaction + +:::warning +The value returned from the function provided to `runOnce` must return a value which can be serialized with `toString` otherwise you will recieve a return value of `[ERROR]` +::: + +```js +async () => { + const sigName = "sig1"; + // example transaction + let txn = { + to: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + value: 1, + gasPrice: 20000000000, + nonce: 0, + }; + + // using ether's serializeTransaction + // https://docs.ethers.org/v5/api/utils/transactions/#transactions--functions + const serializedTx = ethers.utils.serializeTransaction(txn); + let hash = utils.keccak256(ethers.utils.toUtf8Bytes(serializedTx)); + // encode the message into an uint8array for signing + const toSign = await new TextEncoder().encode(hash); + const signature = await Lit.Actions.signAndCombineEcdsa({ + toSign, + publicKey, + sigName, + }); + + // the code in the function given to runOnce below will only be run by one node + let res = await Lit.Actions.runOnce({ waitForResponse: true, name: "txnSender" }, async () => { + // get the node operator's rpc url for the 'ethereum' chain + const rpcUrl = await Lit.Actions.getRpcUrl({ chain: "ethereum" }); + const provider = new ethers.providers.JsonRpcProvider(rpcUrl); + const tx = await provider.sendTransaction(signature); + return tx.blockHash; // return the tx to be broadcast to all other nodes + }); + + // set the response from the action as the result of runOnce operation + // will be sent by all nodes, even though only a single node did the computation + Lit.Actions.setResponse(res); +} + +const client = new LitNodeClient({ + litNetwork: "datil-dev", +}); +``` +In the above `runOnce` example, within the Lit Action code, you'll notice we specify two properties in the object passed to `Lit.Actions.runOnce`: +- *`waitForResponse`* - boolean to wait for all nodes to respond if set to `true` +- *`name`* - string to name the response from the operations. Helpful if using `runOnce` multiple times in a single action. + + +## ExecuteJs `response strategy` + +When using `runOnce` you might want to set the result of the `runOnce` execution as a response from the Lit Action. By default the `response strategy` is to use the least occuring response from a node executing the Lit Action as the response returned in the `ExecuteJsResponse`. The options for strategies are the following. + +- `leastCommon` - the least occuring response will be returned as part of the result. +- `mostCommon` - the most common response will be returned as part of the result. +- `custom` - a response that is returned from the provided `customFilter` will be added to the execution result. + +:::note +In the event all responses are the same then the strategy will not be relevant. +::: + +For information on using the `signAndCombineEcdsa` function go [here](./combining-signatures.md). + +For information on using the `getRpcUrl` function go [here](./get-rpc-url.md). diff --git a/docs/build/lit-actions/sign-eth-tx.md b/docs/build/lit-actions/sign-eth-tx.md index 35e23c71..47bfbda0 100644 --- a/docs/build/lit-actions/sign-eth-tx.md +++ b/docs/build/lit-actions/sign-eth-tx.md @@ -1 +1,68 @@ -# Sign an Ethereum Transaction \ No newline at end of file +# Signing an Ethereum Transaction within a Lit Action + +## Overview + +When [signing a transaction](../serverless-signing/quick-start#sign-a-transaction.md) with Lit, signature shares are typically combined client-side. However, the `signAndCombineEcdsa` function allows you to combine signature shares directly within a Lit Action, which is useful for when you want to make use of the signed data within your Lit Action e.g. submitting a signed transaction. The signature shares will remain within the confines of each Lit node's [Trusted Execution Environment (TEE)](../../resources/how-it-works#1-lit-nodes.md) without ever being exposed to the outside world. + +When you call the `signAndCombineEcdsa` function, signature shares are collected from each Lit node before being combined on a *single* node. The following example demonstrates how you can use this functionality to sign a blockchain transaction using ethers.js + +## Code Example + +The complete code example is available in the [Lit Developer Guides Code Repository](https://github.com/LIT-Protocol/developer-guides-code/tree/master/sign-and-combine-ecdsa/nodejs). There you can find a Node.js implementation of the code. + +### Example Lit Action + +The following Lit Action uses `signAndCombineEcdsa` to combine partial signatures provided by each Lit node, each of which signs a share of the `toSign` variable — this variable contains the hash of the serialized transaction. After combining these shares into a complete signature, we use `ethers.js` to serialize the transaction again, this time including the signature, to finalize it for submission. + +```jsx +const _litActionCode = async () => { + const signature = await Lit.Actions.signAndCombineEcdsa({ + toSign, + publicKey, + sigName, + }); + + const jsonSignature = JSON.parse(signature); + jsonSignature.r = "0x" + jsonSignature.r.substring(2); + jsonSignature.s = "0x" + jsonSignature.s; + const hexSignature = ethers.utils.joinSignature(jsonSignature); + + const signedTx = ethers.utils.serializeTransaction( + unsignedTransaction, + hexSignature + ); + + const recoveredAddress = ethers.utils.recoverAddress(toSign, hexSignature); + console.log("Recovered Address:", recoveredAddress); + + const response = await Lit.Actions.runOnce( + { waitForResponse: true, name: "txnSender" }, + async () => { + try { + const rpcUrl = await Lit.Actions.getRpcUrl({ chain }); + const provider = new ethers.providers.JsonRpcProvider(rpcUrl); + const transactionReceipt = await provider.sendTransaction(signedTx); + + return `Transaction Sent Successfully. Transaction Hash: ${transactionReceipt.hash}`; + } catch (error) { + return `Error: When sending transaction: ${error.message}`; + } + } + ); + + Lit.Actions.setResponse({ response }); +}; + +const litActionCode = `(${_litActionCode.toString()})();`; +``` +## Prerequisites + +- Knowlege of [SessionSigs](../authentication/session-sigs/intro) +- Basic understanding of [Lit Actions](../serverless-signing/quick-start) + +## Summary +This guide demonstrates how to combine PKP signature shares, and submit a signed transaction all within a Lit Action. + +If you'd like to learn more about Lit Actions, check out the [Lit Actions SDK](https://actions-docs.litprotocol.com/), or our [Advanced Topics](https://developer.litprotocol.com/category/advanced-topics-1) section on Lit Actions. + + diff --git a/sidebars.js b/sidebars.js index 852d4abc..cd2263c6 100644 --- a/sidebars.js +++ b/sidebars.js @@ -224,52 +224,52 @@ const sidebars = { 'build/getting-started/installing-sdk', 'build/getting-started/connecting-to-lit', 'build/getting-started/authenticating-a-session', - 'build/getting-started/making-first-decryption', - 'build/getting-started/making-first-signing', - ], - }, - { - type: 'category', - label: 'Capacity Credits', - collapsed: true, - // link: { - // type: 'doc', - // id: 'build/capacity-credits/overview', - // }, - items: [ { type: 'category', - label: 'Minting a Credit', + label: 'Capacity Credits', collapsed: true, + link: { + type: 'doc', + id: 'build/getting-started/capacity-credits', + }, items: [ - 'build/capacity-credits/minting/via-lit-explorer', - 'build/capacity-credits/minting/via-lit-contracts-sdk', + { + type: 'category', + label: 'Minting a Credit', + collapsed: true, + items: [ + 'build/getting-started/capacity-credits/minting/via-lit-explorer', + 'build/getting-started/capacity-credits/minting/via-lit-contracts-sdk', + ], + }, + { + type: 'category', + label: 'Delegating a Credit', + collapsed: true, + items: [ + 'build/getting-started/capacity-credits/delegating/delegate-a-credit', + 'build/getting-started/capacity-credits/delegating/use-delegated-credit', + ], + }, ], }, + 'build/getting-started/making-first-decryption', + 'build/getting-started/making-first-signing', { type: 'category', - label: 'Delegating a Credit', + label: 'Payment Delegation DB', collapsed: true, + // link: { + // type: 'doc', + // id: 'build/payment-delegation-db/overview', + // }, items: [ - 'build/capacity-credits/delegating/delegate-a-credit', - 'build/capacity-credits/delegating/use-delegated-credit', + 'build/payment-delegation-db/register-payer-wallet', + 'build/payment-delegation-db/adding-payees', ], }, ], }, - { - type: 'category', - label: 'Payment Delegation DB', - collapsed: true, - // link: { - // type: 'doc', - // id: 'build/payment-delegation-db/overview', - // }, - items: [ - 'build/payment-delegation-db/register-payer-wallet', - 'build/payment-delegation-db/adding-payees', - ], - }, { type: 'category', label: 'Session Signatures',