Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(stdlib): Slice.loadBasechainAddress() and Slice.skipBasechainAddress() #2395

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
54 changes: 54 additions & 0 deletions docs/src/content/docs/ref/core-cells.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,59 @@ s1.skipAddress();
let fizz: Int = s1.loadUint(32); // 42
```

### Slice.loadBasechainAddress

<Badge text="Available since Tact 1.6.4" variant="tip" size="medium"/><p/>

```tact
extends mutates fun loadBasechainAddress(self: Slice): BasechainAddress;
```

Extension mutation function for the [`Slice{:tact}`][slice] type.

Loads and returns a [`BasechainAddress{:tact}`][base-addr] [struct][struct] from the [`Slice{:tact}`][slice].

Attempts to load such [`BasechainAddress{:tact}`][base-addr] struct when [`Slice{:tact}`][slice] doesn't contain it throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.

Attempts to load more data than [`Slice{:tact}`][slice] contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.
Comment on lines +1209 to +1211
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when a slice that is not a valid basechain addess is passed?

Copy link
Member Author

@novusnota novusnota Mar 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exit code 9.

Actually, I may have found a bunch of long-standing typos — the exit code 8 doesn't seem right for the .load functions.

Double-checking those now.

UPD: They're incorrect

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be documented


Usage example:

```tact
let s: Slice = beginCell()
.storeBasechainAddress(BasechainAddress{ hash: null })
.asSlice();
let fizz: BasechainAddress = s.loadBasechainAddress();
```

### Slice.skipBasechainAddress

<Badge text="Available since Tact 1.6.4" variant="tip" size="medium"/><p/>

```tact
extends mutates fun skipBasechainAddress(self: Slice);
```

Extension mutation function for the [`Slice{:tact}`][slice] type.

Skips a [`BasechainAddress{:tact}`][base-addr] [struct][struct] from the [`Slice{:tact}`][slice].

Attempts to skip such [`BasechainAddress{:tact}`][base-addr] struct when [`Slice{:tact}`][slice] doesn't contain it throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`.

Attempts to skip more data than [`Slice{:tact}`][slice] contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.

Usage example:

```tact
let s1: Slice = beginCell()
.storeBasechainAddress(BasechainAddress{ hash: null })
.storeUint(42, 32)
.asSlice();

s1.skipBasechainAddress();
let fizz: Int = s1.loadUint(32); // 42
```

### Slice.loadRef

```tact
Expand Down Expand Up @@ -2015,6 +2068,7 @@ fun cautiousParse(payload: Slice): TripleAxe? {
[message]: /book/structs-and-messages#messages
[null]: /book/optionals

[base-addr]: /ref/core-addresses#basechainaddress
[std-repr]: /book/cells#cells-representation

[tlb]: https://docs.ton.org/develop/data-formats/tl-b-language
Expand Down
77 changes: 75 additions & 2 deletions src/stdlib/stdlib/std/internal/address.tact
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ asm( -> 1 0) extends mutates fun loadAddress(self: Slice): Address { LDMSGADDR }
/// }
/// ```
///
/// See: https://docs.tact-lang.org/ref/core-cells#sliceloadaddress
/// See: https://docs.tact-lang.org/ref/core-cells#sliceskipaddress
///
asm extends mutates fun skipAddress(self: Slice) { LDMSGADDR NIP }

Expand Down Expand Up @@ -307,12 +307,15 @@ inline fun contractBasechainAddress(s: StateInit): BasechainAddress {
///
/// ```tact
/// fun example() {
/// let addr: BasechainAddress = newBasechainAddress(0x83dfd552e63729b472fcbcc8c45ebcc6691702558b68ec7527e1ba403a0f31a8);
/// let addr: BasechainAddress =
/// newBasechainAddress(0x83dfd552e63729b472fcbcc8c45ebcc6691702558b68ec7527e1ba403a0f31a8);
/// let b: Builder = beginCell();
/// let b2: Builder = b.storeBasechainAddress(addr);
/// }
/// ```
///
/// See: https://docs.tact-lang.org/ref/core-cells#builder.storebasechainaddress
///
extends fun storeBasechainAddress(self: Builder, address: BasechainAddress): Builder {
if (address.hash == null) {
return self.storeUint(0, 2); // 0b00
Expand All @@ -323,6 +326,76 @@ extends fun storeBasechainAddress(self: Builder, address: BasechainAddress): Bui
.storeUint(address.hash!!, 256);
}

/// Extension mutation function for the `Slice` type. Available since Tact 1.6.4.
///
/// Loads and returns a `BasechainAddress` struct from the `Slice`.
///
/// Attempts to load such `BasechainAddress` struct when `Slice` doesn't contain it throw an exception with [exit code 8]: `Cell overflow`.
///
/// Attempts to load more data than `Slice` contains throw an exception with [exit code 9]: `Cell underflow`.
///
/// ```tact
/// fun example() {
/// let s: Slice = beginCell()
/// .storeBasechainAddress(BasechainAddress{ hash: null })
/// .asSlice();
/// let fizz: BasechainAddress = s.loadBasechainAddress();
/// }
/// ```
///
/// See:
/// * https://docs.tact-lang.org/ref/core-cells#sliceloadbasechainaddress
/// * https://docs.tact-lang.org/book/exit-codes
///
/// [exit code 8]: https://docs.tact-lang.org/book/exit-codes#8
/// [exit code 9]: https://docs.tact-lang.org/book/exit-codes#9
///
extends mutates fun loadBasechainAddress(self: Slice): BasechainAddress {
if (self.loadUint(2) == 0) {
return BasechainAddress{ hash: null };
} else {
// Skip the remaining prefix
self.skipBits(9);
// Load the hash (account ID)
return BasechainAddress{ hash: self.loadUint(256) };
}
}

/// Extension mutation function for the `Slice` type. Available since Tact 1.6.4.
///
/// Skips a `BasechainAddress` struct from the `Slice`.
///
/// Attempts to skip such `BasechainAddress` struct when `Slice` doesn't contain it throw an exception with [exit code 8]: `Cell overflow`.
///
/// Attempts to skip more data than `Slice` contains throw an exception with [exit code 9]: `Cell underflow`.
///
/// ```tact
/// fun example() {
/// let s1: Slice = beginCell()
/// .storeBasechainAddress(BasechainAddress{ hash: null })
/// .storeUint(42, 32)
/// .asSlice();
///
/// s1.skipBasechainAddress();
/// let fizz: Int = s1.loadUint(32); // 42
/// }
/// ```
///
/// See:
/// * https://docs.tact-lang.org/ref/core-cells#sliceskipbasechainaddress
/// * https://docs.tact-lang.org/book/exit-codes
///
/// [exit code 8]: https://docs.tact-lang.org/book/exit-codes#8
/// [exit code 9]: https://docs.tact-lang.org/book/exit-codes#9
///
extends mutates fun skipBasechainAddress(self: Slice) {
if (self.loadUint(2) != 0) {
// 9 bits of the remaining prefix since first 2 are loaded already
// plus 256 bits of the hash (account ID)
self.skipBits(265);
}
}

/// Global function. Available since Tact 1.6.3.
///
/// Checks whether the `address` is in the basechain, i.e., its chain ID is 0. If it is not, throws an exception with exit code 138: `Not a basechain address`.
Expand Down
Loading
Loading