Failed to deploy contract using typescript sdk

SDK version: fuels@0.74.0
nodejs version: v20.11.1
testnet version: beta-5
environment: MacOS 11.6.7

Steps to reproduce:

  1. Follow Quickstart Contract | Fuel Docs to build contract byte code & ABI.
  2. Use the following code to deploy contract:
    const factory = new ContractFactory(byteCode, abi, wallet);
    const { minGasPrice: gasPrice } = wallet.provider.getGasConfig();
    const contract = await factory.deployContract({ gasPrice });
    console.log(`${wallet.address.bech32Address} deployed contract ${contract.id}`);
    console.log(JSON.stringify(contract));

Expected behavior: Contract deployed successfully without error
Actual behavior:
const subscriptionStreamReader = response.body.pipeThrough(new FuelSubscriptionStream()).getReader();
^

TypeError: response.body.pipeThrough is not a function
at fuelGraphQLSubscriber (/Users/yuduan/Projects/fuel/node_modules/@fuel-ts/account/dist/index.js:1087:50)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async _Provider.sendTransaction (/Users/yuduan/Projects/fuel/node_modules/@fuel-ts/account/dist/index.js:3898:41)
at async ContractFactory.deployContract (/Users/yuduan/Projects/fuel/node_modules/@fuel-ts/contract/dist/index.js:166:5)

Node.js v20.11.1

Hi @yuduan0220, thanks for the report. There is a PR that will fix this error.

Also, please try using 0.73.0 as mentioned in the guide, and try again

@Dhaiwat10 I tried 0.73.0 and got the same error.

1 Like

Thanks @nedsalk is it gonna be included in 0.75.0?

@yuduan0220 You’re welcome! Yes, it’ll be included in that release. The PR for the release is here.

I downloaded 0.75.0 and got a different error now:

fuel/node_modules/@fuel-ts/account/dist/index.js:1065
this.stream = response.body.getReader();
TypeError: response.body.getReader is not a function

@yuduan0220 Where are you running your code, in nodejs (a server) or in Safari (a web app)? Also, could you please give us a repo with the problematic code?

Hey, I’m running it through cmd line with node version 16.
Another thing I found is that even exception was thrown, the contract was deployed and I could find it on the explorer.

The code is really simple, snippet below:


async function deploy(byteCode, abi, wallet) {
    const factory = new ContractFactory(byteCode, abi, wallet);
    const { minGasPrice: gasPrice } = wallet.provider.getGasConfig();
    const contract = await factory.deployContract({ gasPrice });
    console.log(`${wallet.address.bech32Address} deployed contract ${contract.id}`);
    console.log(JSON.stringify(contract));
    // interact with deployed contract

    await interact(contract.id, abi, wallet);
}

Could you please run it with node v18 or above? We officially support only v18 and v20.

On the note of successful deployment, it shouldn’t be possible for you to even deploy the app with node v16 because we’re using native fetch for all calls, which was only introduced in v17 under an experimental flag and stabilized in v18. I suspect you’ve got something going on with node-fetch being put in place of fetch, which allows you to send the contract deployment request but fails on response.body.getReader() because body.getReader doesn’t exist in node-fetch.

Brilliant, @nedsalk I’ve upgraded to node v18 and removed global fetch override. I’m able to deploy the contract, thanks a ton!

However I’m seeing a second issue, when trying to read value from the deployed contract.

async function interact(id, abi, wallet) {
    const contract = new Contract(id, abi, wallet);
    const { valueBefore } = await contract.functions.count().simulate();
    console.log({valueBefore});
}

I got the error: “RevertError: The script reverted with reason Unknown”

The contract I deployed is very simple:

contract;

storage {
    counter: u64 = 0,
}

abi Counter {
    #[storage(read, write)]
    fn increment(input: u64);

    #[storage(read)]
    fn count() -> u64;
}

impl Counter for Contract {
    #[storage(read)]
    fn count() -> u64 {
        return storage.counter.read()
    }

    #[storage(read, write)]
    fn increment(input: u64) {
        let incremented = storage.counter.read() + input;
        storage.counter.write(incremented);
    }
}

Great, we’re moving forward!

Related to the RevertError, I tried reproducing your error locally and it didn’t fail for me. Which forc version are you using to build your contract? It should be version 0.50.0.

Also, you’ve got a bug in { valueBefore }, it should be { value } because that’s the name of the return object’s property.

Hey thanks again for the hint, I checked I’m on 0.49.2.
When I run fuelup update, it says I already have the latest.
latest updated
updated components:

  • forc 0.49.2
  • forc-explore 0.28.1
  • forc-wallet 0.4.3
  • fuel-core 0.22.0
  • fuel-core-keygen 0.22.0

Hmm, I’m kinda stumped here. Perhaps you did something in-between that’s causing this issue because I’m able to interact with the equivalent contract normally, both with bytecodes generated with forc 0.49.2 and 0.50.0 on fuel-core 0.21.1 which is the beta-5 version of fuel-core.

Just to unblock you, given that you’re using the TS SDK, we do have a quickstart template that you can use. Could you please follow its instructions and let us know how it went?

Thanks again for your suggestion @nedsalk. I tried the below steps:

  1. Use a very simple contract, deploy it and read test_function through await contract.functions.test_function().simulate(); it works, I got value true in the response.
contract;

abi MyContract {
	fn test_function() -> bool;
}

impl MyContract for Contract {
	fn test_function() -> bool {
		true
	}
}
  1. Take the example contract from Quickstart Contract | Fuel Docs, deploy it then read the count through await contract.functions.count().simulate();, it doesn’t work and I got error “The script reverted with reason Unknown, cause: ScriptResultDecoderError: Execution of the script associated with contract xxx resulted in a non-zero exit code: 1”
contract;
 
storage {
    counter: u64 = 0,
}
 
abi Counter {
    #[storage(read, write)]
    fn increment();
 
    #[storage(read)]
    fn count() -> u64;
}
 
impl Counter for Contract {
    #[storage(read)]
    fn count() -> u64 {
        storage.counter.read()
    }
 
    #[storage(read, write)]
    fn increment() {
        let incremented = storage.counter.read() + 1;
        storage.counter.write(incremented);
    }
}

I also have this problem. Have you solved it

Nope, hasn’t heard back from the team yet. Keep me posted if you found something.

I figured it out, the revert is due to uninitialized storage value, despite I’ve used the initializer as below:

storage {
    counter: u64 = 0,
}

If I directly try to perform a storage.counter.read(), I get The transaction reverted with an unknown reason: 0. However I added an init method which explicitly set the storage counter value to 42, after that I’m able to retrieve its value correctly.

To summarize, what I did is:

  1. Add a new method in the contract:
fn constructor() {
    storage.counter.write(42);
}
  1. Deploy the contract
  2. Call the constructor method to explicitly write to the storage.
  3. Read the storage afterwards and get a value 42 as expected.

@nedsalk Can you help me understand why the initial value of the storage can’t be read?

Sorry for not addressing your comments earlier, this conversation slipped through.

I tried the simple counter example via https://www.sway-playground.org/ by:

  1. Compiling and deploying the contract,
  2. Calling the get method before the increment method

And it worked. I can’t reproduce the problem you’re facing. The sway playground is using forc 0.60.0, deploying on the sepolia testnet which is using fuel-core 0.27.0, and using fuels 0.88.1 for the typescript code.

The initial value of the storage can be read via this.

A lot of development has happened since this issue arose and you might be using outdated versions of all three dependencies listed above.
The quickstart guide I gave you previously also got revamped and now we’ve got a CLI tool that you can use. Could you please try that and see if you’re still facing issues? Please take note that you have to set your forc and fuel-core versions via fuelup. After install of fuelup, you can do this one-liner to set it up:

fuelup toolchain new custom && fuelup component add forc@0.60.0 && fuelup component add fuel-core@0.27.0.

2 Likes