#Can the contract state be set to a different value for every deployment?

19 messages · Page 1 of 1 (latest)

void merlin
#

Can the contract state be set to a different value for every deployment during the deployment transaction?
Something like this:

const initialState: Field = Field.random()
const transaction = await Mina.transaction(
      { sender, fee: transactionFee, memo: “Mina Navigators“ },
      () => {
        AccountUpdate.fundNewAccount(sender);
        zkApp.deploy({ verificationKey });
        zkApp.init(initialState) // sets  @state(Field) state to initialState
      }
    );

I've found no way so far to do it, as the init() function does not take arguments.

Now I first send the deployment transaction, wait for it to be included in the block, and then send the second transaction to initialize the contract state to custom values that are different for every deployment (like name for NFT).

I want to send one transaction instead of two.

gentle matrix
#

For this case, I have a static injector class and provide inputs via Provable.witness(). I am wondering if this is an acceptable approach 🤔 (looks pretty good)

#
class NFTInjector {
  static getName(): CircuitString {
    return CircuitString.fromString("Cars")
  }
}

class NftSmartContract extends SmartContract {
  @state(CircuitString) nftName = State<CircuitString>();

  @method init() {
    super.init();
    this.nftName.set(Provable.witness(CircuitString, () => NFTInjector.getName()))
  }
}
void merlin
#

Thanks a lot! Can you share what the code for deployment looks like? The one that calls Mina.transaction and zkApp.deploy?

gentle matrix
#

The code looks as usual:

let initialBalance = 10_000_000_000;
let tx = await Mina.transaction(feePayer, () => {
  AccountUpdate.fundNewAccount(feePayer);
  contract.deploy();
});
await tx.prove();
await tx.sign([feePayerKey, zkappKey]).send();
carmine inlet
#

Hey @void merlin one thing to note is that init() is already called by deploy. So you don't call it a second time.

void merlin
#

I understand that init() is being called by deploy; the problem is that even if I redefine the init(), there is no way to pass arguments to it as deploy() does not accept arguments for init()

In Ethereum, you can pass arguments to the constructor:

contract Sale {
    constructor(uint256 price) {
        _price = price;
    }
const Sale = await ethers.getContractFactory('Sale');
const sale = await Sale.deploy(price);

await sale.deployed();

But I've finally found the method to pass arguments with o1js. It used not to work with previous versions of o1js, but it works with the last version:

export class KeyValue extends SmartContract {
  @state(Field) key = State<Field>();
  @state(Field) value = State<Field>();

  @method setNewKey(key: Field) {
    this.key.set(key);
  }

  @method setNewValue(value: Field) {
    this.value.set(value);
  }
}

const key: Field = Field.random();
const value: Field = Field.random();
const transaction = await Mina.transaction(
    { sender, fee: transactionFee },
    () => {
      AccountUpdate.fundNewAccount(sender);
      zkApp.deploy({});
      zkApp.setNewKey(key);
      zkApp.setNewValue(value);
    }
  );
await transaction.prove();
transaction.sign([deployer, zkAppPrivateKey]);

An example of such deployment:
https://berkeley.minaexplorer.com/wallet/B62qmPdvENk1xLaTZN4bFWscqmjB6c1dSAXHHTVWFaQ9Z1Y5C9wtWNn

proud harbor
# void merlin I understand that init() is being called by deploy; the problem is that even if ...

This will however let you update those values after the deployment freely, which is something you might not want. It also creates 3 account updates and additional proofs, which is unnecessary. If you want to set the state only on deployment and in the 1 account update you can do it like this:

const transaction = await Mina.transaction(
  { sender, fee: transactionFee },
  () => {
    AccountUpdate.fundNewAccount(sender);
    zkApp.deploy({});
    // update current account update
    zkApp.key.set(key);
    zkApp.value.set(value);
  }
);
void merlin
void merlin
proud harbor
void merlin
proud harbor
#

Can you share the code which generated those 3 account updates?

proud harbor
void merlin
#

To test how its presence changes the behavior. Can be omitted

proud harbor
#

Then try to omit it, or at least remove the @method decorator. I think that's why you have an extra account update.