> ## Documentation Index
> Fetch the complete documentation index at: https://docs.near.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Transfers & Actions

> Learn how contracts can make transfers, call other contracts, and more

export const Github = ({url, start, end, fname, language, withSourceLink = true}) => {
  const [code, setCode] = useState(null);
  function toRaw(ref) {
    const fullUrl = ref.slice(ref.indexOf('https'));
    const [url] = fullUrl.split('#');
    const [org, repo, , branch, ...pathSeg] = new URL(url).pathname.split('/').slice(1);
    return `https://raw.githubusercontent.com/${org}/${repo}/${branch}/${pathSeg.join('/')}`;
  }
  async function fetchCode(url, fromLine, toLine) {
    let res;
    if (typeof window !== 'undefined') {
      const validUntil = localStorage.getItem(`${url}-until`);
      if (validUntil && Number(validUntil) > Date.now()) {
        res = localStorage.getItem(url);
      }
    }
    if (!res) {
      try {
        res = await (await fetch(url)).text();
        if (typeof window !== 'undefined') {
          localStorage.setItem(url, res);
          localStorage.setItem(`${url}-until`, String(Date.now() + 60000));
        }
      } catch {
        return 'Error fetching code, please try reloading';
      }
    }
    let body = res.split('\n');
    const from = fromLine ? Number(fromLine) - 1 : 0;
    const to = toLine ? Number(toLine) : body.length;
    body = body.slice(from, to);
    const precedingSpace = body.reduce((prev, line) => {
      if (line.length === 0) return prev;
      const spaces = line.match(/^\s+/);
      if (spaces) return Math.min(prev, spaces[0].length);
      return 0;
    }, Infinity);
    return body.map(line => line.slice(precedingSpace === Infinity ? 0 : precedingSpace)).join('\n');
  }
  function buildSourceUrl(url, start, end) {
    const base = url.split('#')[0];
    if (start && end) return `${base}#L${start}-L${end}`;
    if (start) return `${base}#L${start}`;
    return base;
  }
  useEffect(() => {
    const rawUrl = toRaw(url);
    fetchCode(rawUrl, start, end).then(res => setCode(res));
  }, [url, start, end]);
  const sourceUrl = buildSourceUrl(url, start, end);
  const fileName = fname ?? sourceUrl.split('/').pop();
  return <div className="my-5">
      {code === null ? <div>Loading...</div> : <CodeBlock language={language} filename={fileName} lines>
          {code}
        </CodeBlock>}
      {withSourceLink && <div className="flex justify-end" style={{
    marginTop: "-1rem"
  }}>
          <a href={sourceUrl} target="_blank" rel="noreferrer noopener" className="text-[0.6875rem] font-medium text-[#656d76] no-underline hover:text-[#1f2328] dark:text-[#8b949e] dark:hover:text-[#e6edf3]">
            See code on GitHub
          </a>
        </div>}
    </div>;
};

This page describes the different types of actions that a smart contract can perform on NEAR like transferring NEAR, calling other contracts, creating sub-accounts, and deploying contracts. It also explains how to add access keys to accounts.

Smart contracts can perform specific `Actions` such as transferring NEAR, or calling other contracts.

An important property of `Actions` is that they can be batched together when acting on the same contract. **Batched actions** act as a unit: they execute in the same [receipt](/protocol/transactions/transaction-execution#receipts--finality), and if **any fails**, then they **all get reverted**.

<Info>
  `Actions` can be batched only when they act on the **same contract**. You can batch calling two methods on a contract,
  but **cannot** call two methods on different contracts.
</Info>

***

## Transfer NEAR Ⓝ

You can send `$NEAR` from your contract to any other account on the network. The Gas cost for transferring `$NEAR` is fixed and is based on the protocol's genesis config. Currently, it costs `~0.45 TGas`.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
  use near_sdk::{near, AccountId, Promise, NearToken};

  #[near(contract_state)]
  #[derive(Default)]
  pub struct Contract { }

  #[near]
  impl Contract {
    pub fn transfer(&self, to: AccountId, amount: NearToken){
      Promise::new(to).transfer(amount);
    }
  }
```

<Tip>
  **Why is there no callback?**
  The only case where a transfer will fail is if the receiver account does **not** exist.
</Tip>

<Warning>
  Remember that your balance is used to cover for the contract's storage. When sending money, make sure you always leave enough to cover for future storage needs.
</Warning>

***

## Function Call

Your smart contract can call methods in another contract. In the snippet below we call a method
in a deployed [Hello NEAR](../quickstart) contract, and check if everything went
right in the callback.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
  use near_sdk::{near, env, log, Promise, Gas, PromiseError};
  use serde_json::json;

  #[near(contract_state)]
  #[derive(Default)]
  pub struct Contract { }

  const HELLO_NEAR: &str = "hello-nearverse.testnet";
  const NO_DEPOSIT: u128 = 0;
  const CALL_GAS: Gas = Gas(5_000_000_000_000);

  #[near]
  impl Contract {
    pub fn call_method(&self){
      let args = json!({ "message": "howdy".to_string() })
                .to_string().into_bytes().to_vec();

      Promise::new(HELLO_NEAR.parse().unwrap())
      .function_call("set_greeting".to_string(), args, NO_DEPOSIT, CALL_GAS)
      .then(
        Promise::new(env::current_account_id())
        .function_call("callback".to_string(), Vec::new(), NO_DEPOSIT, CALL_GAS)
      );
    }

    pub fn callback(&self, #[callback_result] result: Result<(), PromiseError>){
      if result.is_err(){
          log!("Something went wrong")
      }else{
          log!("Message changed")
      }
    }
  }
```

<Warning>
  The snippet showed above is a low level way of calling other methods. We recommend make calls to other contracts as explained in the [Cross-contract Calls section](/smart-contracts/anatomy/crosscontract).
</Warning>

***

## Create a Sub Account

Your contract can create direct sub accounts of itself, for example, `user.near` can create `sub.user.near`.

Accounts do **NOT** have control over their sub-accounts, since they have their own keys.

Sub-accounts are simply useful for organizing your accounts (e.g. `dao.project.near`, `token.project.near`).

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
  use near_sdk::{near, env, Promise, NearToken};

  #[near(contract_state)]
  #[derive(Default)]
  pub struct Contract { }

  const MIN_STORAGE: NearToken = NearToken::from_millinear(1); //0.001Ⓝ

  #[near]
  impl Contract {
    pub fn create(&mut self, prefix: String) {
      let account_id = prefix + "." + &env::current_account_id().to_string();
      Promise::new(account_id.parse().unwrap())
        .create_account()
        .transfer(MIN_STORAGE);
    }
  }
```

<Tip>
  Notice that in the snippet we are transferring some money to the new account for storage
</Tip>

<Warning>
  When you create an account from within a contract, it has no keys by default. If you don't explicitly [add keys](#add-keys) to it or [deploy a contract](#deploy-a-contract) on creation then it will be [locked](../../protocol/accounts-contracts/access-keys#locked-accounts).
</Warning>

<hr className="subsection" />

#### Creating `.testnet` / `.near` Accounts

Accounts can only create immediate sub-accounts of themselves.

If your contract wants to create a `.mainnet` or `.testnet` account, then it needs to [call](#function-call)
the `create_account` method of `near` or `testnet` root contracts.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
  use near_sdk::{near, Promise, Gas, NearToken };
  use serde_json::json;

  #[near(contract_state)]
  #[derive(Default)]
  pub struct Contract { }

  const CALL_GAS: Gas = Gas::from_gas(28_000_000_000_000);
  const MIN_STORAGE: NearToken = NearToken::from_yoctonear(1_820_000_000_000_000_000_000); //0.00182Ⓝ

  #[near]
  impl Contract {
    pub fn create_account(&mut self, account_id: String, public_key: String){
      let args = json!({
                  "new_account_id": account_id,
                  "new_public_key": public_key,
                }).to_string().into_bytes().to_vec();

      // Use "near" to create mainnet accounts
      Promise::new("testnet".parse().unwrap())
        .function_call("create_account".to_string(), args, MIN_STORAGE, CALL_GAS);
    }
  }
```

***

## Deploy a Contract

When creating an account you can also batch the action of deploying a contract to it. Note that for this, you will need to pre-load the byte-code you want to deploy in your contract.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
  use near_sdk::{near, env, Promise, NearToken};

  #[near(contract_state)]
  #[derive(Default)]
  pub struct Contract { }

  const MIN_STORAGE: NearToken = NearToken::from_millinear(1100); //1.1Ⓝ
  const HELLO_CODE: &[u8] = include_bytes!("./hello.wasm");

  #[near]
  impl Contract {
    pub fn create_hello(&self, prefix: String){
      let account_id = prefix + "." + &env::current_account_id().to_string();
      Promise::new(account_id.parse().unwrap())
        .create_account()
        .transfer(MIN_STORAGE)
        .deploy_contract(HELLO_CODE.to_vec());
    }
  }
```

<Tip>
  If an account with a contract deployed does **not** have any access keys, this is known as a locked contract. When the account is locked, it cannot sign transactions therefore, actions can **only** be performed from **within** the contract code.
</Tip>

***

## Add Keys

When you use actions to create a new account, the created account does not have any [access keys](../../protocol/accounts-contracts/access-keys), meaning that it **cannot sign transactions** (e.g. to update its contract, delete itself, transfer money).

There are two options for adding keys to the account:

1. `add_access_key`: adds a key that can only call specific methods on a specified contract.
2. `add_full_access_key`: adds a key that has full access to the account.

<br />

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
  use near_sdk::{near, env, Promise, NearToken, PublicKey};

  #[near(serializers = [json, borsh])]
  #[derive(Default)]
  pub struct Contract { }

  const MIN_STORAGE: NearToken = NearToken::from_millinear(1100); //1.1Ⓝ
  const HELLO_CODE: &[u8] = include_bytes!("./hello.wasm");

  #[near]
  impl Contract {
    pub fn create_hello(&self, prefix: String, public_key: PublicKey){
      let account_id = prefix + "." + &env::current_account_id().to_string();
      Promise::new(account_id.parse().unwrap())
        .create_account()
        .transfer(MIN_STORAGE)
        .deploy_contract(HELLO_CODE.to_vec())
        .add_full_access_key(public_key);
    }
  }
```

Notice that what you actually add is a "public key". Whoever holds its private counterpart, i.e. the private-key, will be able to use the newly access key.

<Note>
  The `public_key` can use any of NEAR's [signature schemes](/protocol/accounts-contracts/access-keys#signature-schemes) — `ed25519`, `secp256k1`, or the post-quantum `ml-dsa-65`. Adding an `ml-dsa-65` key needs no code changes: pass an `ml-dsa-65:...` key exactly like the examples above.
</Note>

<Tip>
  If an account with a contract deployed does **not** have any access keys, this is known as a locked contract. When the account is locked, it cannot sign transactions therefore, actions can **only** be performed from **within** the contract code.
</Tip>

***

## Delete Account

There are two scenarios in which you can use the `delete_account` action:

1. As the **last** action in a chain of batched actions.
2. To make your smart contract delete its own account.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
  use near_sdk::{near, env, Promise, NearToken, AccountId};

  #[near(contract_state)]
  #[derive(Default)]
  pub struct Contract { }

  const MIN_STORAGE: NearToken = NearToken::from_millinear(1); //0.001Ⓝ

  #[near]
  impl Contract {
    pub fn create_delete(&self, prefix: String, beneficiary: AccountId){
      let account_id = prefix + "." + &env::current_account_id().to_string();
      Promise::new(account_id.parse().unwrap())
        .create_account()
        .transfer(MIN_STORAGE)
        .delete_account(beneficiary);
    }

    pub fn self_delete(beneficiary: AccountId){
      Promise::new(env::current_account_id())
        .delete_account(beneficiary);
    }
  }
```

<Warning>
  **Token Loss**
  If the beneficiary account does not exist the funds will be [**dispersed among validators**](../../protocol/network/token-loss).
</Warning>

<Warning>
  **Token Loss**
  Do **not** use `delete` to try fund a new account. Since the account doesn't exist the tokens will be lost.
</Warning>
