Deploy Contract
This guide shows how to deploy a smart contract to Starknet using Starknet.go.
Prerequisites
- Go 1.18 or higher
- Starknet.go installed
- A Starknet node URL
- Compiled Cairo contract
- Account with sufficient funds
Overview
This example deploys an ERC20 token using the UDC (Universal Deployer Contract) smart contract.
Steps:
- Rename the
.env.template
file located at the root of theexamples
folder to.env
- Uncomment, and assign your Sepolia testnet endpoint to the
RPC_PROVIDER_URL
variable in the.env
file - Uncomment, and assign your account address to the
ACCOUNT_ADDRESS
variable in the.env
file (make sure to have a few ETH in it) - Uncomment, and assign your starknet public key to the
PUBLIC_KEY
variable in the.env
file - Uncomment, and assign your private key to the
PRIVATE_KEY
variable in the.env
file - Make sure you are in the
deployContractUDC
directory - Execute
go run main.go
The transaction hash and status will be returned at the end of the execution.
Code Example
main.go
package main
import (
"context"
"encoding/hex"
"fmt"
"math/big"
"math/rand"
"strconv"
"time"
"github.com/NethermindEth/juno/core/felt"
"github.com/NethermindEth/starknet.go/account"
"github.com/NethermindEth/starknet.go/rpc"
"github.com/NethermindEth/starknet.go/utils"
setup "github.com/NethermindEth/starknet.go/examples/internal"
)
// More info: https://docs.starknet.io/architecture-and-concepts/accounts/universal-deployer/
// NOTE : Please add in your keys only for testing purposes, in case of a leak you would potentially lose your funds.
var (
someContractHash string = "0x046ded64ae2dead6448e247234bab192a9c483644395b66f2155f2614e5804b0" // The contract hash to be deployed (in this example, it's an ERC20 contract)
UDCAddress string = "0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf" // UDC contract address
contractMethod string = "deployContract" // UDC method to deploy a contract (from pre-declared contracts)
)
// Example successful transaction created from this example on Sepolia
// https://sepolia.voyager.online/tx/0xa9a67a7cd8d218bd225335ea2ad4ea4d4c906a5806f14603c7036bfe49ca92
func main() {
fmt.Println("Starting deployContractUDC example")
// Load variables from '.env' file
rpcProviderUrl := setup.GetRpcProviderUrl()
accountAddress := setup.GetAccountAddress()
accountCairoVersion := setup.GetAccountCairoVersion()
privateKey := setup.GetPrivateKey()
publicKey := setup.GetPublicKey()
// Initialize connection to RPC provider
client, err := rpc.NewProvider(rpcProviderUrl)
if err != nil {
panic(fmt.Sprintf("Error dialing the RPC provider: %s", err))
}
// Here we are converting the account address to felt
accountAddressInFelt, err := utils.HexToFelt(accountAddress)
if err != nil {
panic(err)
}
// Initialize the account memkeyStore (set public and private keys)
ks := account.NewMemKeystore()
privKeyBI, ok := new(big.Int).SetString(privateKey, 0)
if !ok {
panic("Failed to convert privKey to bigInt")
}
ks.Put(publicKey, privKeyBI)
fmt.Println("Established connection with the client")
// Initialize the account
accnt, err := account.NewAccount(client, accountAddressInFelt, publicKey, ks, accountCairoVersion)
if err != nil {
panic(err)
}
// Convert the contractAddress from hex to felt
contractAddress, err := utils.HexToFelt(UDCAddress)
if err != nil {
panic(err)
}
// Build the functionCall struct, where :
FnCall := rpc.InvokeFunctionCall{
ContractAddress: contractAddress, //contractAddress is the contract that we want to call
FunctionName: contractMethod, //this is the function that we want to call
CallData: getUDCCalldata(accountAddress), //change this function content to your use case
}
// After the signing we finally call the AddInvokeTransaction in order to invoke the contract function
resp, err := accnt.BuildAndSendInvokeTxn(context.Background(), []rpc.InvokeFunctionCall{FnCall}, 1.5)
if err != nil {
panic(err)
}
fmt.Println("Waiting for the transaction status...")
txReceipt, err := accnt.WaitForTransactionReceipt(context.Background(), resp.TransactionHash, time.Second)
if err != nil {
panic(err)
}
// This returns us with the transaction hash and status
fmt.Printf("Transaction hash response: %v\n", resp.TransactionHash)
fmt.Printf("Transaction execution status: %s\n", txReceipt.ExecutionStatus)
fmt.Printf("Transaction status: %s\n", txReceipt.FinalityStatus)
}
// getUDCCalldata is a simple helper to set the call data required by the UDCs deployContract function. Update as needed.
func getUDCCalldata(data ...string) []*felt.Felt {
classHash, err := utils.HexToFelt(someContractHash)
if err != nil {
panic(err)
}
salt := new(felt.Felt).SetUint64(rand.Uint64()) // to prevent address clashes
unique := felt.Zero // see https://docs.starknet.io/architecture-and-concepts/accounts/universal-deployer/#deployment_types
// As we are using an ERC20 token in this example, the calldata needs to have the ERC20 constructor required parameters.
// You must adjust these fields to match the constructor's parameters of your desired contract.
// https://docs.openzeppelin.com/contracts-cairo/0.8.1/api/erc20#ERC20-constructor-section
calldata, err := utils.HexArrToFelt([]string{
hex.EncodeToString([]byte("MyERC20Token")), //name
hex.EncodeToString([]byte("MET")), //symbol
strconv.FormatInt(200000000000000000, 16), //fixed_supply (u128 low). See https://book.cairo-lang.org/ch02-02-data-types.html#integer-types
strconv.FormatInt(0, 16), //fixed_supply (u128 high)
data[0], //recipient
})
if err != nil {
panic(err)
}
calldataLen := new(felt.Felt).SetUint64(uint64(len(calldata)))
return append([]*felt.Felt{classHash, salt, &unique, calldataLen}, calldata...)
}
Explanation
- Initialize the Starknet client
- Create an account instance
- Read the compiled contract file
- Deploy the contract using the account
- The transaction hash is returned upon successful deployment
Best Practices
- Always verify contract compilation
- Use proper error handling
- Consider gas estimation before deployment
- Test on testnet first
- Keep track of deployed contract addresses
Common Issues
- Invalid contract bytecode
- Insufficient funds
- Contract size limits
- Network congestion
- Compilation errors