Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: proxy deploy with storage #3235

Merged
merged 7 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fluffy-bulldogs-lay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"fuels": patch
---

fix: proxy deploy with storage
7 changes: 6 additions & 1 deletion packages/fuels/src/cli/commands/deploy/deployContract.ts
petertonysmith94 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ export async function deployContract(

const targetBytecode = readFileSync(binaryPath);
const targetAbi = JSON.parse(readFileSync(abiPath, 'utf-8'));
const targetStorageSlots = deployConfig.storageSlots ?? [];

const proxyBytecode = Src14OwnedProxyFactory.bytecode;
const proxyAbi = Src14OwnedProxy.abi;
const proxyFactory = new Src14OwnedProxyFactory(wallet);
const proxyStorageSlots = Src14OwnedProxy.storageSlots ?? [];

const isProxyEnabled = tomlContents?.proxy?.enabled;
const proxyAddress = tomlContents?.proxy?.address;
Expand Down Expand Up @@ -82,15 +84,18 @@ export async function deployContract(
// b. Deploy the SR-C14 Compliant / Proxy Contract
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { storageSlots, stateRoot, ...commonDeployConfig } = deployConfig;
const mergedStorageSlots = targetStorageSlots.concat(proxyStorageSlots);

const proxyDeployConfig: DeployContractOptions = {
...commonDeployConfig,
storageSlots: mergedStorageSlots,
configurableConstants: {
INITIAL_TARGET: { bits: targetContract.id.toB256() },
INITIAL_OWNER: { Initialized: { Address: { bits: wallet.address.toB256() } } },
},
};

const proxyFactory = new ContractFactory(proxyBytecode, proxyAbi, wallet);
const { waitForResult: waitForProxy } = await proxyFactory.deploy(proxyDeployConfig);
const { contract: proxyContract } = await waitForProxy();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/* eslint-disable @typescript-eslint/consistent-type-imports */

/*
Fuels version: 0.94.7
Fuels version: 0.94.8
*/

import { Contract, Interface } from "../../../../..";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/* eslint-disable @typescript-eslint/consistent-type-imports */

/*
Fuels version: 0.94.7
Fuels version: 0.94.8
*/

import { Contract, ContractFactory, decompressBytecode } from "../../../../..";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/* eslint-disable @typescript-eslint/consistent-type-imports */

/*
Fuels version: 0.94.7
Fuels version: 0.94.8
*/

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/* eslint-disable @typescript-eslint/consistent-type-imports */

/*
Fuels version: 0.94.7
Fuels version: 0.94.8
*/

export { Src14OwnedProxy } from './Src14OwnedProxy';
Expand Down
117 changes: 60 additions & 57 deletions packages/fuels/test/features/deploy.test.ts
petertonysmith94 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { JsonAbi } from '@fuel-ts/abi-coder';
import type { Account } from '@fuel-ts/account';
import { Contract } from '@fuel-ts/program';
import { existsSync, readFileSync, writeFileSync } from 'fs';
import { join } from 'path';
Expand Down Expand Up @@ -58,6 +60,20 @@ describe('deploy', { timeout: 180000 }, () => {
expect(firstFuelsContents.fooBar).toMatch(/0x/);
});

/**
* Executes the target contract and returns the values of the functions for proxy deploys.
*/
async function executeTargetContract(contractId: string, abi: JsonAbi, wallet: Account) {
const targetContract = new Contract(contractId, abi, wallet);

const { value: getCountValue } = await targetContract.functions.get_value().get();

const res = await targetContract.functions.test_function().call();
const { value: testFunctionValue } = await res.waitForResult();

return { getCountValue, testFunctionValue };
}

it('should run `deploy` command [using proxy + re-deploy]', async () => {
using launched = await launchTestNode({
nodeOptions: {
Expand Down Expand Up @@ -92,34 +108,26 @@ describe('deploy', { timeout: 180000 }, () => {
expect(firstFuelsContents.fooBar).toMatch(/0x/);
expect(firstFuelsContents.upgradable).toMatch(/0x/);

/**
* a) Add helper
* For interacting with deployed contract
*/
async function executeTargetContract() {
const upgradableContractId = firstFuelsContents.upgradable;
const upgradableAbi = JSON.parse(
readFileSync(
join(paths.upgradableContractPath, 'out', 'debug', 'upgradable-abi.json'),
'utf-8'
)
);

const targetContract = new Contract(upgradableContractId, upgradableAbi, wallet);
const res = await targetContract.functions.test_function().call();
const { value } = await res.waitForResult();

return value;
}
const contractId = firstFuelsContents.upgradable;
const abi = JSON.parse(
readFileSync(
join(paths.upgradableContractPath, 'out', 'debug', 'upgradable-abi.json'),
danielbate marked this conversation as resolved.
Show resolved Hide resolved
'utf-8'
)
);

/**
* b) Interact with target contract
* Calling `test_function` should return `true` for the first execution.
* a) Interacting with the target contract
* Calling `test_function` should return `true` and `get_value`
* should return `10` for the first execution.
*/
expect(await executeTargetContract()).toBe(true); // TRUE
expect(await executeTargetContract(contractId, abi, wallet)).toStrictEqual({
getCountValue: 10,
testFunctionValue: true,
});

/**
* c) Modify `main.sw` method before second deploy
* b) Modify `main.sw` method before second deploy
* This will make the method return `false` instead of `true`.
*/
const mainPath = join(paths.upgradableContractPath, 'src', 'main.sw');
Expand All @@ -140,10 +148,14 @@ describe('deploy', { timeout: 180000 }, () => {
expect(firstFuelsContents.upgradable).toEqual(secondFuelsContents.upgradable);

/**
* d) Interact with target contract
* Now, calling `test_function` should return `false` instead.
* c) Interact with target contract
* Now, calling `test_function` should return `false` instead,
* but `get_value` should still return `10`.
*/
expect(await executeTargetContract()).toBe(false); // FALSE
expect(await executeTargetContract(contractId, abi, wallet)).toStrictEqual({
getCountValue: 10,
testFunctionValue: false,
});
});

it('should run `deploy` command [using proxy and chunking + re-deploy]', async () => {
Expand Down Expand Up @@ -180,39 +192,26 @@ describe('deploy', { timeout: 180000 }, () => {
expect(firstFuelsContents.fooBar).toMatch(/0x/);
expect(firstFuelsContents.upgradable).toMatch(/0x/);

/**
* a) Add helper
* For interacting with deployed contract
*/
async function executeTargetContract() {
const upgradableChunkedContractId = firstFuelsContents.upgradableChunked;
const upgradableChunkedAbi = JSON.parse(
readFileSync(
join(paths.upgradableChunkedContractPath, 'out', 'debug', 'upgradable-chunked-abi.json'),
'utf-8'
)
);

const targetContract = new Contract(
upgradableChunkedContractId,
upgradableChunkedAbi,
wallet
);

const res = await targetContract.functions.test_function().call();
const { value } = await res.waitForResult();

return value;
}
const contractId = firstFuelsContents.upgradableChunked;
const abi = JSON.parse(
readFileSync(
join(paths.upgradableChunkedContractPath, 'out', 'debug', 'upgradable-chunked-abi.json'),
danielbate marked this conversation as resolved.
Show resolved Hide resolved
'utf-8'
)
);

/**
* b) Interact with target contract
* Calling `test_function` should return `true` for the first execution.
* a) Interacting with the target contract
* Calling `test_function` should return `true` and `get_value`
* should return `10` for the first execution.
*/
expect(await executeTargetContract()).toBe(true); // TRUE
expect(await executeTargetContract(contractId, abi, wallet)).toStrictEqual({
getCountValue: 10,
testFunctionValue: true,
});

/**
* c) Modify `main.sw` method before second deploy
* b) Modify `main.sw` method before second deploy
* This will make the method return `false` instead of `true`.
*/
const mainPath = join(paths.upgradableChunkedContractPath, 'src', 'main.sw');
Expand All @@ -233,9 +232,13 @@ describe('deploy', { timeout: 180000 }, () => {
expect(firstFuelsContents.upgradableChunked).toEqual(secondFuelsContents.upgradableChunked);

/**
* d) Interact with target contract
* Now, calling `test_function` should return `false` instead.
* c) Interact with target contract
* Now, calling `test_function` should return `false` instead,
* but `get_value` should still return `10`.
*/
expect(await executeTargetContract()).toBe(false); // FALSE
expect(await executeTargetContract(contractId, abi, wallet)).toStrictEqual({
getCountValue: 10,
testFunctionValue: false,
});
});
});