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

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.ton.org/feedback

```json
{
  "path": "/standard/wallets/v5-api",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# Wallet V5 API

export const Image = ({src, darkSrc, alt = '', darkAlt, href, target, height = 342, width = 608, noZoom = false, center = false}) => {
  const isSVG = src.match(/\.svg(?:[#?].*?)?$/i) !== null;
  const shouldInvert = isSVG && !darkSrc;
  const shouldCreateLink = href !== undefined;
  const minPx = 9;
  const maxPx = 608;
  const expectedPx = `a number or a string with a number that is greater than ${minPx - 1} and less than or equal to ${maxPx}`;
  const createInvalidPropCallout = (title, received, expected) => {
    return <Danger>
        <span className="font-bold">
          Invalid <code>{title.toString()}</code> passed!
        </span>
        <br />
        <span className="font-bold">Received: </span>
        {received.toString()}
        <br />
        <span className="font-bold">Expected: </span>
        {expected.toString()}
        {}
      </Danger>;
  };
  const checkValidDimensionValue = value => {
    switch (typeof value) {
      case "string":
      case "number":
        const num = Number(value);
        return Number.isSafeInteger(num) && num >= minPx && num <= maxPx;
      default:
        return false;
    }
  };
  let callouts = [];
  if (height && !checkValidDimensionValue(height)) {
    callouts.push(createInvalidPropCallout("height", height, expectedPx));
  }
  if (width && !checkValidDimensionValue(width)) {
    callouts.push(createInvalidPropCallout("width", width, expectedPx));
  }
  if (callouts.length !== 0) {
    return callouts;
  }
  const heightPx = Number(height);
  const widthPx = Number(width);
  const shouldCenter = center === "true" || center === true ? true : false;
  const shouldNotZoom = noZoom === "true" || noZoom === true ? true : false;
  const images = <>
      <img className="block dark:hidden" src={src} alt={alt} {...height && ({
    height: heightPx
  })} {...width && ({
    width: widthPx
  })} {...(shouldCreateLink || shouldInvert || shouldNotZoom) && ({
    noZoom: "true"
  })} />
      <img className={`hidden dark:block ${shouldInvert ? "invert" : ""}`} src={darkSrc ?? src} alt={darkAlt ?? alt} {...height && ({
    height: heightPx
  })} {...width && ({
    width: widthPx
  })} {...(shouldCreateLink || shouldInvert || shouldNotZoom) && ({
    noZoom: "true"
  })} />
    </>;
  if (shouldCreateLink) {
    if (shouldCenter) {
      return <div style={{
        display: "flex",
        justifyContent: "center"
      }}>
          <a href={href} target={target ?? "_self"}>
            {images}
          </a>
        </div>;
    }
    return <a href={href} target={target ?? "_self"}>
        {images}
      </a>;
  }
  if (shouldCenter) {
    return <div style={{
      display: "flex",
      justifyContent: "center"
    }}>{images}</div>;
  }
  return images;
};

export const Aside = ({type = "note", title = "", icon = "", iconType = "regular", children}) => {
  const asideVariants = ["note", "tip", "caution", "danger"];
  const asideComponents = {
    note: {
      outerStyle: "border-sky-500/20 bg-sky-50/50 dark:border-sky-500/30 dark:bg-sky-500/10",
      innerStyle: "text-sky-900 dark:text-sky-200",
      calloutType: "note",
      icon: <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-sky-500" aria-label="Note">
          <path fill-rule="evenodd" clip-rule="evenodd" d="M7 1.3C10.14 1.3 12.7 3.86 12.7 7C12.7 10.14 10.14 12.7 7 12.7C5.48908 12.6974 4.0408 12.096 2.97241 11.0276C1.90403 9.9592 1.30264 8.51092 1.3 7C1.3 3.86 3.86 1.3 7 1.3ZM7 0C3.14 0 0 3.14 0 7C0 10.86 3.14 14 7 14C10.86 14 14 10.86 14 7C14 3.14 10.86 0 7 0ZM8 3H6V8H8V3ZM8 9H6V11H8V9Z"></path>
        </svg>
    },
    tip: {
      outerStyle: "border-emerald-500/20 bg-emerald-50/50 dark:border-emerald-500/30 dark:bg-emerald-500/10",
      innerStyle: "text-emerald-900 dark:text-emerald-200",
      calloutType: "tip",
      icon: <svg width="11" height="14" viewBox="0 0 11 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="text-emerald-600 dark:text-emerald-400/80 w-3.5 h-auto" aria-label="Tip">
          <path d="M3.12794 12.4232C3.12794 12.5954 3.1776 12.7634 3.27244 12.907L3.74114 13.6095C3.88471 13.8248 4.21067 14 4.46964 14H6.15606C6.41415 14 6.74017 13.825 6.88373 13.6095L7.3508 12.9073C7.43114 12.7859 7.49705 12.569 7.49705 12.4232L7.50055 11.3513H3.12521L3.12794 12.4232ZM5.31288 0C2.52414 0.00875889 0.5 2.26889 0.5 4.78826C0.5 6.00188 0.949566 7.10829 1.69119 7.95492C2.14321 8.47011 2.84901 9.54727 3.11919 10.4557C3.12005 10.4625 3.12175 10.4698 3.12261 10.4771H7.50342C7.50427 10.4698 7.50598 10.463 7.50684 10.4557C7.77688 9.54727 8.48281 8.47011 8.93484 7.95492C9.67728 7.13181 10.1258 6.02703 10.1258 4.78826C10.1258 2.15486 7.9709 0.000106649 5.31288 0ZM7.94902 7.11267C7.52078 7.60079 6.99082 8.37878 6.6077 9.18794H4.02051C3.63739 8.37878 3.10743 7.60079 2.67947 7.11294C2.11997 6.47551 1.8126 5.63599 1.8126 4.78826C1.8126 3.09829 3.12794 1.31944 5.28827 1.3126C7.2435 1.3126 8.81315 2.88226 8.81315 4.78826C8.81315 5.63599 8.50688 6.47551 7.94902 7.11267ZM4.87534 2.18767C3.66939 2.18767 2.68767 3.16939 2.68767 4.37534C2.68767 4.61719 2.88336 4.81288 3.12521 4.81288C3.36705 4.81288 3.56274 4.61599 3.56274 4.37534C3.56274 3.6515 4.1515 3.06274 4.87534 3.06274C5.11719 3.06274 5.31288 2.86727 5.31288 2.62548C5.31288 2.38369 5.11599 2.18767 4.87534 2.18767Z"></path>
        </svg>
    },
    caution: {
      outerStyle: "border-amber-500/20 bg-amber-50/50 dark:border-amber-500/30 dark:bg-amber-500/10",
      innerStyle: "text-amber-900 dark:text-amber-200",
      calloutType: "warning",
      icon: <svg className="flex-none w-5 h-5 text-amber-400 dark:text-amber-300/80" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-label="Warning">
          <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
        </svg>
    },
    danger: {
      outerStyle: "border-red-500/20 bg-red-50/50 dark:border-red-500/30 dark:bg-red-500/10",
      innerStyle: "text-red-900 dark:text-red-200",
      calloutType: "danger",
      icon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" className="text-red-600 dark:text-red-400/80 w-4 h-4" aria-label="Danger">
          <path d="M17.1 292c-12.9-22.3-12.9-49.7 0-72L105.4 67.1c12.9-22.3 36.6-36 62.4-36l176.6 0c25.7 0 49.5 13.7 62.4 36L494.9 220c12.9 22.3 12.9 49.7 0 72L406.6 444.9c-12.9 22.3-36.6 36-62.4 36l-176.6 0c-25.7 0-49.5-13.7-62.4-36L17.1 292zm41.6-48c-4.3 7.4-4.3 16.6 0 24l88.3 152.9c4.3 7.4 12.2 12 20.8 12l176.6 0c8.6 0 16.5-4.6 20.8-12L453.4 268c4.3-7.4 4.3-16.6 0-24L365.1 91.1c-4.3-7.4-12.2-12-20.8-12l-176.6 0c-8.6 0-16.5 4.6-20.8 12L58.6 244zM256 128c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"></path>
        </svg>
    }
  };
  let variant = type;
  let gotInvalidVariant = false;
  if (!asideVariants.includes(type)) {
    gotInvalidVariant = true;
    variant = "danger";
  }
  const iconVariants = ["regular", "solid", "light", "thin", "sharp-solid", "duotone", "brands"];
  if (!iconVariants.includes(iconType)) {
    iconType = "regular";
  }
  return <>
      <div className={`callout my-4 px-5 py-4 overflow-hidden rounded-2xl flex gap-3 border ${asideComponents[variant].outerStyle}`} data-callout-type={asideComponents[variant].calloutType}>
        <div className="mt-0.5 w-4" data-component-part="callout-icon">
          {}
          {icon === "" ? asideComponents[variant].icon : <Icon icon={icon} iconType={iconType} size={14} />}
        </div>
        <div className={`text-sm prose min-w-0 w-full ${asideComponents[variant].innerStyle}`} data-component-part="callout-content">
          {gotInvalidVariant ? <p>
              <span className="font-bold">
                Invalid <code>type</code> passed!
              </span>
              <br />
              <span className="font-bold">Received: </span>
              {type}
              <br />
              <span className="font-bold">Expected one of: </span>
              {asideVariants.join(", ")}
            </p> : <>
              {title && <p className="font-bold">{title}</p>}
              {children}
            </>}
        </div>
      </div>
    </>;
};

This article provides overview of wallet V5 public interfaces, how to interact with them and serialize used data structures.

<Aside>
  Note, that many of the things we implement in this article are for education purposes and they might need to be refined before production use.

  Moreover, all these V5 wallet contract interfaces are implemented in [`@ton/ton`](https://github.com/ton-org/ton) client library as WalletV5 contract wrapper class.
</Aside>

There are several ways how you can interact with deployed V5 wallet smart contract:

* Send external signed message
* Send internal signed message
* Send internal message from extension

Let's first explore message structure, that is used to perform different actions on wallet contract.

## TL-B

This is TL-B for V5 wallet actions, it includes some [complex TL-B patterns](/languages/tl-b/complex-and-non-trivial-examples.mdx). You can also find it on [GitHub](https://github.com/ton-blockchain/wallet-contract-v5/blob/321186127e8cc5e395ad3b2f1870839237c56f5f/types.tlb), in the wallet repo.

```tlb expandable theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
// Contract state
contract_state$_
  is_signature_allowed: (## 1)
  seqno:                #
  wallet_id:            #
  public_key:           (## 256)
  extensions_dict:      (HashmapE 256 int1)
= ContractState;

// Extended actions in W5:
add_extension#02 addr:MsgAddressInt = W5ExtendedAction;
delete_extension#03 addr:MsgAddressInt = W5ExtendedAction;
set_signature_auth_allowed#04 allowed:Bool = W5ExtendedAction;

// note: `m = extended actions count - 1`, so the last ref is not empty cell
extended_list_last$_ action:W5ExtendedAction = W5ExtendedActionList 0;
extended_list_action$_ {n:#} action:W5ExtendedAction prev:^(W5ExtendedActionList n) = W5ExtendedActionList (n + 1);

// `OutList m` is standard actions from block.tlb:
w5_actions_request$_ {m:#} {n:#} out_actions:(Maybe ^(OutList m)) extended_actions:(Maybe (W5ExtendedActionList n)) = W5InnerRequest m n;

w5_signed_request$_ {m:#} {n:#}
  wallet_id:    #
  valid_until:  #
  msg_seqno:    #
  inner:        (W5InnerRequest m n)
  signature:    bits512
= W5SignedRequest m n;

// actions_count = m, extended_actions_count - 1 = n
w5_internal_signed_request#73696e74 {m:#} {n:#} request:(W5SignedRequest m n) = W5MsgBody m n;
w5_external_signed_request#7369676e {m:#} {n:#} request:(W5SignedRequest m n) = W5MsgBody m n;

w5_extension_action_request#6578746e {m:#} {n:#} query_id:uint64 request:(W5InnerRequest m n) = W5MsgBody m n;

// opcode detection, actual InternalMsgBody / ExternalMsgBody is in W5MsgBody
w5_internal_signed_request#73696e74 rest:Any = InternalMsgBody;
w5_external_signed_request#7369676e rest:Any = InternalMsgBody;
w5_extension_action_request#6578746e rest:Any = InternalMsgBody;
```

Three types of messages that were described above can be seen here:

```tlb theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
w5_internal_signed_request#73696e74 {m:#} {n:#} request:(W5SignedRequest m n) = W5MsgBody m n;
w5_external_signed_request#7369676e {m:#} {n:#} request:(W5SignedRequest m n) = W5MsgBody m n;
w5_extension_action_request#6578746e {m:#} {n:#} query_id:uint64 request:(W5InnerRequest m n) = W5MsgBody m n;
```

Each of them includes the same `W5InnerRequest` field that dictates whats need to be done by wallet contract. In case of signed messages, the request needs to be verified, so `W5InnerRequest` is wrapped in `W5SignedRequest` structure, which contains necessary information for this.

Let's break down these data structures.

## Message structure

Message structure for V5 wallet contract is quite cumbersome and hard to read, it's made for optimal (de-)serialization and not optimized for understanding. It is described in [TL-B](/languages/tl-b/overview) languages and includes snake-cell pattern. We will try to get a grip of it by breaking down core data structures and how they are used.

You can skip to [Examples section](#examples), where we would use existing high-level libraries that abstract low level logic from the user.

## Inner Request

Inner request is defined as follows:

```tlb theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
w5_actions_request$_ {m:#} {n:#}
  out_actions:(Maybe ^(OutList m))
  extended_actions:(Maybe (W5ExtendedActionList n))
= W5InnerRequest m n;
```

V5 wallet supports two main types of actions that can be performed:

```mermaid theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
graph TD
    A[Root Actions] --> B[Send Message Action]
    A --> C[Extended Actions]
    C --> D[Add Extension]
    C --> E[Delete Extension]
    C --> F[Set Signature Auth]
```

The action structure allows for:

* **Send Message Actions**: Standard message sending with specified mode
* **Extended Actions**: Advanced wallet management operations
  * **Add Extension**: Register new extension addresses
  * **Delete Extension**: Remove extension addresses
  * **Set Signature Auth**: Enable/disable signature-based authentication

As you can see in TL-B, `out_actions` are snake-cell list of ordinary out messages, followed then by binary flag `has_other_actions` and `other_actions` extended action list.

#### Inner Request Structure

The Inner Request serialization follows this structure:

```mermaid theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
graph TD
    A[Inner Request] --> B[out_actions: Maybe OutList]
    A --> C[has_other_actions: 1 bit]

    B --> B1{Has out actions?}
    B1 -->|Yes| B2[OutList Chain]
    B1 -->|No| B3[Empty/Nothing]

    B2 --> B4[Mode: 8 bits]
    B2 --> B5[Message Reference]
    B2 --> B6[Previous OutList Reference]

    C --> C1{Bit = 1?}
    C1 -->|Yes| D[other_actions: ActionList]
    C1 -->|No| D1[No extended actions]

    D --> D2[Extended Action]
    D --> D3[Previous ActionList Reference]

    D2 --> D4[Add Extension #02]
    D2 --> D5[Delete Extension #03]
    D2 --> D6[Set Signature Auth #04]

    style A fill:#e1f5fe
    style B2 fill:#f3e5f5
    style D fill:#e8f5e8
```

#### Serialization Layout

The Inner Request is serialized in the following order:

```mermaid theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
graph LR
    subgraph "Cell Data"
        A[out_actions flag] --> B[has_other_actions: 1 bit]
    end

    subgraph "References"
        C[Ref 0: OutList Chain]
        D[Ref 1: ActionList Chain]
    end

    A -.-> C
    B -.-> D

    subgraph "OutList Structure"
        E[Mode: 8 bits] --> F[Message Ref] --> G[Prev OutList Ref]
    end

    subgraph "ActionList Structure"
        H[Action Type: 8 bits] --> I[Action Data] --> J[Prev ActionList Ref]
    end

    C --> E
    D --> H
```

## Signed Request

Signed message is a message that was signed using owners private key from his dedicated keypair, method from asymmetric cryptography. Later this message will be verified on-chain using public key stored in wallet smart contract - [read more](/standard/wallets/how-it-works#how-ownership-verification-works) about how ownership verification works.

Before V5 standard, there was only one way to deliver signed message to wallet contract - via external-in message. However, external messages has certain limitations, e.g. you can only send external-out messages from the smart contracts themselves. This means that it wasn't possible to deliver signed message from inside the blockchain, from another smart contract. V5 standard adds this functionality, partially enabling [gasless transaction](/standard/wallets/v5#preparing-for-gasless-transactions).

Besides `W5InnerRequest` field that contains actual actions that will be performed, `W5SignedRequest` structure contains usual wallet message fields that were in-place in previous versions, read more about them [here](/standard/wallets/how-it-works).

## Examples

Here we will take a look at code examples in Typescript using low level serialization library *@ton/core*.

### How to create Inner Request

As per message structure section above, `Inner Request` consists of 2 kinds of actions, basic *send message* actions and *extended actions* that affect contract behavior.

Let's write code that handles packing for extended actions:

```ts expandable theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
import {
    Address,
    beginCell,
    Builder,
    Cell
} from '@ton/core';

// declare actions as tagged union
export type OutActionAddExtension = {
    type: 'addExtension';
    address: Address;
}

export type OutActionRemoveExtension = {
    type: 'removeExtension';
    address: Address;
}

export type OutActionSetIsPublicKeyEnabled = {
    type: 'setIsPublicKeyEnabled';
    isEnabled: boolean;
}

export type OutActionExtended = OutActionSetIsPublicKeyEnabled | OutActionAddExtension | OutActionRemoveExtension;

// store each action content as described in its TL-B specification:
// 8 bits for action tag and then useful payload

const outActionAddExtensionTag = 0x02;
function storeOutActionAddExtension(action: OutActionAddExtension) {
    return (builder: Builder) => {
        builder.storeUint(outActionAddExtensionTag, 8).storeAddress(action.address)
    }
}

const outActionRemoveExtensionTag = 0x03;
function storeOutActionRemoveExtension(action: OutActionRemoveExtension) {
    return (builder: Builder) => {
        builder.storeUint(outActionRemoveExtensionTag, 8).storeAddress(action.address)
    }
}

const outActionSetIsPublicKeyEnabledTag = 0x04;
function storeOutActionSetIsPublicKeyEnabled(action: OutActionSetIsPublicKeyEnabled) {
    return (builder: Builder) => {
        builder.storeUint(outActionSetIsPublicKeyEnabledTag, 8).storeUint(action.isEnabled ? 1 : 0, 1)
    }
}

// entry point for storing any extended action
export function storeOutActionExtendedV5R1(action: OutActionExtended) {
    switch (action.type) {
        case 'setIsPublicKeyEnabled':
            return storeOutActionSetIsPublicKeyEnabled(action);
        case 'addExtension':
            return storeOutActionAddExtension(action);
        case 'removeExtension':
            return storeOutActionRemoveExtension(action);
        default:
            throw new Error('Unknown action type' + (action as OutActionExtended)?.type);
    }
}

// and now the hard part - list snake-cell serialization;
// we will use this function recursively, to store actions as reference cells one by one
function packExtendedActionsRec(extendedActions: OutActionExtended[]): Cell {
    const [first, ...rest] = extendedActions;

    let builder = beginCell()
        .store(storeOutActionExtendedV5R1(first));

    if (rest.length > 0) {
        // if there are more actions, store them recursively
        builder = builder.storeRef(packExtendedActionsRec(rest));
    }

    return builder.endCell();
}
```

Now we have to deal with basic action serialization. However, since these are the messages that are described in [`block.tlb`](/languages/tl-b/overview), we can use contract-agnostic code from serialization library to store them.

Here is a code snippet for storing V5 wallet actions as per `Inner Request` TL-B:

```ts expandable theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
import {
    beginCell,
    Builder, Cell,
    loadOutList,
    OutActionSendMsg, SendMode,
    Slice,
    storeOutList
} from '@ton/core';

// helper functions
export function isOutActionExtended(action: OutActionSendMsg | OutActionExtended): action is OutActionExtended {
    return (
        action.type === 'setIsPublicKeyEnabled' || action.type === 'addExtension' || action.type === 'removeExtension'
    );
}

export function isOutActionBasic(action: OutActionSendMsg | OutActionExtended): action is OutActionSendMsg {
    return !isOutActionExtended(action);

}

// main entrypoint for storing any actions list
export function storeOutListExtendedV5(actions: (OutActionExtended | OutActionSendMsg)[]) {
    const extendedActions = actions.filter(isOutActionExtended);
    const basicActions = actions.filter(isOutActionBasic);

    return (builder: Builder) => {
        // here we use "storeOutList", serialization function from @ton/core
        const outListPacked = basicActions.length ? beginCell().store(storeOutList(basicActions.slice())) : null;
        builder.storeMaybeRef(outListPacked);

        if (extendedActions.length === 0) {
           // has_more_actions flag to false
            builder.storeUint(0, 1);
        } else {
            const [first, ...rest] = extendedActions;

            builder
            // has_more_actions flag to true
                .storeUint(1, 1)
            // here we use our store function from previous code section
                .store(storeOutActionExtendedV5(first));
            // if there are more actions - store them one by one
            if (rest.length > 0) {
                builder.storeRef(packExtendedActionsRec(rest));
            }
        }
    }
}
```

With this, we can serialize and store list of actions, in next section we will learn how to use them to send signed message.

### How to create and send Signed Request

There are several additional arguments that we need to create signed message besides the list of actions from previous section:

* `walletId`
* `seqno`
* `privateKey`
* `validUntil`

You can read more about where to obtain them and what there purpose is in [How it works](/standard/wallets/how-it-works) section.

In this code snippet we will learn how to create signed serialized message.

```ts expandable theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
import { sign } from "@ton/crypto";

export type WalletV5BasicSendArgs = {
    seqno: number;
    validUntil: number;
    privateKey: Buffer;
}

// w5_internal_signed_request#73696e74 {m:#} {n:#} request:(W5SignedRequest m n) = W5MsgBody m n;
// w5_external_signed_request#7369676e {m:#} {n:#} request:(W5SignedRequest m n) = W5MsgBody m n;
export type WalletV5SendArgsSinged = WalletV5BasicSendArgs
    & { authType?: 'external' | 'internal';};

// w5_extension_action_request#6578746e {m:#} {n:#} query_id:uint64 request:(W5InnerRequest m n) = W5MsgBody m n;
export type Wallet5VSendArgsExtensionAuth = WalletV5BasicSendArgs & {
    authType: 'extension';
    queryId?: bigint;
}

export type WalletV5SendArgs =
    | WalletV5SendArgsSinged
    | Wallet5VSendArgsExtensionAuth;

const OpCodes = {
    authExtension: 0x6578746e,
    authSignedExternal: 0x7369676e,
    authSignedInternal: 0x73696e74
}

export function createWalletTransferV5R1<T extends WalletV5SendArgs>(
    args: T extends Wallet5VSendArgsExtensionAuth
    // action types are from Inner Request section
        ? T & { actions: (OutActionSendMsg | OutActionExtended)[]}
        : T & { actions: (OutActionSendMsg | OutActionExtended)[], walletId: (builder: Builder) => void }
): Cell {
    // Check number of actions
    if (args.actions.length > 255) {
        throw Error("Maximum number of OutActions in a single request is 255");
    }

    // store each message type according to its TL-B

    if (args.authType === 'extension') {
        return beginCell()
            .storeUint(OpCodes.authExtension, 32)
            .storeUint(args.queryId ?? 0, 64)
            // use storeOutListExtendedV5
            .store(storeOutListExtendedV5(args.actions))
            .endCell();
    }

    const signingMessage = beginCell()
        .storeUint(args.authType === 'internal'
            ? OpCodes.authSignedInternal
            : OpCodes.authSignedExternal, 32)
        .store(args.walletId);


    // now we store common part for both messages
    signingMessage.storeUint(args.timeout || Math.floor(Date.now() / 1e3) + 60, 32); // Default timeout: 60 seconds

    signingMessage
        .storeUint(args.seqno, 32)
        .store(storeOutListExtendedV5(args.actions));

    // now we need to sign message
    const signature = sign(signingMessage.endCell().hash(), args.secretKey);

    return beginCell().storeBuilder(signingMessage).storeBuffer(signature).endCell();
}
```

Now what is left is sending the message. The way we send created message is dependent on the message type.

#### Sending external\_signed message

After obtaining signed message cell we need to serialize it as external message and send it to the blockchain.

```ts theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
import {
    Address,
    beginCell,
    Cell,
    external,
    storeMessage
} from '@ton/core';

// with authType = 'external'
const msgCell = createWalletTransferV5(...);

const v5WalletAddress = Address.parse("EQ....");

const serializedExternal = external({
  to: v5WalletAddress,
  body: msgCell
});

// BoC: bag of cells
const boc = beginCell()
  .store(storeMessage(serializedExternal))
  .endCell()
  .toBoc();
```

You can send this BoC to the network in any convenient way, e.g. with API provider like [TonCenter /message](https://toncenter.com/api/v3/index.html#/api%2Fv2/api_v3_post_v2_message) or with your own [liteserver](/ecosystem/nodes/overview).

#### Sending internal\_extension and internal\_signed

These two types of messages are internal messages, meaning that they need to come from another contract. However strange that may sound, the easiest way to send internal message from another contract is to ask another wallet contract to send internal message to our wallet contract with body that will contain our constructed message.

<Image src="/resources/images/wallets/internal_message_light.svg" darkSrc="/resources/images/wallets/internal_message_dark.svg" alt="Internal message flow" />

For simplicity, we will use wallet V4 contract with existing client serialization library that will take care of all low level stuff.

```ts expandable theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
import {beginCell, toNano, TonClient, WalletContractV4, internal, fromNano} from "@ton/ton"
import {getHttpEndpoint} from "@orbs-network/ton-access"
import {mnemonicToPrivateKey} from "@ton/crypto"

// v4 wallet mnemonic
const mnemonics = "dog bacon bread ..."

const endpoint = await getHttpEndpoint({network: 'testnet'})
const client = new TonClient({
    endpoint: endpoint,
})
const keyPair = await mnemonicToPrivateKey(mnemonics.split(" "))
const secretKey = keyPair.secretKey
const workchain = 0 // we are working in basechain.
const deployerWallet = WalletContractV4.create({
    workchain: workchain,
    publicKey: keyPair.publicKey,
})

const deployerWalletContract = client.open(deployerWallet)


// with authType = 'internal' or 'extension'
const internalMsgBody = createWalletTransferV5(...);

// here we use function from previous section to create V5 wallet message cell
// next, we will send it as internal message using V4 wallet

// address of our V5 wallet contract
const v5WalletAddress = Address.parse("EQ....");

const seqnoForV4Wallet: number = await deployerWalletContract.getSeqno()

await deployerWalletContract.sendTransfer({
    seqno,
    secretKey,
    messages: [
        internal({
            to: v5WalletAddress,
            value: toNano("0.05"),
            body: internalMsgBody,
        }),
    ],
})
```
