You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: website/docs/guides/covenants.md
+23-4Lines changed: 23 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -143,7 +143,11 @@ Smart contracts which persist for multiple transactions might want to keep data
143
143
Covenants can also use 'simulated state', where state is kept in the contract script and the contract enforces a new P2SH locking bytecode of the contract with a different state update. This method causes the contract address to change with each state update.
144
144
:::
145
145
146
-
### Keeping local State in NFTs
146
+
### Keeping local state in NFTs
147
+
148
+
When we want to share local state between multiple transactions or contracts, we can use the NFT commitment field in an NFT. This state is accessible in any transaction that includes the NFT.
149
+
150
+
#### Example: Streaming Mecenas
147
151
148
152
To demonstrate the concept of 'local state' we consider the Mecenas contract again, and focus on a drawback of this contract: you have to claim the funds at exactly the right moment or you're leaving money on the table. Every time you claim money from the contract, the `this.age` counter is reset, so the next claim is possible 30 days after the previous claim. So if we wait a few days to claim, **these days are basically wasted**.
@@ -212,6 +216,21 @@ Instead of having a pledge per 30 day period, we define a pledge per block. At a
212
216
We use `tx.locktime` to introspect the value of the timelock, and to write the value to the contract local state: the NFT commitment field.
213
217
:::
214
218
219
+
#### Integer padding for local state
220
+
221
+
Padding an integer to a fixed-size byte-length is a very important when storing local state in an nftCommitment. We can use the `toPaddedBytes(int, length)` function to pad the integer to the desired length. When casting a script number to bytes, developers need to consider what the preferable fixed-size length is for each individual case depending on the integer range. Below we add a table with info on the maximum integer size for common cases:
222
+
223
+
| Integer Type | Max integer value | Max Byte Size in Script Number Format |
VM numbers follow Script Number format (A.K.A. CSCriptNum), to convert VM number to bytes or the reverse, it's recommended to use helper functions for these conversions from libraries like Libauth.
232
+
:::
233
+
215
234
### Issuing NFTs as receipts
216
235
217
236
A covenant that manages funds (BCH + fungible tokens of a certain category) which are pooled together from different people often wants to enable its participants to also exit the covenants with their funds. It would be incredibly hard continuously updating a data structure to keep track of which address contributed how much in the local state of the contract. A much better solution is to issue receipts each time funds are added to the pool! This way the contract does not have a 'global view' of who owns what at any time, but it can validate the receipts when invoking a withdrawal.
@@ -251,12 +270,12 @@ contract PooledFunds(
251
270
if (amountTokensAdded > 0) {
252
271
// Require 1000 sats to pay for future withdrawal fee
Checks that sig `s` is a valid signature for message `msg` and matches with public key `pk`.
115
115
116
+
## Other functions
117
+
118
+
### toPaddedBytes()
119
+
```solidity
120
+
bytes toPaddedBytes(int value, int length)
121
+
```
122
+
123
+
Pads the integer `value` with zeros to the specified `length`. This is most useful when storing integer values in local state (see [local state guide][local-state-guide]).
124
+
125
+
:::tip
126
+
Using `bytes20 placeholderPkh = toPaddedBytes(0, 20)` will generate a 20 byte zero-array at runtime, whereas
127
+
`bytes20 placeholderPkh = 0x0000000000000000000000000000000000000000` will actually take 20 bytes of space in your contract.
Copy file name to clipboardExpand all lines: website/docs/language/types.md
+22-28Lines changed: 22 additions & 28 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -70,7 +70,7 @@ Members:
70
70
-`reverse()`: Reverses the string.
71
71
72
72
:::caution
73
-
The script will fail if `split()`or `slice()` is called with an index that is out of bounds.
73
+
The script will fail if `split()`or `slice()` is called with an index that is out of bounds.
74
74
:::
75
75
76
76
## Bytes
@@ -167,7 +167,7 @@ Type casting can be done both explicitly and implicitly depending on the type. `
167
167
```solidity
168
168
pubkey pk = pubkey(0x0000);
169
169
bytes editedPk = bytes(pk) + 0x1234;
170
-
bytes4 zeroBytes = bytes4(0); // 0x00000000
170
+
bool b = bool(5); // true
171
171
```
172
172
173
173
### Casting Table
@@ -179,45 +179,39 @@ See the following table for information on which types can be cast to other whic
179
179
| int || bytes, bool |
180
180
| bool || int |
181
181
| string || bytes |
182
-
| bytes || sig, pubkey, int|
182
+
| bytes || sig, datasig, pubkey, int |
183
183
| pubkey | bytes | bytes |
184
184
| sig | bytes | bytes |
185
185
| datasig | bytes | bytes |
186
186
187
-
### Int to Byte Casting
188
-
189
-
When casting integer types to bytes of a certain size, the integer value is padded with zeros, e.g. `bytes4(0) == 0x00000000`. It is also possible to pad with a variable number of zeros by passing in a `size` parameter, which indicates the size of the output, e.g. `bytes(0, 4 - 2) == 0x0000`.
190
-
191
-
:::tip
192
-
Using `bytes20 placeholderPkh= bytes20(0)` will generate a 20 byte zero-array programmatically, whereas
193
-
`bytes20 placeholderPkh= 0x0000000000000000000000000000000000000000` will actually take 20 bytes of space in your contract.
194
-
:::
195
-
196
-
Casting an integer to a fixed-size byte-length can be a very important when storing local state in an nftCommitment. When casting a script number to bytes, developers need to consider what the preferable fixed-size length is for each individual case depending on the integer range. Below we add a table with info on the maximum integer size for common cases:
197
-
198
-
| Integer Type | Max integer value | Max Byte Size in Script Number Format |
VM numbers follow Script Number format (A.K.A. CSCriptNum), to convert VM number to bytes or the reverse, it's recommended to use helper functions for these conversions from libraries like Libauth.
207
-
:::
208
-
209
-
### Semantic Byte Casting
187
+
### Semantic Bytes Casting
210
188
211
-
When casting unbounded `bytes` types to bounded `bytes` types (such as `bytes20` or `bytes32`), this is a purely semantic cast. The bytes are not padded with zeros, and no checks are performed to ensure the cast bytes are of the correct length. This can be helpful in certain cases, such as `LockingBytecode`, which expects a specific length input.
189
+
When casting unbounded `bytes` types to bounded `bytes` types (such as `bytes20` or `bytes32`), this is a purely semantic cast. The bytes are not padded with zeros, and no checks are performed to ensure the cast bytes are of the correct length. This is why this cast is marked with the `unsafe_` prefix. This can be helpful in certain cases, such as `LockingBytecode`, which expects a specific length input.
bytes25 lockingBytecode = new LockingBytecodeP2PKH(bytes20Pkh);
219
197
```
220
198
199
+
### Other Semantic Casting
200
+
When casting a `bytes` to an `int` or when casting an `int` to a `bool`, opcodes are added to the script to perform a conversion between the two types. If you are an advanced user and want to perform these casts without the added opcodes, you can use the `unsafe_` prefix.
201
+
202
+
#### Example
203
+
```solidity
204
+
bytes bytesValue = 0x123456000000; // not a valid minimally encoded integer
An overview of all supported operators and their precedence is included below. Notable is a lack of exponentiation, since these operations are not supported by the underlying Bitcoin Script.
Copy file name to clipboardExpand all lines: website/docs/releases/migration-notes.md
+50Lines changed: 50 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,56 @@
2
2
title: Migration Notes
3
3
---
4
4
5
+
## v0.12 to v0.13
6
+
7
+
### cashc compiler
8
+
9
+
#### bounded bytes casting
10
+
11
+
To indicate that `bytes4(bytes)` casting is purely semantic (and does not offer any type safety), we have renamed it to `unsafe_bytes4(bytes)`. We have also disallowed `bytes4(int)` casting (see section *int to padded bytes casting*).
In the past, `bytes4(int)` or `bytes(int, 4)` would perform a `NUM2BIN` operation, padding the value to 4 bytes, while `bytes4(bytes)` was a purely semantic type cast. This caused confusion, so instead you can now use the `toPaddedBytes(int, length)` function to perform the same padding (`NUM2BIN`) operation.
29
+
30
+
```solidity
31
+
// before
32
+
bytes4(5); // => 0x05000000
33
+
bytes(5, 4); // => 0x05000000
34
+
35
+
// after
36
+
toPaddedBytes(5, 4); // => 0x05000000
37
+
```
38
+
39
+
#### bool casting
40
+
41
+
The `bool()` casting function now correctly changes the value of the argument to `true` for non-zero values and `false` for zero values, instead of only semantically treating the value as a boolean. This worked correctly when using the boolean directly inside `require` or `if` statements, but not when using it in a comparison.
0 commit comments