diff --git a/.changeset/thirty-parrots-sniff.md b/.changeset/thirty-parrots-sniff.md new file mode 100644 index 00000000000..8bf2b37b303 --- /dev/null +++ b/.changeset/thirty-parrots-sniff.md @@ -0,0 +1,4 @@ +--- +--- + +docs: predicate and script deploys diff --git a/apps/docs-snippets/package.json b/apps/docs-snippets/package.json index dcefef909ee..c82dae8222a 100644 --- a/apps/docs-snippets/package.json +++ b/apps/docs-snippets/package.json @@ -4,13 +4,7 @@ "description": "", "private": true, "scripts": { - "pretest": "run-s fuels:build type:check", - "xpretest": "run-s kill-node fuels:build fuels:node fuels:deploy kill-node type:check", - "kill-node": "lsof -t -i:4000 | xargs -r kill", - "fuels:deploy": "pnpm fuels deploy", - "fuels:node": "pnpm fuels node > /dev/null 2>&1 &", - "fuels:build": "pnpm fuels build", - "type:check": "tsc --noEmit" + "pretest": "./scripts/pretest.sh" }, "devDependencies": { "@fuel-ts/account": "workspace:*", diff --git a/apps/docs-snippets/scripts/pretest.sh b/apps/docs-snippets/scripts/pretest.sh new file mode 100755 index 00000000000..e4e41106e97 --- /dev/null +++ b/apps/docs-snippets/scripts/pretest.sh @@ -0,0 +1,17 @@ +# Kill anything running on port 4000 +lsof -t -i:4000 | xargs -r kill + +# Runs a node at port 4000 +pnpm fuels node > /dev/null 2>&1 & + +# Builds projects +pnpm fuels build + +# Deploys projects (needed for loader bytecode) +pnpm fuels deploy + +# Kills the node +lsof -t -i:4000 | xargs -r kill + +# Checks for type errors +pnpm tsc --noEmit \ No newline at end of file diff --git a/apps/docs-snippets/src/guide/predicates/deploying-predicates.test.ts b/apps/docs-snippets/src/guide/predicates/deploying-predicates.test.ts index fa6f03423d0..8e5cc8755cd 100644 --- a/apps/docs-snippets/src/guide/predicates/deploying-predicates.test.ts +++ b/apps/docs-snippets/src/guide/predicates/deploying-predicates.test.ts @@ -1,17 +1,16 @@ -import { readFileSync } from 'fs'; -import { ContractFactory, Predicate, Provider, Wallet, hexlify } from 'fuels'; +import { ContractFactory, Provider, Wallet, hexlify } from 'fuels'; import { launchTestNode } from 'fuels/test-utils'; -import { join } from 'path'; -import { ConfigurablePin as TypegenPredicate } from '../../../test/typegen'; +import { + ConfigurablePin as TypegenPredicate, + ConfigurablePinLoader as TypegenPredicateLoader, +} from '../../../test/typegen'; /** * @group browser * @group node - * - * TODO: enable the test and reintroduce the docs */ -describe.skip('Deploying Predicates', () => { +describe('Deploying Predicates', () => { it('deploys a predicate via loader and calls', async () => { using launched = await launchTestNode(); @@ -33,64 +32,52 @@ describe.skip('Deploying Predicates', () => { const { waitForResult: waitForDeploy } = await factory.deployAsBlobTxForScript(); await waitForDeploy(); - const loaderBytecode = hexlify( - readFileSync( - join( - __dirname, - '../../../test/fixtures/forc-projects/configurable-pin/out/release/configurable-pin.deployed.bin' - ) - ) - ); - // #region deploying-predicates - // #import { Provider, Wallet, hexlify }; - // #context import { readFileSync } from 'fs'; + // #import { Provider, Wallet }; // #context import { WALLET_PVT_KEY } from 'path/to/my/env/file'; - // #context import { TypegenPredicate } from 'path/to/typegen/outputs'; - - // First, we will need the loader bytecode that is generated by `fuels deploy` - // #context const loaderBytecode = hexlify(readFileSync('path/to/forc/build/outputs'))); + // #context import { TypegenPredicateLoader } from 'path/to/typegen/outputs'; const provider = await Provider.create(providerUrl); const wallet = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); + const baseAssetId = provider.getBaseAssetId(); - // Then we will instantiate the predicate using both the scripts bytecode and it's loader bytecode, - // now we are free to interact with the predicate as we would normally, such as overriding the configurables - const predicate = new Predicate({ - bytecode: loaderBytecode, - abi: TypegenPredicate.abi, - data: [1337], + // First, we will need to instantiate the script via it's loader bytecode. + // This can be imported from the typegen outputs that were created on `fuels deploy`. + // Then we can use the predicate as we would normally, such as overriding the configurables. + const predicate = new TypegenPredicateLoader({ + data: [23], provider, + configurableConstants: { + PIN: 23, + }, }); - // First, let's fund the predicate - const { waitForResult: waitForFund } = await wallet.transfer(predicate.address, 100_000); - await waitForFund(); + // Now, let's fund the predicate + const fundTx = await wallet.transfer(predicate.address, 100_000, baseAssetId); + await fundTx.waitForResult(); - const { waitForResult: waitForTransfer } = await predicate.transfer(receiver.address, 1000); - const { gasUsed } = await waitForTransfer(); + // Then we'll execute the transfer and validate the predicate + const transferTx = await predicate.transfer(receiver.address, 1000, baseAssetId); + const { gasUsed } = await transferTx.waitForResult(); // #endregion deploying-predicates - const anotherPredicate = new Predicate({ - bytecode: TypegenPredicate.bytecode, - abi: TypegenPredicate.abi, - data: [1337], + const anotherPredicate = new TypegenPredicate({ + data: [23], provider, + configurableConstants: { + PIN: 23, + }, }); - const { waitForResult: waitForAnotherFund } = await wallet.transfer( - anotherPredicate.address, - 100_000 - ); - await waitForAnotherFund(); + const anotherFundTx = await wallet.transfer(anotherPredicate.address, 100_000); + await anotherFundTx.waitForResult(); - const { waitForResult: waitForAnotherTransfer } = await anotherPredicate.transfer( - receiver.address, - 1000 - ); - const { gasUsed: anotherGasUsed } = await waitForAnotherTransfer(); + const anotherTransferTx = await anotherPredicate.transfer(receiver.address, 1000); + const { gasUsed: anotherGasUsed } = await anotherTransferTx.waitForResult(); - expect(recieverInitialBalance.toNumber()).toBeLessThan(recieverInitialBalance.toNumber()); - expect(gasUsed.toNumber()).toBeLessThan(anotherGasUsed.toNumber()); + expect(recieverInitialBalance.toNumber()).toBeLessThan( + (await receiver.getBalance()).toNumber() + ); + expect(gasUsed.toNumber()).toBeLessThanOrEqual(anotherGasUsed.toNumber()); }); }); diff --git a/apps/docs-snippets/src/guide/scripts/deploying-scripts.test.ts b/apps/docs-snippets/src/guide/scripts/deploying-scripts.test.ts index 9abe0160fe0..5990ef108f7 100644 --- a/apps/docs-snippets/src/guide/scripts/deploying-scripts.test.ts +++ b/apps/docs-snippets/src/guide/scripts/deploying-scripts.test.ts @@ -1,17 +1,16 @@ -import { readFileSync } from 'fs'; -import { ContractFactory, Provider, Script, Wallet, hexlify } from 'fuels'; +import { ContractFactory, Provider, Wallet, hexlify } from 'fuels'; import { launchTestNode } from 'fuels/test-utils'; -import { join } from 'path'; -import { SumScript as TypegenScript } from '../../../test/typegen'; +import { + SumScript as TypegenScript, + SumScriptLoader as TypegenScriptLoader, +} from '../../../test/typegen'; /** * @group browser * @group node - * - * TODO: enable the test and reintroduce the docs */ -describe.skip('Deploying Scripts', () => { +describe('Deploying Scripts', () => { it('deploys a script via loader and calls', async () => { using launched = await launchTestNode(); @@ -27,29 +26,17 @@ describe.skip('Deploying Scripts', () => { const { waitForResult: waitForDeploy } = await factory.deployAsBlobTxForScript(); await waitForDeploy(); - const loaderBytecode = hexlify( - readFileSync( - join( - __dirname, - '../../../test/fixtures/forc-projects/sum-script/out/release/sum-script-loader.bin' - ) - ) - ); - // #region deploying-scripts - // #import { Provider, Wallet, hexlify }; - // #context import { readFileSync } from 'fs'; + // #import { Provider, Wallet }; // #context import { WALLET_PVT_KEY } from 'path/to/my/env/file'; - // #context import { TypegenScript } from 'path/to/typegen/outputs'; - - // First, we will need the loader bytecode that is generated by `fuels deploy` - // #context const loaderBytecode = hexlify(readFileSync('path/to/forc/build/outputs'))); + // #context import { TypegenScriptLoader } from 'path/to/typegen/outputs'; const provider = await Provider.create(providerUrl); const wallet = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); - // Then we will instantiate the script using both the scripts bytecode and it's loader bytecode - const script = new Script(loaderBytecode, TypegenScript.abi, wallet); + // First, we will need to instantiate the script via it's loader bytecode. This can be imported from the typegen outputs + // that were created on `fuels deploy` + const script = new TypegenScriptLoader(wallet); // Now we are free to interact with the script as we would normally, such as overriding the configurables const configurable = { @@ -59,15 +46,16 @@ describe.skip('Deploying Scripts', () => { const { waitForResult } = await script.functions.main(10).call(); const { value, gasUsed } = await waitForResult(); + // value: 10 // #endregion deploying-scripts - const scriptWithoutLoader = new Script(TypegenScript.bytecode, TypegenScript.abi, wallet); + const scriptWithoutLoader = new TypegenScript(wallet); scriptWithoutLoader.setConfigurableConstants(configurable); const { waitForResult: waitForAnotherResult } = await script.functions.main(10).call(); const { value: anotherValue, gasUsed: anotherGasUsed } = await waitForAnotherResult(); expect(value).toBe(30); expect(anotherValue).toBe(30); - expect(gasUsed.toNumber()).toBeLessThan(anotherGasUsed.toNumber()); + expect(gasUsed.toNumber()).toBeLessThanOrEqual(anotherGasUsed.toNumber()); }); }); diff --git a/apps/docs/.vitepress/config.ts b/apps/docs/.vitepress/config.ts index de078a21ee9..f62eb604519 100644 --- a/apps/docs/.vitepress/config.ts +++ b/apps/docs/.vitepress/config.ts @@ -275,6 +275,10 @@ export default defineConfig({ text: 'Instantiating A Script', link: '/guide/scripts/instantiating-a-script', }, + { + text: 'Deploying Scripts', + link: '/guide/scripts/deploying-scripts', + }, { text: 'Configurable Constants', link: '/guide/scripts/configurable-constants', @@ -298,6 +302,10 @@ export default defineConfig({ text: 'Instantiating A Predicate', link: '/guide/predicates/instantiating-a-predicate', }, + { + text: 'Deploying Predicates', + link: '/guide/predicates/deploying-predicates', + }, { text: 'Configurable Constants', link: '/guide/predicates/configurable-constants', diff --git a/apps/docs/src/guide/predicates/deploying-predicates.md b/apps/docs/src/guide/predicates/deploying-predicates.md new file mode 100644 index 00000000000..54c2d3d4c43 --- /dev/null +++ b/apps/docs/src/guide/predicates/deploying-predicates.md @@ -0,0 +1,20 @@ +# Deploying Predicates + +In order to optimize the cost of your recurring predicate executions, we recommend first deploying your predicate. This can be done using the [Fuels CLI](../fuels-cli/index.md) and running the [deploy command](../fuels-cli/commands.md#fuels-deploy). + +By deploying the predicate, its bytecode is stored on chain as a blob. The SDK will then produce bytecode that can load the blob on demand to execute the original predicate. This far reduces the repeat execution cost of the predicate. + +## How to Deploy a Predicate + +To deploy a predicate, we can use the [Fuels CLI](../fuels-cli/index.md) and execute the [deploy command](../fuels-cli/commands.md#fuels-deploy). + +This will perform the following actions: + +1. Compile the predicate using your `forc` version +1. Deploy the built predicate binary to the chain as a blob +1. Generate a new, smaller predicate that loads the deployed predicate's blob +1. Generate types for both the predicate and the loader that you can use in your application + +We can then utilize the above generated types like so: + +<<< @/../../docs-snippets/src/guide/predicates/deploying-predicates.test.ts#deploying-predicates{ts:line-numbers} diff --git a/apps/docs/src/guide/scripts/deploying-scripts.md b/apps/docs/src/guide/scripts/deploying-scripts.md new file mode 100644 index 00000000000..c11be125e3e --- /dev/null +++ b/apps/docs/src/guide/scripts/deploying-scripts.md @@ -0,0 +1,20 @@ +# Deploying Scripts + +In order to optimize the cost of your recurring script executions, we recommend first deploying your script. This can be done using the [Fuels CLI](../fuels-cli/index.md) and running the [deploy command](../fuels-cli/commands.md#fuels-deploy). + +By deploying the script, its bytecode is stored on chain as a blob. The SDK will then produce bytecode that can load the blob on demand to execute the original script. This far reduces the repeat execution cost of the script. + +## How to Deploy a Script + +To deploy a script, we can use the [Fuels CLI](../fuels-cli/index.md) and execute the [deploy command](../fuels-cli/commands.md#fuels-deploy). + +This will perform the following actions: + +1. Compile the script using your `forc` version +1. Deploy the built script binary to the chain as a blob +1. Generate a script that loads the blob that can be used to execute the script +1. Generate types for both the script and the loader that you can use in your application + +We can then utilize the above generated types like so: + +<<< @/../../docs-snippets/src/guide/scripts/deploying-scripts.test.ts#deploying-scripts{ts:line-numbers}