diff --git a/examples/deploy/main.go b/examples/deploy/main.go index 28d8db6e..4b43216a 100644 --- a/examples/deploy/main.go +++ b/examples/deploy/main.go @@ -9,6 +9,7 @@ import ( starknetgo "github.com/NethermindEth/starknet.go" "github.com/NethermindEth/starknet.go/artifacts" "github.com/NethermindEth/starknet.go/gateway" + "github.com/NethermindEth/starknet.go/rpcv02" "github.com/NethermindEth/starknet.go/types" ) @@ -35,7 +36,7 @@ func main() { os.Exit(1) } - contractClass := types.ContractClass{} + contractClass := rpcv02.ContractClass{} err = json.Unmarshal(artifacts.AccountCompiled, &contractClass) if err != nil { fmt.Println("could not log file", err) diff --git a/examples/deployAccount/README.md b/examples/deployAccount/README.md new file mode 100644 index 00000000..e0c2fb2a --- /dev/null +++ b/examples/deployAccount/README.md @@ -0,0 +1,57 @@ +# DeployAccount example + +# todo (update) + +This directory provides a full example on how to use the gateway API to : + +- Deploy an OpenZeppelin account +- Deploy an ERC20 contract +- Mint the ERC20 contract +- Transfer tokens from the deployed account to a third-party account + +## Run the program + +In a terminal in this directory, enter : `go run main.go` + +You can choose to run the program with an instance of the devnet (local Starknet instance) or with the testnet by setting the `env` variable to `dev` for devnet or `testnet` for testnet. + +Note: The private key of the deployed account will be saved in hex format in the `private_key.txt` file. This allows you, in case of failure, to not rerun the program entirely. + +## Contracts + +All used contracts can be found in `./contracts` + +- The account is in `./contracts/account/` +- The erc20 is in `./contracts/erc20/` + +You will find for each contract : the Cairo version, the compiled version and the abi. + +If you want to compile contracts yourself, input this command in a terminal : +`starknet-compile --output --abi ` + +For the transfer operation, an account is already deployed on testnet at this address : `0x0024e9f35c5d6a14dcbb3f08be5fb7703e76611767266068c521fe8cba27983c` + +Note: + +If you run the program with a devnet instance, you have to deploy an account manually and set the `predeployedContract` value with the deployed account address. + +## Providing ethereum to the deployed account + +When running the program, you will be prompted to add ethereum to the account. + +This step has to be done with the testnet [faucet](https://faucet.goerli.starknet.io/) + +Copy to the clipboard the address of the contract printed in the terminal and past it in the faucet. The transaction can take several minutes. + +Once the transaction is accepted, go to [voyager](https://goerli.voyager.online/) to search for your contract. You should see that it has a little amount of ethereum. + +Those ETHs are used to pay transaction fees. + +NOTE: this operation has to be done too for devnet. See the devnet documentation to see the process. + +## Useful links + +- [voyager](https://goerli.voyager.online/): to explore deployed contracts and transactions +- [starknet faucet](https://faucet.goerli.starknet.io/): to provide ETH to accounts +- [devnet](https://github.com/Shard-Labs/starknet-devnet) : local starknet instance +- [cairo-lang](https://github.com/starkware-libs/cairo-lang) : Cairo and CLI installing diff --git a/examples/deployAccount/contracts/account/OZAccount.cairo b/examples/deployAccount/contracts/account/OZAccount.cairo new file mode 100644 index 00000000..ab64c72b --- /dev/null +++ b/examples/deployAccount/contracts/account/OZAccount.cairo @@ -0,0 +1,115 @@ +# SPDX-License-Identifier: MIT +# OpenZeppelin Contracts for Cairo v0.3.1 (account/presets/Account.cairo) + +%lang starknet + +from starkware.cairo.common.cairo_builtins import HashBuiltin, SignatureBuiltin, BitwiseBuiltin + +from openzeppelin.account.library import Account, AccountCallArray + +from openzeppelin.introspection.erc165.library import ERC165 + +# +# Constructor +# + +@constructor +func constructor{ + syscall_ptr : felt*, + pedersen_ptr : HashBuiltin*, + range_check_ptr + }(public_key: felt): + Account.initializer(public_key) + return () +end + +# +# Getters +# + +@view +func get_public_key{ + syscall_ptr : felt*, + pedersen_ptr : HashBuiltin*, + range_check_ptr + }() -> (res: felt): + let (res) = Account.get_public_key() + return (res=res) +end + +@view +func get_nonce{ + syscall_ptr : felt*, + pedersen_ptr : HashBuiltin*, + range_check_ptr + }() -> (res: felt): + let (res) = Account.get_nonce() + return (res=res) +end + +@view +func supportsInterface{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + } (interfaceId: felt) -> (success: felt): + let (success) = ERC165.supports_interface(interfaceId) + return (success) +end + +# +# Setters +# + +@external +func set_public_key{ + syscall_ptr : felt*, + pedersen_ptr : HashBuiltin*, + range_check_ptr + }(new_public_key: felt): + Account.set_public_key(new_public_key) + return () +end + +# +# Business logic +# + +@view +func is_valid_signature{ + syscall_ptr : felt*, + pedersen_ptr : HashBuiltin*, + range_check_ptr, + ecdsa_ptr: SignatureBuiltin* + }( + hash: felt, + signature_len: felt, + signature: felt* + ) -> (is_valid: felt): + let (is_valid) = Account.is_valid_signature(hash, signature_len, signature) + return (is_valid=is_valid) +end + +@external +func __execute__{ + syscall_ptr : felt*, + pedersen_ptr : HashBuiltin*, + range_check_ptr, + ecdsa_ptr: SignatureBuiltin*, + bitwise_ptr: BitwiseBuiltin* + }( + call_array_len: felt, + call_array: AccountCallArray*, + calldata_len: felt, + calldata: felt*, + nonce: felt + ) -> (response_len: felt, response: felt*): + let (response_len, response) = Account.execute( + call_array_len, + call_array, + calldata_len, + calldata, + nonce + ) + return (response_len=response_len, response=response) +end \ No newline at end of file diff --git a/examples/deployAccount/contracts/erc20/erc20.cairo b/examples/deployAccount/contracts/erc20/erc20.cairo new file mode 100644 index 00000000..817b245c --- /dev/null +++ b/examples/deployAccount/contracts/erc20/erc20.cairo @@ -0,0 +1,179 @@ +# SPDX-License-Identifier: MIT + +%lang starknet + +from starkware.cairo.common.cairo_builtins import HashBuiltin +from starkware.cairo.common.uint256 import Uint256 +from starkware.cairo.common.bool import TRUE + +from openzeppelin.token.erc20.library import ERC20 +from openzeppelin.access.ownable.library import Ownable + +@constructor +func constructor{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }(owner: felt): + ERC20.initializer('MyToken', 'MTK', 18) + Ownable.initializer(owner) + return () +end + +# +# Getters +# + +@view +func name{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }() -> (name: felt): + let (name) = ERC20.name() + return (name) +end + +@view +func get_owner{ + syscall_ptr : felt*, + pedersen_ptr : HashBuiltin*, + range_check_ptr, +}() -> (address : felt): + let (address) = Ownable.owner() + return (address) +end + +@view +func symbol{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }() -> (symbol: felt): + let (symbol) = ERC20.symbol() + return (symbol) +end + +@view +func totalSupply{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }() -> (totalSupply: Uint256): + let (totalSupply) = ERC20.total_supply() + return (totalSupply) +end + +@view +func decimals{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }() -> (decimals: felt): + let (decimals) = ERC20.decimals() + return (decimals) +end + +@view +func balanceOf{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }(account: felt) -> (balance: Uint256): + let (balance) = ERC20.balance_of(account) + return (balance) +end + +@view +func allowance{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }(owner: felt, spender: felt) -> (remaining: Uint256): + let (remaining) = ERC20.allowance(owner, spender) + return (remaining) +end + +# +# Externals +# + +@external +func transfer{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }(recipient: felt, amount: Uint256) -> (success: felt): + ERC20.transfer(recipient, amount) + return (TRUE) +end + +@external +func transferFrom{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }(sender: felt, recipient: felt, amount: Uint256) -> (success: felt): + ERC20.transfer_from(sender, recipient, amount) + return (TRUE) +end + +@external +func approve{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }(spender: felt, amount: Uint256) -> (success: felt): + ERC20.approve(spender, amount) + return (TRUE) +end + +@external +func increaseAllowance{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }(spender: felt, added_value: Uint256) -> (success: felt): + ERC20.increase_allowance(spender, added_value) + return (TRUE) +end + +@external +func decreaseAllowance{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }(spender: felt, subtracted_value: Uint256) -> (success: felt): + ERC20.decrease_allowance(spender, subtracted_value) + return (TRUE) +end + +@external +func transferOwnership{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }(newOwner: felt): + Ownable.transfer_ownership(newOwner) + return () +end + +@external +func renounceOwnership{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }(): + Ownable.renounce_ownership() + return () +end + +@external +func mint{ + syscall_ptr: felt*, + pedersen_ptr: HashBuiltin*, + range_check_ptr + }(to: felt, amount: Uint256): + ERC20._mint(to, amount) + return () +end diff --git a/examples/deployAccount/go.mod b/examples/deployAccount/go.mod new file mode 100644 index 00000000..562e3272 --- /dev/null +++ b/examples/deployAccount/go.mod @@ -0,0 +1,33 @@ +module deployaccount + +go 1.18 + +replace github.com/NethermindEth/starknet.go => ../../ + +require github.com/NethermindEth/starknet.go v0.3.1-0.20220909184134-51c4e68080bd + +require ( + github.com/NethermindEth/juno v0.3.1 // indirect + github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect + github.com/bits-and-blooms/bitset v1.7.0 // indirect + github.com/consensys/gnark-crypto v0.11.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/deckarep/golang-set v1.8.0 // indirect + github.com/ethereum/go-ethereum v1.10.26 // indirect + github.com/fxamacker/cbor/v2 v2.4.0 // indirect + github.com/go-ole/go-ole v1.2.1 // indirect + github.com/go-stack/stack v1.8.0 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect + github.com/stretchr/testify v1.8.1 // indirect + github.com/test-go/testify v1.1.4 // indirect + github.com/tklauser/go-sysconf v0.3.5 // indirect + github.com/tklauser/numcpus v0.2.2 // indirect + github.com/x448/float16 v0.8.4 // indirect + golang.org/x/crypto v0.2.0 // indirect + golang.org/x/sys v0.3.0 // indirect + gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/examples/deployAccount/go.work b/examples/deployAccount/go.work new file mode 100644 index 00000000..b32bc53a --- /dev/null +++ b/examples/deployAccount/go.work @@ -0,0 +1,6 @@ +go 1.18 + +use ( + . + ../.. +) diff --git a/examples/deployAccount/main.go b/examples/deployAccount/main.go new file mode 100644 index 00000000..32e8e342 --- /dev/null +++ b/examples/deployAccount/main.go @@ -0,0 +1,329 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "os" + + "github.com/NethermindEth/juno/core/felt" + starknetgo "github.com/NethermindEth/starknet.go" + "github.com/NethermindEth/starknet.go/artifacts" + "github.com/NethermindEth/starknet.go/gateway" + "github.com/NethermindEth/starknet.go/rpcv02" + "github.com/NethermindEth/starknet.go/types" + "github.com/NethermindEth/starknet.go/utils" + ethrpc "github.com/ethereum/go-ethereum/rpc" +) + +const ( + clientEndpoint = "http://0.0.0.0:50505" //devnet + env = "testnet" + compiledOZAccount = "./contracts/account/OZAccount_compiled.json" + compiledERC20Contract = "./contracts/erc20/erc20_custom_compiled.json" + predeployedContract = "0x0024e9f35c5d6a14dcbb3f08be5fb7703e76611767266068c521fe8cba27983c" + classHash = "0x0148abd2788c5606368d2ad824da288b46e69db0c628f969b1c271a99adc3553" + maxPoll = 15 + pollInterval = 5 +) + +func main() { + // Connect to client + c, err := ethrpc.DialContext(context.Background(), clientEndpoint) + if err != nil { + panic(fmt.Sprintf("Failed to connect to client: ", err)) + } + + classHashFelt, err := utils.HexToFelt(classHash) + if err != nil { + panic(err) + } + + accountCompiled := felt.Zero.SetBytes(artifacts.AccountCompiled) + + fakePubKey := felt.Zero.SetUint64(1234) + + // Build transaction + clientv02 := rpcv02.NewProvider(c) + deployAcntTx := rpcv02.BroadcastedDeployAccountTransaction{ + BroadcastedTxnCommonProperties: rpcv02.BroadcastedTxnCommonProperties{ + Type: rpcv02.TransactionType_Deploy, + MaxFee: fakePubKey, + Nonce: &felt.Zero, + Signature: []*felt.Felt{}, // todo(fillin) + Version: rpcv02.TransactionV0, + }, + ClassHash: classHashFelt, + ConstructorCalldata: []*felt.Felt{accountCompiled}, //todo(test/fix) + ContractAddressSalt: fakePubKey, + } + + // Submit transaction + deployAcntResp, err := clientv02.AddDeployAccountTransaction(context.Background(), deployAcntTx) + if err != nil { + panic(err) + } + + fmt.Println(deployAcntResp) + + /////// GET ADDRESS + // // new Open Zeppelin account v0.5.1 : + // // Generate public and private key pair. + // const privateKey = stark.randomAddress(); + // console.log('New OZ account :\nprivateKey=', privateKey); + // const starkKeyPub = ec.starkCurve.getStarkKey(privateKey); + // console.log('publicKey=', starkKeyPub); + + // const OZaccountClassHash = "0x2794ce20e5f2ff0d40e632cb53845b9f4e526ebd8471983f7dbd355b721d5a"; + // // Calculate future address of the account + // const OZaccountConstructorCallData = CallData.compile({ publicKey: starkKeyPub }); + // const OZcontractAddress = hash.calculateContractAddressFromHash( + // starkKeyPub, + // OZaccountClassHash, + // OZaccountConstructorCallData, + // 0 + // ); + + ///////// MINT + // curl -X POST http://127.0.0.1:5050/mint -d '{"address":"0x04a093c37ab61065d001550089b1089922212c60b34e662bb14f2f91faee2979","amount":50000000000000000000,"lite":true}' -H "Content-Type:application/json" + // // {"new_balance":50000000000000000000,"tx_hash":null,"unit":"wei"}const OZaccount = new Account(provider, OZcontractAddress, privateKey); + + //////// DEPLOY ACCOUNT + // const { transaction_hash, contract_address } = await OZaccount.deployAccount({ + // classHash: OZaccountClassHash, + // constructorCalldata: OZaccountConstructorCallData, + // addressSalt: starkKeyPub + // }); + + // await provider.waitForTransaction(transaction_hash); + // console.log('✅ New OpenZeppelin account created.\n address =', contract_address); + + privateKey, err := starknetgo.Curve.GetRandomPrivateKey() + if err != nil { + fmt.Println("can't get random private key:", err) + os.Exit(1) + } + pubX, _, err := starknetgo.Curve.PrivateToPoint(privateKey) + if err != nil { + fmt.Println("can't generate public key:", err) + os.Exit(1) + } + + contractClass := rpcv02.ContractClass{} + err = json.Unmarshal(artifacts.AccountCompiled, &contractClass) + if err != nil { + fmt.Println("could not log file", err) + os.Exit(1) + } + fmt.Println("Deploying account to testnet. It may take a while.") + accountResponse, err := gw.Deploy(context.Background(), contractClass, types.DeployRequest{ + Type: gateway.DEPLOY, + ContractAddressSalt: types.BigToHex(pubX), // salt to hex + ConstructorCalldata: []string{pubX.String()}}) // public key + if err != nil { + fmt.Println("can't deploy account:", err) + os.Exit(1) + } + + if err := waitForTransaction(gw, accountResponse.TransactionHash); err != nil { + fmt.Println("Account deployement transaction failure:", err) + os.Exit(1) + } + + tx, err := gw.Transaction(context.Background(), gateway.TransactionOptions{TransactionHash: accountResponse.TransactionHash}) + if err != nil { + fmt.Println("can't fetch transaction data:", err) + os.Exit(1) + } + + account, err := starknetgo.NewGatewayAccount(privateKey.String(), types.StrToFelt(tx.Transaction.ContractAddress), gw) + if err != nil { + fmt.Println("can't create account:", err) + os.Exit(1) + } + + fmt.Println("Account deployed. Contract address: ", account.Address) + if err := savePrivateKey(types.BigToHex(privateKey)); err != nil { + fmt.Println("can't save private key:", err) + os.Exit(1) + } + + // At this point you need to add funds to the deployed account in order to use it. + var input string + fmt.Println("The deployed account has to be feeded with ETH to perform transaction.") + fmt.Print("When your account has been funded with the faucet, press any key and enter to continue : ") + fmt.Scan(&input) + + fmt.Println("Deploying erc20 contract. It may take a while") + erc20Response, err := gw.Deploy(context.Background(), compiledERC20Contract, types.DeployRequest{ + Type: gateway.DEPLOY, + ContractAddressSalt: types.BigToHex(pubX), // salt to hex + ConstructorCalldata: []string{ + account.Address.String(), // owner + "2000", // initial supply + "0", // Uint256 additional parameter + }, + }) + if err != nil { + fmt.Println("can't deploy erc20 contract:", err) + os.Exit(1) + } + + if err := waitForTransaction(gw, erc20Response.TransactionHash); err != nil { + fmt.Println("ERC20 deployment transaction failure:", err) + os.Exit(1) + } + + txERC20, err := gw.Transaction(context.Background(), gateway.TransactionOptions{TransactionHash: erc20Response.TransactionHash}) + if err != nil { + fmt.Println("can't fetch transaction data:", err) + os.Exit(1) + } + fmt.Println("ERC20 contract deployed.", + "Contract address: ", txERC20.Transaction.ContractAddress, + "Transaction hash: ", txERC20.Transaction.TransactionHash, + ) + + erc20ContractAddr := txERC20.Transaction.ContractAddress + + fmt.Println("Minting 10 tokens to your account...") + if err := mint(gw, account, erc20ContractAddr); err != nil { + fmt.Println("can't mint erc20 contract:", err) + os.Exit(1) + } + + balance, err := balanceOf(gw, erc20ContractAddr, account.Address.Hex()) + if err != nil { + fmt.Println("can't get balance of:", account.Address, err) + os.Exit(1) + } + fmt.Println("Your account has ", balance, " tokens.") + + fmt.Println("Transferring 5 tokens from", account.Address, "to", predeployedContract) + if err := transferFrom(gw, account, erc20ContractAddr, predeployedContract); err != nil { + fmt.Println("can't transfer tokens:", account.Address, err) + os.Exit(1) + } + + balanceAccount, err := balanceOf(gw, erc20ContractAddr, account.Address.Hex()) + if err != nil { + fmt.Println("can't get balance of:", account.Address, err) + os.Exit(1) + } + balancePredeployed, err := balanceOf(gw, erc20ContractAddr, account.Address.Hex()) + if err != nil { + fmt.Println("can't get balance of:", predeployedContract, err) + os.Exit(1) + } + + fmt.Println("Transfer done.") + fmt.Println("Account balance: ", balanceAccount, ". Predeployed account balance: ", balancePredeployed) +} + +// Utils function to wait for transaction to be accepted on L2 and print tx status. +func waitForTransaction(gw *gateway.Gateway, transactionHash string) error { + acceptedOnL2 := false + var receipt *gateway.TransactionReceipt + var err error + fmt.Println("Polling until transaction is accepted on L2...") + for !acceptedOnL2 { + _, receipt, err = gw.PollTx(context.Background(), transactionHash, types.ACCEPTED_ON_L2, pollInterval, maxPoll) + if err != nil { + fmt.Println(receipt.Status) + return fmt.Errorf("Transaction Failure (%s): can't poll to desired status: %s", transactionHash, err.Error()) + } + fmt.Println("Current status : ", receipt.Status) + if receipt.Status == types.ACCEPTED_ON_L2.String() { + acceptedOnL2 = true + } + } + return nil +} + +// mint mints the erc20 contract through the account. +func mint(gw *gateway.Gateway, account *starknetgo.Account, erc20address string) error { + // Transaction that will be executed by the account contract. + tx := []types.FunctionCall{ + { + ContractAddress: types.StrToFelt(erc20address), + EntryPointSelector: "mint", + Calldata: []string{ + account.Address.String(), // to + "10", // amount to mint + "0", // UInt256 additional parameter + }, + }, + } + + execResp, err := account.Execute(context.Background(), tx, types.ExecuteDetails{}) + if err != nil { + return fmt.Errorf("can't execute transaction: %w", err) + } + + if err := waitForTransaction(gw, execResp.TransactionHash); err != nil { + return fmt.Errorf("a problem occured with the transaction: %w", err) + } + return nil +} + +// transferFrom will transfer 5 tokens from account balance to the otherAccount by +// calling the transferFrom function of the erc20 contract. +func transferFrom(gw *gateway.Gateway, account *starknetgo.Account, erc20address, otherAccount string) error { + // Transaction that will be executed by the account contract. + tx := []types.FunctionCall{ + { + ContractAddress: types.StrToFelt(erc20address), + EntryPointSelector: "transferFrom", + Calldata: []string{ + account.Address.String(), // sender + types.HexToBN(otherAccount).String(), // recipient + "5", // amount to transfer + "0", // UInt256 additional parameter + }, + }, + } + + execResp, err := account.Execute(context.Background(), tx, types.ExecuteDetails{}) + if err != nil { + return fmt.Errorf("can't execute transaction: %w", err) + } + + if err := waitForTransaction(gw, execResp.TransactionHash); err != nil { + return fmt.Errorf("a problem occured with transaction: %w", err) + } + return nil +} + +// balanceOf returns the balance of the account at the accountAddress address. +func balanceOf(gw *gateway.Gateway, erc20address, accountAddress string) (string, error) { + res, err := gw.Call(context.Background(), types.FunctionCall{ + ContractAddress: types.StrToFelt(erc20address), + EntryPointSelector: "balanceOf", + Calldata: []string{ + types.HexToBN(accountAddress).String(), + }, + }, "") + if err != nil { + return "", fmt.Errorf("can't call erc20: %s. Error: %w", accountAddress, err) + } + low := types.StrToFelt(res[0]) + hi := types.StrToFelt(res[1]) + + balance, err := types.NewUint256(low, hi) + if err != nil { + return "", nil + } + return balance.String(), nil +} + +func savePrivateKey(privKey string) error { + file, err := os.Create("private_key.txt") + if err != nil { + return fmt.Errorf("can't create private_key.txt") + } + defer file.Close() + if _, err := file.WriteString(privKey); err != nil { + return fmt.Errorf("can't write private_key.txt") + } + return nil +} diff --git a/utils/Felt.go b/utils/Felt.go index db97b235..406d77fb 100644 --- a/utils/Felt.go +++ b/utils/Felt.go @@ -33,3 +33,9 @@ func FeltToBigInt(f *felt.Felt) (*big.Int, bool) { func BigIntToFelt(big *big.Int) (*felt.Felt, error) { return new(felt.Felt).SetString(big.String()) } + +func ByteArrToFeltArr(byteArr *[]byte) (feltArr []*felt.Felt) { + for _, byteElt := range *byteArr { + feltArr = append(feltArr, felt.Zero.SetBytes(byteElt)) + } +}