codenlighten/scrypt
0
1---2sidebar_position: 43---4 5# Built-ins6 7## Global Functions8 9The following functions come with `sCrypt`.10 11### Assert12 13- `assert(condition: boolean, errorMsg?: string)` Throw an `Error` with the optional error message if `condition` is `false`. Otherwise, nothing happens.14 15```ts16assert(1n === 1n) // nothing happens17assert(1n === 2n) // throws Error('Execution failed')18assert(false, 'hello') // throws Error('Execution failed, hello')19```20 21### Fill22 23- `fill(value: T, length: number): T[length] ` Returns an `FixedArray` with all `size` elements set to `value`, where `value` can be any type. 24 25:::note26`length` must be a [compiled-time constant](./how-to-write-a-contract.md#compile-time-constant).27:::28 29 30```ts31// good32fill(1n, 3) // numeric literal 333fill(1n, M) // const M = 334fill(1n, Demo.N) // `N` is a static readonly property of class `Demo`35```36 37### Math38 39- `abs(a: bigint): bigint` Returns the absolute value of `a`.40 41```ts42abs(1n) // 1n43abs(0n) // 0n44abs(-1n) // 1n45```46 47- `min(a: bigint, b: bigint): bigint` Returns the smallest of `a` and `b`.48 49```ts50min(1n, 2n) // 1n51```52 53- `max(a: bigint, b: bigint): bigint` Returns the lagest of `a` and `b`.54 55```ts56max(1n, 2n) // 2n57```58 59- `within(x: bigint, min: bigint, max: bigint): boolean` Returns `true` if `x` is within the specified range (left-inclusive and right-exclusive), `false` otherwise.60 61```ts62within(0n, 0n, 2n) // true63within(1n, 0n, 2n) // true64within(2n, 0n, 2n) // false65```66 67### Hashing68 69- `ripemd160(a: ByteString): Ripemd160` Returns the [RIPEMD160](https://en.wikipedia.org/wiki/RIPEMD) hash result of `a`.70- `sha1(a: ByteString): Sha1` Returns the [SHA1](https://en.wikipedia.org/wiki/SHA-1) hash result of `a`.71- `sha256(a: ByteString): Sha256` Returns the [SHA256](https://www.movable-type.co.uk/scripts/sha256.html) hash result of `a`.72- `hash160(a: ByteString): Ripemd160` Actually returns `ripemd160(sha256(a))`73- `hash256(a: ByteString): Sha256` Actually returns `sha256(sha256(a))`74 75### ByteString Operations76 77- `int2ByteString(n: bigint, size?: bigint): ByteString` If `size` is omitted, convert `n` is converted to a `ByteString` in [sign-magnitude](https://en.wikipedia.org/wiki/Signed_number_representations#Sign%E2%80%93magnitude) little endian format, with as few bytes as possible (a.k.a., minimally encoded). Otherwise, converts the number `n` to a `ByteString` of the specified size, including the sign bit; fails if the number cannot be accommodated.78 79```ts80// as few bytes as possible81int2ByteString(128n) // '8000', little endian82int2ByteString(127n) // '7f'83int2ByteString(0n) // ''84int2ByteString(-1n) // '81'85int2ByteString(-129n) // '8180', little endian86 87// specified size88int2ByteString(1n, 3n) // '010000', 3 bytes89int2ByteString(-129n, 3n) // '810080', 3 bytes90 91// Error: -129 cannot fit in 1 byte92int2ByteString(-129n, 1n)93```94 95- `byteString2Int(a: ByteString): bigint` Convert ByteString in sign-magnitude little endian format to bigint.96 97```ts98byteString2Int(toByteString('8000')) // 128n99byteString2Int(toByteString('')) // 0n100byteString2Int(toByteString('00')) // 0n101byteString2Int(toByteString('81')) // -1n102 103byteString2Int(toByteString('010000')) // 1n104byteString2Int(toByteString('810080')) // -129n105```106 107- `len(a: ByteString): number` Returns the byte length of `a`. 108 109```ts110const s1 = toByteString('0011', false) // '0011', 2 bytes111len(s1) // 2112 113const s2 = toByteString('hello', true) // '68656c6c6f', 5 bytes114len(s2) // 5115```116 117- `reverseByteString(b: ByteString, size: number): ByteString` Returns reversed bytes of `b` which is of `size` bytes. It is often useful when converting a number between little-endian and big-endian.118 119:::note120`size` must be a [compiled-time constant](./how-to-write-a-contract.md#compile-time-constant).121:::122 123```ts124const s1 = toByteString('793ff39de7e1dce2d853e24256099d25fa1b1598ee24069f24511d7a2deafe6c') 125reverseByteString(s1, 32) // 6cfeea2d7a1d51249f0624ee98151bfa259d095642e253d8e2dce1e79df33f79126```127 128- `slice(byteString: ByteString, start: BigInt, end?: BigInt): ByteString` return a substring from `start` to, but not including, `end`. If `end` is not specified, the substring continues to the last byte.129 130```ts131const message = toByteString('001122')132slice(message, 1n) // '1122'133slice(message, 1n, 2n) // '11'134```135 136### Bitwise Operator137 138Bigint in the Bitcoin is stored in [sign–magnitude format](https://en.wikipedia.org/wiki/Signed_number_representations#Sign%E2%80%93magnitude), not [two's complement format](https://en.wikipedia.org/wiki/Signed_number_representations#Two's_complement) commonly used. If the operands are all nonnegative, the result of the operation is consistent with TypeScript's bitwise operator, except `~`. Otherwise, the operation results may be inconsistent and thus undefined. It is strongly recommended to **NEVER** apply bitwise operations on negative numbers.139 140- `and(x: bigint, y: bigint): bigint` Bitwise AND141 142```ts143and(13n, 5n) // 5n144and(0x0a32c845n, 0x149f72n) // 0x00108840n, 1083456n145```146 147- `or(x: bigint, y: bigint): bigint` Bitwise OR148 149```ts150or(13n, 5n) // 13n151or(0x0a32c845n, 0x149f72n) // 0xa36df77n, 171368311n152```153 154- `xor(x: bigint, y: bigint): bigint` Bitwise XOR155 156```ts157xor(13n, 5n) // 8n158xor(0x0a32c845n, 0x149f72n) // 0x0a265737n, 170284855n159```160 161- `invert(x: bigint): bigint` Bitwise NOT162 163```ts164invert(13n) // -114n165```166 167- `lshift(x: bigint, n: bigint): bigint` Arithmetic left shift, returns `x * 2^n`.168 169```ts170lshift(2n, 3n) // 16n171```172 173- `rshift(x: bigint, n: bigint): bigint` Arithmetic right shift, returns `x / 2^n`.174 175```ts176rshift(21n, 3n) // 2n177rshift(1024n, 11n) // 0n178```179 180### Exit181 182- `exit(status: boolean): void` Call this function will terminate contract execution. If `status` is `true` then the contract succeeds; otherwise, it fails.183 184## `SmartContract` Methods185 186The following `@methods` come with the `SmartContract` base class.187 188### `compile`189 190Function `static async compile(): Promise<TranspileError[]>` compiles the contract and returns transpile errors if compiling fails.191 192```ts193// returns transpile errors if compiling fails194const transpileErrors = await Demo.compile()195```196 197### `scriptSize`198 199Function `get scriptSize(): number` returns the byte length of the contract locking script.200 201```ts202const demo = new Demo()203const size = demo.scriptSize204```205 206### `loadArtifact`207 208Function `static loadArtifact(artifact: MergedArtifact)` loads the contract artifact file in order to rebuild a contract instance, it's usually called at the front end.209 210```ts211import { TicTacToe } from './contracts/tictactoe';212var artifact = require('../artifacts/src/contracts/tictactoe.json');213TicTacToe.loadArtifact(artifact);214```215 216You may visit [here](https://academy.scrypt.io/en/courses/Build-a-Tic-tac-toe-Game-with-sCrypt-614c387bc0974f55df5af1e5/lessons/2/chapters/1) for more details about how to add a front end to a contract.217 218### `checkSig`219 220Function `checkSig(signature: Sig, publicKey: PubKey): boolean` verifies an ECDSA signature. It takes two inputs: an ECDSA signature and a public key. 221 222It returns if the signature matches the public key.223 224:::caution225All signature checking functions (`checkSig` and `checkMultiSig`) follow the [**NULLFAIL** rule](https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki#NULLFAIL): if the signature is invalid, the entire contract aborts and fails immediately, unless the signature is an empty ByteString, in which case these functions return `false`.226:::227 228For example, Pay-to-Public-Key-Hash ([P2PKH](https://learnmeabitcoin.com/guide/p2pkh)) can be implemented as below.229 230```ts231class P2PKH extends SmartContract {232 // public key hash of the recipient.233 @prop()234 readonly pubKeyHash: PubKeyHash235 236 constructor(pubKeyHash: PubKeyHash) {237 super(...arguments)238 this.pubKeyHash = pubKeyHash239 }240 241 @method()242 public unlock(sig: Sig, pubkey: PubKey) {243 // check if the passed public key belongs to the specified public key hash244 assert(hash160(pubkey) == this.pubKeyHash, 'public key hashes are not equal')245 // check signature validity246 assert(this.checkSig(sig, pubkey), 'signature check failed')247 }248}249```250 251### `checkMultiSig`252 253Function `checkMultiSig(signatures: Sig[], publickeys: PubKey[]): boolean` verifies an array of ECDSA signatures. It takes two inputs: an array of ECDSA signatures and an array of public keys.254 255The function compares the first signature against each public key until it finds an ECDSA match. Starting with the subsequent public key, it compares the second signature against each remaining public key until it finds an ECDSA match. The process is repeated until all signatures have been checked or not enough public keys remain to produce a successful result. All signatures need to match a public key. Because public keys are not checked again if they fail any signature comparison, signatures must be placed in the `signatures` array using the same order as their corresponding public keys were placed in the `publickeys` array. If all signatures are valid, `true` is returned, `false` otherwise.256 257```ts258class MultiSigPayment extends SmartContract {259 // public key hashes of the 3 recipients260 @prop()261 readonly pubKeyHashes: FixedArray<PubKeyHash, 3>262 263 constructor(pubKeyHashes: FixedArray<PubKeyHash, 3>) {264 super(...arguments)265 this.pubKeyHashes = pubKeyHashes266 }267 268 @method()269 public unlock(270 signatures: FixedArray<Sig, 3>, 271 publicKeys: FixedArray<PubKey, 3>272 ) {273 // check if the passed public keys belong to the specified public key hashes274 for (let i = 0; i < 3; i++) {275 assert(hash160(publicKeys[i]) == this.pubKeyHashes[i], 'public key hash mismatch¸')276 }277 // validate signatures278 assert(this.checkMultiSig(signatures, publicKeys), 'checkMultiSig failed')279 }280}281```282 283### `buildStateOutput`284 285Function `buildStateOutput(amount: bigint): ByteString` creates an output containing the latest state. It takes an input: the number of satoshis in the output.286 287```ts288class Counter extends SmartContract {289 // ...290 291 @method(SigHash.ANYONECANPAY_SINGLE)292 public incOnChain() {293 // ... update state294 295 // construct the new state output 296 const output: ByteString = this.buildStateOutput(this.ctx.utxo.value)297 298 // ... verify outputs of current tx299 }300}301```302 303### `buildChangeOutput`304 305Function `buildChangeOutput(): ByteString` creates a P2PKH change output. It will calculate the change amount (`this.changeAmount`) automatically, and use the signer's address by default, unless `changeAddress` field is explicitly set in `MethodCallOptions`.306 307```ts308class Auction extends SmartContract {309 310 // ...311 312 @method()313 public bid(bidder: PubKeyHash, bid: bigint) {314 315 // ...316 317 // Auction continues with a higher bidder.318 const auctionOutput: ByteString = this.buildStateOutput(bid)319 320 // Refund previous highest bidder.321 const refundOutput: ByteString = Utils.buildPublicKeyHashOutput(322 highestBidder,323 highestBid324 )325 let outputs: ByteString = auctionOutput + refundOutput326 327 // Add change output.328 outputs += this.buildChangeOutput()329 330 assert(hash256(outputs) == this.ctx.hashOutputs, 'hashOutputs check failed')331 }332}333 334const { tx: callTx, atInputIndex } = await auction.methods.bid(335 PubKeyHash(toHex(publicKeyHashNewBidder)),336 BigInt(balance + 1),337 {338 fromUTXO: getDummyUTXO(balance),339 changeAddress: addressNewBidder, // specify the change address of method calling tx explicitly340 } as MethodCallOptions<Auction>341)342```343 344:::note345If you use a [customized call tx builder](../how-to-deploy-and-call-a-contract/how-to-customize-a-contract-tx.md), you must explicitly set the change output of the transaction in the builder beforehand. Otherwise, you cannot call `this.changeAmount` or `this.buildChangeOutput` in the contract.346:::347 348```ts349const unsignedTx: bsv.Transaction = new bsv.Transaction()350 // add inputs and outputs351 // ...352 // add change output353 // otherwise you cannot call `this.changeAmount` and `this.buildChangeOutput` in the contract354 .change(options.changeAddress);355```356 357### `fromTx`358 359Function `static fromTx(tx: bsv.Transaction, atOutputIndex: number, offchainValues?: Record<string, any>)` creates an instance with its state synchronized to a given transaction output, identified by `tx` the transaction and `atOutputIndex` the output index. It is needed to [create an up-to-date instance of a contract](./../how-to-deploy-and-call-a-contract/how-to-deploy-and-call-a-contract.md#create-a-smart-contract-instance-from-a-transaction).360 361```ts362// create an instance from a transaction output363const instance = ContractName.fromTx(tx, atOutputIndex)364 365// we're good here, the `instance` is state synchronized with the on-chain transaction366```367 368If the contract contains @prop's of type `HashedMap` or `HashedSet`, the values of all these properties at this transaction must be passed in the third argument.369 370```ts371// e.g. the contract has two stateful properties of type `HashedMap` or `HashedSet`372// @prop(true) mySet: HashedSet<bigint>373// @prop() myMap: HashedMap<bigint, bigint>374const instance = ContractName.fromTx(tx, atOutputIndex, {375 // pass the values of all these properties at the transaction moment376 'mySet': currentSet,377 'myMap': currentMap,378})379```380 381### `buildDeployTransaction`382 383Function `async buildDeployTransaction(utxos: UTXO[], amount: number, changeAddress?: bsv.Address | string): Promise<bsv.Transaction>` creates a tx to deploy the contract. The first parameter `utxos` represents one or more [P2PKH](https://learnmeabitcoin.com/technical/p2pkh) inputs for paying transaction fees. The second parameter `amount` is the balance of contract output. The last parameter `changeAddress` is optional and represents a change address. Users override it to [cutomize a deployment tx](../how-to-deploy-and-call-a-contract/how-to-customize-a-contract-tx.md#customize) as below.384 385 386```ts387override async buildDeployTransaction(utxos: UTXO[], amount: number, changeAddress?: bsv.Address | string): Promise<bsv.Transaction> {388 const deployTx = new bsv.Transaction()389 // add p2pkh inputs for paying tx fees390 .from(utxos) 391 // add contract output392 .addOutput(new bsv.Transaction.Output({393 script: this.lockingScript,394 satoshis: amount,395 }))396 // add the change output if passing `changeAddress`397 if (changeAddress) {398 deployTx.change(changeAddress);399 if (this._provider) {400 deployTx.feePerKb(await this.provider.getFeePerKb());401 }402 }403 404 return deployTx;405 }406```407 408### `bindTxBuilder`409 410Function `bindTxBuilder(methodName: string, txBuilder: MethodCallTxBuilder<SmartContract>):void` binds the customized transaction builder `MethodCallTxBuilder`, which returns a `ContractTransation`, to a contract public `@method` identified by `methodName`.411 412```ts413 414/**415 * A transaction builder.416 * The default transaction builder only supports fixed-format call transactions. 417 * Some complex contracts require a custom transaction builder to successfully call the contract.418 */419export interface MethodCallTxBuilder<T extends SmartContract> {420 (current: T, options: MethodCallOptions<T>, ...args: any): Promise<ContractTransaction>421}422 423 424// bind a customized tx builder for the public method `instance.unlock()`425instance.bindTxBuilder("unlock", (options: MethodCallOptions<T>, ...args: any) => {426 // ...427})428```429 430You may visit [here](../how-to-deploy-and-call-a-contract/how-to-customize-a-contract-tx.md#customize-1) to see more details on how to customize tx builder.431 432 433### `multiContractCall`434 435When the `@method`s of multiple contracts is called in a transaction, the transaction builders for each contract collectively construct the `ContractTransation`. Function `static async multiContractCall(partialContractTx: ContractTransaction, signer: Signer): Promise<MultiContractTransaction>` signs and broadcasts the final transaction.436 437```ts438const partialContractTx1 = await counter1.methods.incrementOnChain(439 {440 multiContractCall: true,441 } as MethodCallOptions<Counter>442)443 444const partialContractTx2 = await counter2.methods.incrementOnChain(445 {446 multiContractCall: true,447 partialContractTx: partialContractTx1448 } as MethodCallOptions<Counter>449);450 451const {tx: callTx, nexts} = await SmartContract.multiContractCall(partialContractTx2, signer)452 453 454console.log('Counter contract counter1, counter2 called: ', callTx.id)455```456 457 458 459## Standard Libraries460 461`sCrypt` comes with standard libraries that define many commonly used functions.462 463### `Utils`464 465The `Utils` library provides a set of commonly used utility functions.466 467- `static toLEUnsigned(n: bigint, l: bigint): ByteString` Convert the signed integer `n` to an unsigned integer of `l` bytes, in sign-magnitude little endian format.468 469```ts470Utils.toLEUnsigned(10n, 3n) // '0a0000'471Utils.toLEUnsigned(-10n, 2n) // '0a00'472```473 474- `static fromLEUnsigned(bytes: ByteString): bigint` Convert ByteString to unsigned integer.475 476```ts477Utils.fromLEUnsigned(toByteString('0a00')) // 10n478Utils.fromLEUnsigned(toByteString('8a')) // 138n, actually converts 8a00 to unsigned integer479```480 481- `static readVarint(buf: ByteString): ByteString` Read a [VarInt](https://learnmeabitcoin.com/technical/varint) field from `buf`.482 483```ts484Utils.readVarint(toByteString('0401020304')) // '01020304'485```486 487- `static writeVarint(buf: ByteString): ByteString` Convert `buf` to a [VarInt](https://learnmeabitcoin.com/technical/varint) field, including the preceding length.488 489```ts490Utils.writeVarint(toByteString('010203')) // '03010203'491```492 493- `static buildOutput(outputScript: ByteString, outputSatoshis: bigint): ByteString` Build a transaction output with the specified script and satoshi amount.494 495```ts496const lockingScript = toByteString('01020304')497Utils.buildOutput(lockingScript, 1n) // '01000000000000000401020304'498```499 500- `static buildPublicKeyHashScript(pubKeyHash: PubKeyHash ): ByteString` Build a [Pay to Public Key Hash (P2PKH)](https://wiki.bitcoinsv.io/index.php/Bitcoin_Transactions#Pay_to_Public_Key_Hash_.28P2PKH.29) script from a public key hash.501 502```ts503const pubKeyHash = PubKeyHash(toByteString('0011223344556677889900112233445566778899'))504Utils.buildPublicKeyHashScript(pubKeyHash) // '76a914001122334455667788990011223344556677889988ac'505```506 507- `static buildPublicKeyHashOutput(pubKeyHash: PubKeyHash, amount: bigint): ByteString` Build a P2PKH output from the public key hash.508 509```ts510const pubKeyHash = PubKeyHash(toByteString('0011223344556677889900112233445566778899'))511Utils.buildPublicKeyHashOutput(pubKeyHash, 1n) // '01000000000000001976a914001122334455667788990011223344556677889988ac'512```513 514- `static buildOpreturnScript(data: ByteString): ByteString` Build a data-carrying [FALSE OP_RETURN](https://wiki.bitcoinsv.io/index.php/OP_RETURN) script from `data` payload.515 516```ts517const data = toByteString('hello world', true)518Utils.buildOpreturnScript(data) // '006a0b68656c6c6f20776f726c64'519```520 521### `HashedMap`522 523 524`HashedMap` provides a map/hashtable-like data structure. It is different to use `HashedMap` in on-chain and off-chain context.525 526#### On-chain527 528The main difference between `HashedMap` and other data types we’ve [previously introduced](../how-to-write-a-contract/#data-types) is that it does NOT store raw data (i.e., keys and values) in the contract on the blockchain. It stores their hashed values instead, to minimize on-chain storage, which is expensive.529 530These guidelines must be followed when using `HashedMap` in a contract `@method`, i.e., on-chain context.531 532* Only the following methods can be called.533 534 - `set(key: K, val: V): HashedMap`: Adds a new element with a specified key and value. If an element with the same key already exists, the element will be updated.535 - `canGet(key: K, val: V): boolean`: Returns `true` if the specified **key and value pair** exists, otherwise returns `false`.536 - `has(key: K): boolean`: Returns `true` if the specified key exists, otherwise returns `false`.537 - `delete(key: K): boolean`: Returns `true` if a key exists and has been removed, otherwise returns `false`.538 - `clear(): void`: Remove all key and value pairs.539 - `size: number`: Returns the number of elements.540 541:::note 542`get()` is not listed, since the value itself is not stored and thus must be passed in and verified using `canGet()`.543:::544 545* The aforementioned methods can only be used in public `@method`s, NOT in non-public `@method`s, including constructors.546 547* `HashedMap` can be used as an `@prop`, either stateful or not:548 549```ts550@prop() map: HashedMap<KeyType, ValueType>; // valid551@prop(true) map: HashedMap<KeyType, ValueType> // also valid552```553 554* It CANNOT be used as a `@method` parameter, regardless of public or not:555 556```ts557@method public unlock(map: HashedMap<KeyType, ValueType>) // invalid as a parameter type558@method foo(map: HashedMap<KeyType, ValueType>) // invalid as a parameter type559```560 561* No nesting is allowed currently. That is, key and value cannot contain a `HashedMap`.562```ts563type Map1 = HashedMap<KeyType1, ValueType1>564HashedMap<KeyType2, Map1> // invalid565HashedMap<Map1, ValueType2> // invalid566 567type KeyType = {568 key1: KeyType1569 key2: KeyType2570}571HashedMap<KeyType, ValueType> // valid572```573 574A full example may look like this:575 576```ts577class MyContract extends SmartContract {578 @prop(true)579 myMap: HashedMap<bigint, bigint>;580 581 // HashedMap can be a parameter in constructor582 constructor(map: HashedMap<bigint, bigint>) {583 // assignment is ok, but not calling method584 this.myMap = map;585 }586 587 @method()588 public unlock(key: bigint, val: bigint) {589 this.myMap.set(key, val);590 assert(this.myMap.has(key));591 assert(this.myMap.canGet(key, val));592 assert(this.myMap.delete(key));593 assert(!this.myMap.has(key));594 }595}596```597 598#### Off-chain599 600`HashedMap` acts just like the JavaScript/TypeScript [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) when used in off-chain code (that is, not in a contract's `@method`). For example, you can create an instance like this:601 602```ts603// create an empty map604let hashedMap = new HashedMap<bigint, ByteString>();605 606// create from (key,value) pairs607let hashedMap1 = new HashedMap([['key1', 'value1'], ['key2', 'value2']]);608```609 610Also, you can call its functions like this:611 612```ts613hashedMap.set(key, value);614const v = hashedMap.get(key); // <----615hashedMap.has(key);616hashedMap.delete(key);617...618```619:::note620`get()` can be called since the HashedMap stores the original key and value off chain.621:::622 623Only when the key is an object is `HashedMap` different from `Map`. `HashedMap` will treat two keys the same if they have the same values, while `Map` will only if they reference the same object. For instance:624 625```ts626interface ST {627 a: bigint;628}629 630let map = new Map<ST, bigint>();631map.set({a: 1n}, 1n);632map.set({a: 1n}, 2n);633console.log(map.size); // output ‘2’ cause two keys {a: 1n} reference differently634console.log(map.get({a: 1n})); // output ‘undefined’635 636 637let hashedMap = new HashedMap<ST, bigint>();638hashedMap.set({a: 1n}, 1n);639hashedMap.set({a: 1n}, 2n);640console.log(hashedMap.size); // output ‘1’641console.log(hashedMap.get({a: 1n})); // output ‘2n’642```643 644### `HashedSet`645 646 647`HashedSet` library provides a set-like data structure. It can be regarded as a special `HashedMap` where a value is the same with its key and is thus omitted. Values are hashed before being stored in contracts on the blockchain, as in `HashedMap`.648 649#### On-chain650 651When used in public `@method`s, `HashedSet` also has almost all of the same restrictions as `HashedMap`. Except for the methods on its own whitelist that can be called in `@method`s as following:652 653- `add(value: T): HashedSet`: Inserts a new element with a specified value in to a set, if there isn't an element with the same value already in the set.654 655- `has(value: T): boolean`: Returns `true` if an element with the specified value exists in the set, otherwise returns `false`.656 657- `delete(value: T): boolean`: Returns `true` if an element in the Set existed and has been removed, or false if the element does not exist.658 659- `clear(): void`: Delete all entries of the set.660 661- `size: number`: Returns the size of set, i.e. the number of the entries it contains.662 663 664#### Off-chain665 666`HashedSet` can be used the same as a JavaScript `Set` in off-chain code .667 668```ts669let hashedSet = new HashedSet<bigint>()670hashedSet.add(1n);671hashedSet.has(1n);672hashedSet.delete(1n);673...674```675 676Similar to `HashedMap`, `HashedSet` will treat two objects as identical if their values equal, rather than requiring that they reference to the same object.677 678```ts679interface ST {680 a: bigint;681}682 683let set = new Set<ST>();684set.add({a: 1n});685set.add({a: 1n});686console.log(set.size); // output ‘2’687console.log(set.has({a: 1n})); // output ‘false’688 689 690let hashedSet = new HashedSet<ST, bigint>();691hashedSet.add({a: 1n});692hashedSet.add({a: 1n});693console.log(hashedSet.size); // output ‘1’694console.log(hashedSet.has({a: 1n})); // output ‘true’695```696 697### `Constants`698 699`Constants` defines some commonly used constant values.700 701```ts702class Constants {703 // number of string to denote input sequence704 static readonly InputSeqLen: bigint = BigInt(4);705 // number of string to denote output value706 static readonly OutputValueLen: bigint = BigInt(8);707 // number of string to denote a public key (compressed)708 static readonly PubKeyLen: bigint = BigInt(33);709 // number of string to denote a public key hash710 static readonly PubKeyHashLen: bigint = BigInt(20);711 // number of string to denote a tx id712 static readonly TxIdLen: bigint = BigInt(32);713 // number of string to denote a outpoint714 static readonly OutpointLen: bigint = BigInt(36);715}716```717 