Deploy contract with init arguments

Assuming we have a smart contract that requires some parameters at initialisation:

pub contract TestContract{
  ...
  init(a: Int8, b Int8) {
    ...
  }
}

This contract can be deployed by using the cadence AuthAccount.contracts.add method described here https://docs.onflow.org/cadence/language/contracts/#deploying-a-new-contract

fun add(
    name: String,
    code: [UInt8],
    ... contractInitializerArguments
): DeployedContract

Using the contractInitializerArgument.

Currently to do this through the skds you have to write your own create account transaction. The following is an example how that might look like.

The default template to deploy a contract in flow-go-sdk (and similarly in flow-js-skd) looks like this (https://github.com/onflow/flow-go-sdk/blob/9cd830cd9e3be79f3ad5c3a8d7872165766f658b/templates/accounts.go#L49).

transaction(publicKeys: [String], contracts: {String: String}) {
	prepare(signer: AuthAccount) {
		let acct = AuthAccount(payer: signer)
		for key in publicKeys {
			acct.addPublicKey(key.decodeHex())
		}
		for contract in contracts.keys {
			acct.contracts.add(name: contract, code: contracts[contract]!.decodeHex())
		}
	}
}

Taking this as a starting point and assuming we are only going to deploy one contract we can write the transaction to deploy our TestContract like this:

transaction(publicKeys: [String], contractName: String, contractCode: String, a: Int8, b: Int8) {
	prepare(signer: AuthAccount) {
		let acct = AuthAccount(payer: signer)
		for key in publicKeys {
			acct.addPublicKey(key.decodeHex())
		}
		acct.contracts.add(name: contractName, code: contractCode.decodeHex(), a, b)
	}
}
1 Like

I should also note that a similar approach can be used if you already have an account but then the contract deployment transaction would look like:

transaction(contractName: String, contractCode: String, a: Int8, b: Int8) {
	prepare(signer: AuthAccount) {
		signer.contracts.add(name: contractName, code: contractCode.decodeHex(), a, b)
	}
}
1 Like

It is very clear. Thanks.
I have another question about passing the argument into a script.
I have 2 argument with type UFix64, which alphabet should I use instead of %d?
let minter <- self.tokenAdmin.createNewMinter(allowedAmount: %d) let mintedVault <- minter.mintTokens(amount: %d)

And also what is the proper way to pass argument into a transaction?

	transaction(recipient: Address, amount: UFix64) {
		let tokenAdmin: &FlowToken.Administrator
		let tokenReceiver: &{FungibleToken.Receiver}
	
		prepare(signer: AuthAccount) {
			self.tokenAdmin = signer
			.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin) 
			?? panic("Signer is not the token admin")
	
			self.tokenReceiver = getAccount(0x%s)
			.getCapability(/public/flowTokenReceiver)!
			.borrow<&{FungibleToken.Receiver}>()
			?? panic("Unable to borrow receiver reference")
		}
		execute {
			let minter <- self.tokenAdmin.createNewMinter(allowedAmount: %d)
			let mintedVault <- minter.mintTokens(amount: %d)
	
			self.tokenReceiver.deposit(from: <-mintedVault)
	
			destroy minter
		}
	}

I assume you are trying to do this:

	transaction(recipient: Address, amount: UFix64) {
		let tokenAdmin: &FlowToken.Administrator
		let tokenReceiver: &{FungibleToken.Receiver}
	
		prepare(signer: AuthAccount) {
			self.tokenAdmin = signer
			.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin) 
			?? panic("Signer is not the token admin")
	
			self.tokenReceiver = getAccount(recipient)
			.getCapability(/public/flowTokenReceiver)!
			.borrow<&{FungibleToken.Receiver}>()
			?? panic("Unable to borrow receiver reference")
		}
		execute {
			let minter <- self.tokenAdmin.createNewMinter(allowedAmount: amount)
			let mintedVault <- minter.mintTokens(amount: amount)
	
			self.tokenReceiver.deposit(from: <-mintedVault)
	
			destroy minter
		}
	}

as for how to pass arguments to transactions, here is a flow-go-sdk example: https://github.com/onflow/flow-go-sdk/blob/9cd830cd9e3be79f3ad5c3a8d7872165766f658b/examples/transaction_arguments/main.go#L38
and here is the flow-js-sdk example: https://github.com/onflow/flow-js-sdk/blob/master/docs/examples/introducing-fcl/Quickstart.md#transaction-inputs

so if i have 2 arguments, i need to add twice and in a sequence?
eg.

err = tx.AddArgument(recipient)
err = tx.AddArgument(amount)

Yes, and the order matters.


i have run this script and look like the argument problem has been solved. But the emulator come out with this error, I am not clear about this error. I set
amount,_:= cadence.NewUFix64("50000")
before adding the argument to the transaction.

amount, err := cadence.NewUFix64("50000") you are missing this error. The value string should have a decimal dot “5000.0”.

Oh, thanks for your reminder. Now everything looks good. :grinning:

1 Like