Using the Stark Validator
The Stark Validator Module can be used as a Core Validator for the account. It is used by default by the modular account in many configuration. In this section of the documentation, you will see how you can use the Moduler Account with the Stark Validator Module as a Core Module.
- Using the Stark Validator
 
Note: This section assumes the
SmartrAccountclass has been instantiated in thesmartrAccountvariable as shown in Using the modular account from the SDK. It also assumes theCountercontract that comes with the project has been deploys to thecounterAddressand theCounterABIclass is available. The02-setup.tsscript that comes with this project ensure those steps are executed.
Interacting with a Contract
The starknet modular account SDK provides the SmartrAccount class that extends
the starknet.js Account class. As you can see from the script below, using the
SmartrAccount is exactly like using the Account class, you can:
- instantiate the account with an 
RpcProvider, anaddressand aSigneror private key - use the account in a 
Contractto call view functions - use the 
executefunction of the account to call an external function of a contract.SmartrAccountprovides the same methods asAccount 
// file src/02-execute-tx.ts
import { SmartrAccount } from "@0xknwn/starknet-modular-account";
import { init, CounterABI } from "./02-init";
import { RpcProvider, Contract } from "starknet";
const providerURL = "http://127.0.0.1:5050/rpc";
const main = async () => {
  const provider = new RpcProvider({ nodeUrl: providerURL });
  const { accountAddress, counterAddress, smartrAccountPrivateKey } =
    await init();
  const account = new SmartrAccount(
    provider,
    accountAddress,
    smartrAccountPrivateKey,
    undefined,
    "1",
    "0x3"
  );
  const counter = new Contract(CounterABI, counterAddress, account);
  let currentCounter = await counter.call("get");
  console.log("currentCounter", currentCounter);
  const call = counter.populate("increment");
  const { transaction_hash } = await account.execute(call);
  const receipt = await account.waitForTransaction(transaction_hash);
  console.log("transaction succeeded", receipt.isSuccess());
  currentCounter = await counter.call("get");
  console.log("currentCounter", currentCounter);
};
main()
  .then(() => {})
  .catch((e) => {
    console.warn(e);
  });
Transpile and run the script:
npx tsc --build
node dist/02-execute-tx.js
Interacting with the Stark Validator
The SmartrAccount class, however, provides more than just the regular
Account class. It can interact with functions that are part of the module
and not part of the account. In the case of the Stark Validator, those
functions are:
#![allow(unused)] fn main() { fn get_public_key(self: @TState) -> felt252; fn set_public_key(ref self: TState, new_public_key: felt252); }
To execute a function that is part of the module you need:
- to figure out the stark validator module class hash
 - to check the module is installed on the account. That is something that is setup at the account deployment time
 - to use one of 
callOnModulefor view functions orexecuteOnModulefor running transactions on the SmartrAccount. 
The sections below dig into the details of these operations.
Getting the stark validator module class hash
This is something we have already done previously. You can use
classHash("StaekValidator") after your imported the classHash function from
@0xknwn/starknet-modular-account like below:
// file src/02-check-class.ts
import { classHash, classNames } from "@0xknwn/starknet-modular-account";
console.log("starkValidator class hash:", classHash(classNames.StarkValidator));
To execute the script, make sure you have deployed the account in the network and run the following commands:
npx tsc --build
node dist/02-check-class.js
Check the module is installed on the account
The SmartrAccount provides a method isModule that can be used to know if
a module is installed with the account. 
// file src/02-module-installed.ts
import {
  SmartrAccount,
  classHash,
  classNames,
} from "@0xknwn/starknet-modular-account";
import { init } from "./02-init";
import { RpcProvider } from "starknet";
const providerURL = "http://127.0.0.1:5050/rpc";
const main = async () => {
  const provider = new RpcProvider({ nodeUrl: providerURL });
  const { accountAddress, smartrAccountPrivateKey } = await init();
  const account = new SmartrAccount(
    provider,
    accountAddress,
    smartrAccountPrivateKey,
    undefined,
    "1",
    "0x3"
  );
  const isInstalled = await account.isModule(
    classHash(classNames.StarkValidator)
  );
  console.log(
    "module",
    classHash(classNames.StarkValidator),
    "is installed",
    isInstalled
  );
};
main()
  .then(() => {})
  .catch((e) => {
    console.warn(e);
  });
Transpile and run the script:
npx tsc --build
node dist/02-module-installed.js
Calling views functions in the module
To execute a view function on the module, we must build the argumemt list with
the CallData class. Thwn we can call the callOnModule function from
SmartrAccount with the module class hash, the function name and the calldata
like below:
// file src/02-registered-publickeys.ts
import {
  StarkValidatorABI,
  SmartrAccount,
  classHash,
  classNames,
} from "@0xknwn/starknet-modular-account";
import { init } from "./02-init";
import { CallData, RpcProvider } from "starknet";
const providerURL = "http://127.0.0.1:5050/rpc";
const main = async () => {
  const provider = new RpcProvider({ nodeUrl: providerURL });
  const { accountAddress, smartrAccountPrivateKey } = await init();
  const account = new SmartrAccount(
    provider,
    accountAddress,
    smartrAccountPrivateKey,
    undefined,
    "1",
    "0x3"
  );
  const moduleCallData = new CallData(StarkValidatorABI);
  const calldata = await moduleCallData.compile("get_public_key", {});
  const publickey = await account.callOnModule(
    classHash(classNames.StarkValidator),
    "get_public_key",
    calldata
  );
  console.log("publickey is", `0x${BigInt(publickey[0]).toString(16)}`);
};
main()
  .then(() => {})
  .catch((e) => {
    console.warn(e);
  });
Transpile and run the script:
npx tsc --build
node dist/02-registered-publickey.js
Executing external functions in the module
To execute an external function on the module, we must build the argumemt list
with the CallData class. Then we can call the executeOnModule function from
SmartrAccount with the module class hash, the function name and the calldata
like below. Here we will register a second public key for the same account:
// file src/02-add-publickey.ts
import {
  StarkValidatorABI,
  SmartrAccount,
  classHash,
  classNames,
} from "@0xknwn/starknet-modular-account";
import { init } from "./02-init";
import { CallData, RpcProvider, Signer } from "starknet";
const providerURL = "http://127.0.0.1:5050/rpc";
const newAccountPrivateKey = "0x2";
const main = async () => {
  const signer = new Signer(newAccountPrivateKey);
  const newAccountPublicKey = await signer.getPubKey();
  console.log("second account public key", newAccountPublicKey);
  const provider = new RpcProvider({ nodeUrl: providerURL });
  const { accountAddress, smartrAccountPrivateKey } = await init();
  const account = new SmartrAccount(
    provider,
    accountAddress,
    smartrAccountPrivateKey,
    undefined,
    "1",
    "0x3"
  );
  const moduleCallData = new CallData(StarkValidatorABI);
  const calldata = await moduleCallData.compile("set_public_key", {
    new_public_key: newAccountPublicKey,
  });
  const { transaction_hash } = await account.executeOnModule(
    classHash(classNames.StarkValidator),
    "set_public_key",
    calldata
  );
  const receipt = await account.waitForTransaction(transaction_hash);
  console.log("transaction succeeded", receipt.isSuccess());
};
main()
  .then(() => {})
  .catch((e) => {
    console.warn(e);
  });
Transpile and run the script:
npx tsc --build
node dist/02-update-publickey.js
You can re-run the script from the previous example to check the account has two registered public key:
node dist/02-registered-publickey.js
Interacting with a Contract with the new registered key
You now can interact with the SmartrAccount with your new private key like
below:
// file src/02-execute-tx-pk2.ts
import { SmartrAccount } from "@0xknwn/starknet-modular-account";
import { init, CounterABI } from "./02-init";
import { RpcProvider, Contract } from "starknet";
const providerURL = "http://127.0.0.1:5050/rpc";
const newSmartrAccountPrivateKey = "0x2";
const main = async () => {
  const provider = new RpcProvider({ nodeUrl: providerURL });
  const { accountAddress, counterAddress } = await init();
  const account = new SmartrAccount(
    provider,
    accountAddress,
    newSmartrAccountPrivateKey,
    undefined,
    "1",
    "0x3"
  );
  const counter = new Contract(CounterABI, counterAddress, account);
  let currentCounter = await counter.call("get");
  console.log("currentCounter", currentCounter);
  const call = counter.populate("increment");
  const { transaction_hash } = await account.execute(call);
  const receipt = await account.waitForTransaction(transaction_hash);
  console.log("transaction succeeded", receipt.isSuccess());
  currentCounter = await counter.call("get");
  console.log("currentCounter", currentCounter);
};
main()
  .then(() => {})
  .catch((e) => {
    console.warn(e);
  });
Transpile and run the script:
npx tsc --build
node dist/02-execute-tx-pk2.js
Interacting with the Contract with the SDK Stark Module
You can use the StarkValidator as a secondary module, even when installed as a Core module. To run a transaction with such a configuration, all you have to do is to call the StarkModule with the account address when creating the SmartrAccount by adding a 4th parameter to the constructor. The script below shows the change:
// file src/02-execute-tx-pk2-with-module.ts
import { SmartrAccount } from "@0xknwn/starknet-modular-account";
import { StarkModule } from "@0xknwn/starknet-module";
import { init, CounterABI } from "./02-init";
import { RpcProvider, Contract } from "starknet";
const providerURL = "http://127.0.0.1:5050/rpc";
const newSmartrAccountPrivateKey = "0x2";
const main = async () => {
  const provider = new RpcProvider({ nodeUrl: providerURL });
  const { accountAddress, counterAddress } = await init();
  const module = new StarkModule(accountAddress);
  const account = new SmartrAccount(
    provider,
    accountAddress,
    newSmartrAccountPrivateKey,
    module,
    "1",
    "0x3"
  );
  const counter = new Contract(CounterABI, counterAddress, account);
  let currentCounter = await counter.call("get");
  console.log("currentCounter", currentCounter);
  const call = counter.populate("increment");
  const { transaction_hash } = await account.execute(call);
  const receipt = await account.waitForTransaction(transaction_hash);
  console.log("transaction succeeded", receipt.isSuccess());
  currentCounter = await counter.call("get");
  console.log("currentCounter", currentCounter);
};
main()
  .then(() => {})
  .catch((e) => {
    console.warn(e);
  });
If you check the transaction, you can see the call is prefixed by
a call to __validate_module__ with the account address and StarkValidator
class hash as a first parameter. Transpile and run the script:
npx tsc --build
node dist/02-execute-tx-pk2-with-module.js
Note: The Starkmodule is part of
@0xknwn/starknet-moduleand this SDK as to be installed if you want to interact with the StarkModule as a secondary module.