Skip to main content

Setting up the Near account to be controlled by MPC

One of the powerful features of the NEAR Protocol is its flexible access keys architecture. An account can hold multiple access keys, each with different levels of permission. This enables us to grant transaction-signing capabilities to an external key without compromising security.

To achieve secure external control via MPC, we must derive a valid secp256k1 public key from the MPC smart contract. This key belongs to a key pair that will be used later in the tutorial for signing transactions securely.

Before we proceed, let's create an account on whose behalf we will be acting.

Creating an account​

If you already have a NEAR account that you want to control via MPC, feel free to skip this step. Otherwise, use the following command:

near account create-account fund-myself

Deriving a Public Key from MPC​

As you already know from the Chain Signatures documentation, derivation_path is the key component that allows generating multiple distinct key pairs. When combined with predecessor_id, it forms a unique and secure pair.

In our example, the smart contract acts as a proxy between a user and the MPC, which means the contract itself becomes the predecessor in the derivation process.

To understand how derivation_path is built, let's examine the smart contract implementation:

let derivation_path = format!(
"{}-{}",
env::predecessor_account_id().to_string(),
args.signer_id.to_string()
);
  • args.signer_id is the account on whose behalf we're acting
  • env::predecessor_account_id().to_string() refers to the account that is calling the contract, please do not confuse it with previously mentioned predecessor_id as it refers to the smart contract address

Now that we understand how each input is calculated, let's put them together and actually derive a public key.

const contractId = "broken-rock.testnet"; // smart contract address
const adminAccountId = "admin.testnet"; // signs transactions to act on behalf of `controllableAccountId`
const controllableAccountId = "controllable.testnet"; // on whose behalf we'll be acting

// admin.testnet-controllable.testnet
const derivationPath = `${adminAccountId}-${controllableAccountId}`;

// secp256k1:m2CUiQw9f5nN8sAszkHrbok6apRz7j6LkpFZ6vT6zzxLHh2C54udU9Ue7eRy7FRK42pD796nNSwEdsqXzLb96PR
const derivedPublicKey = await deriveKey(contractId, derivationPath);

Adding key to the account​

Once we have the public key, the final step is to add it to the NEAR account.

near account add-key controllable.testnet grant-full-access use-manually-provided-public-key secp256k1:m2CUiQw9f5nN8sAszkHrbok6apRz7j6LkpFZ6vT6zzxLHh2C54udU9Ue7eRy7FRK42pD796nNSwEdsqXzLb96PR network-config testnet sign-with-legacy-keychain send

In our example, we’ve added this public key as a FullAccess key, meaning it has full control over the account, this allows us to execute all transactions without limitations. However, it is also possible to add the key as a FunctionCall access key with limited permissions.

The next step is to create, sign and eventually send a transfer transaction on behalf of controllable.testnet. Continue to the next chapter to learn how.

Was this page helpful?