diff --git a/website/docs/basics/getting-started.md b/website/docs/basics/getting-started.md index 1a4f7553..07409b4b 100644 --- a/website/docs/basics/getting-started.md +++ b/website/docs/basics/getting-started.md @@ -6,15 +6,22 @@ title: Getting Started To get started with writing CashScript smart contracts quickly, it is recommended to try out the [CashScript Playground](https://playground.cashscript.org/), a web application which lets you easily write and create contracts! -Here you will learn what a CashScript contract looks like through the `TransferWithTimeout` example contract. Then you can compile the contract and provide the contract arguments to create a smart contract address. To actually create the smart contract itself, you fund the address so that it has a UTXO on the contract address. After setting up the smart contract, you can try spending from the smart contract by invoking a contract function! +The Playground supports 'Mocknet', allowing you to create virtual UTXOs for development without having to get Testnet coins and set up a Testnet wallet. :::tip -The [CashScript Playground](https://playground.cashscript.org/) is a great way to get started without doing any JavaScript coding to set up wallets, fetch balances and invoke contract functions. This way you can focus on learning one thing at a time! +The [CashScript Playground](https://playground.cashscript.org/) is a great way to get started without doing any JavaScript/TypeScript coding to set up wallets, fetch balances and invoke contract functions. This way you can focus on learning just CashScript! ::: -## Creating a CashScript Smart Contract +Here are the 5 simple steps for creating your first smart contract transaction with the Playground: +1. Compile a contract, for example the default `TransferWithTimeout` contract. +2. Create a new contract in the 'New Contract' tab by providing the contract arguments. +3. Add UTXOs to the smart contract address and the wallets used for testing. +4. Next, go to the TansactionBuilder select the contract and the function to invoke +5. Finally, specify the in- and outputs for the transaction and click 'Send'! -With the CashScript playground there's a nice integrated editor to get started, as well as an integrated compiler to change your CashScript contract into a Contract `Artifact` behind the scenes. Now, to get started we will have to set up a CashScript editor — outside of the Playground — and learn how to work with the `cashc` compiler to create CashScript contract artifacts. +## Creating a CashScript Contract + +To get started coding locally we will use a code editor and learn how to work with the `cashc` compiler to create CashScript contract artifacts. ### Prerequisites @@ -37,7 +44,7 @@ The command line CashScript compiler `cashc` can be installed from NPM. npm install -g cashc ``` -### Writing your first smart contract +### Writing your first contract Open your code editor to start writing your first CashScript smart contract. We can start from a basic `TransferWithTimeout` smart contract. Create a new file `TransferWithTimeout.cash`. @@ -65,7 +72,7 @@ contract TransferWithTimeout(pubkey sender, pubkey recipient, int timeout) { There are some other examples available on the [Examples page](/docs/language/examples) that can be used to take inspiration from. Further examples of the TypeScript and JavaScript integration can be found on [GitHub](https://github.com/CashScript/cashscript/tree/master/examples). ::: -### Compiling your smart contract +### Compiling your contract The next step after writing your smart contract is using the command line compiler to create a contract artifact, so that it can be imported into the CashScript SDK. @@ -81,7 +88,7 @@ OP_3 OP_PICK OP_0 OP_NUMEQUAL OP_IF OP_4 OP_ROLL OP_ROT OP_CHECKSIG OP_NIP OP_NI ## Creating a CashScript Transaction -After creating a contract artifact, we can now use the TypeScript SDK to initialise the smart contract and to invoke spending functions on the smart contract UTXOs. We'll continue with the `TransferWithTimeout` artifact generated in the previous steps. +After creating a contract artifact, we can now use the TypeScript SDK to initialise the smart contract and to invoke spending functions on the smart contract UTXOs. We'll continue with the `TransferWithTimeout` artifact generated earlier. :::info The CashScript SDK is written in TypeScript meaning that you can either use TypeScript or vanilla JavaScript to use the SDK. diff --git a/website/docs/guides/optimization.md b/website/docs/guides/optimization.md index 3ee0ad89..ce1c0b7b 100644 --- a/website/docs/guides/optimization.md +++ b/website/docs/guides/optimization.md @@ -5,7 +5,26 @@ sidebar_label: Optimization CashScript contracts are transpiled from a solidity syntax to [BCH Script](https://reference.cash/protocol/blockchain/script) by the `cashc` compiler. BCH Script is a lower level language (a list of stack-based operations) where each available operation is mapped to a single byte. -Depending on the complexity of the contract or system design, it may sometimes be useful to optimize the Bitcoin Script by tweaking the contract in CashScript before it is compiled. Below are some ideas to get started. +Depending on the complexity of the contract or system design, it may be useful to optimize the Bitcoin Script by tweaking the contract in CashScript before it is compiled because the minimum fees on the Bitcoin Cash network are based on the bytesize of a transaction (including your contract). + +## Example Workflow + +When optimizing your contract, you will need to compare the contract size to see if the changes have a positive impact. +With the compiler CLI, you can easily check the opcode count and bytesize directly from the generated contract artifact. + +```bash +cashc ./contract.cash --opcount --size +``` + +The size outputs of the `cashc` compiler are based on the bytecode without constructor arguments. This means they will always be an underestimate, as the contract hasn't been initialized with contract arguments. + +:::note +The compiler opcount and bytesize outputs are still helpful to compare the effect of changes to the smart contract code on the compiled output, given that the contract constructor arguments stay the same. +::: + +:::tip +To get the exact contract opcount and bytesize including constructor parameters, initialise the contract with the TypScript SDK and check the values of `contract.opcount` and `contract.bytesize`. +::: ## Optimization Tips & Tricks @@ -73,52 +92,25 @@ The concept of having NFT functions was first introduced by the [Jedex demo](htt By using function NFTs you can use a modular contract design where the contract functions are offloaded to different UTXOs, each identifiable by the main contract by using the same tokenId. ::: -## Example Workflow - -When trying to optimize your contract, you will need to compare the contract size to see if the changes have a positive impact. -With the compiler CLI, you can easily check the opcode count and bytesize directly from the contract (without creating a new artifact). -It's important to know the minimum fees on the Bitcoin Cash network are based on the bytesize of a transaction (including your contract). - -```bash -cashc ./contract.cash --opcount --size -``` - -:::caution -The size output of the `cashc` compiler will always be an underestimate, as the contract hasn't been initialized with contract arguments. -::: - -The `cashc` compiler only knows the opcount and bytesize of a contract before it is initialised with function arguments. Because of this, to get an accurate view of a contracts size, initialise the contract instance first, then get the size from there. This means you will have to re-compile the artifact before checking the contract size through the TypeScript SDK. +## Hand-optimizing Bytecode -```javascript -import { ElectrumNetworkProvider, Contract, SignatureTemplate } from 'cashscript'; -import { alicePub, bobPriv, bobPub } from './keys.js'; -import { compileFile } from 'cashc'; +It's worth considering whether hand-optimizing the contract is necessary at all. If the contract works and there is no glaring inefficiency in the bytecode, perhaps the best optimization is to not to obsess prematurely about things like transaction size. -// compile contract code on the fly -const artifact = compileFile(new URL('contract.cash', import.meta.url)); +>We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%. -// Initialise a network provider for network operations -const provider = new ElectrumNetworkProvider('chipnet'); +### Overwriting the Artifact -// Instantiate a new TransferWithTimeout contract -const contractArguments = [alicePub, bobPub, 100000n] -const options = { provider } -const contract = new Contract(artifact, contractArguments, options); +To manually change the contract bytecode, you need to overwrite the `bytecode` key of your contract artifact. -console.log(contract.opcount); -console.log(contract.bytesize); +```typescript +interface Artifact { + bytecode: string // Compiled Script without constructor parameters added (in ASM format) +} ``` -With this workflow, you can make changes to the contract and the run the JavaScript program to -get an accurate measure of how the bytesize of your contract changes with different optimizations. - -## To optimize or not to optimize? - -In the context of optimizing contract bytecode, there's an important remark to consider: - -### OP_NOP - ->We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%. - -It's worth considering whether optimizing the redeem script is necessary at all. If the contract is accepted by the network, and there is no glaring inefficiency in the bytecode, perhaps the best optimization is to not to obsess prematurely about things like block size. +This way you can still use the CashScript TypeScript SDK while using a hand-optimized contract. +:::caution +If you manually overwite the `bytecode` in the artifact, this will make the auto generated 2-way-mapping to become obsolete. +This result of this is that the dubugging functionality will no longer work for the contract. +::: diff --git a/website/docs/guides/walletconnect.md b/website/docs/guides/walletconnect.md new file mode 100644 index 00000000..2d0b8fad --- /dev/null +++ b/website/docs/guides/walletconnect.md @@ -0,0 +1,93 @@ +--- +title: WalletConnect +--- + +The BCH WalletConnect specification was created in July of 2023 and has become popular since. The standard integrates nicely with CashScript contract development as it was designed with CashScript contract usage in mind. + +You can find a full list of Bitcoin Cash dapps supporting WalletConnect on [Tokenaut.cash](https://tokenaut.cash/dapps?filter=walletconnect). + +:::tip +The specification is called ['wc2-bch-bcr'](https://github.com/mainnet-pat/wc2-bch-bcr) and has extra discussion and info on the [BCH research forum](https://bitcoincashresearch.org/t/wallet-connect-v2-support-for-bitcoincash/). +::: + +## signTransaction Interface + +Most relevant for smart contract usage is the BCH-WalletConnect `signTransaction` interface. + +> This is a most generic interface to propose a bitcoincash transaction to a wallet which reconstructs it and signs it on behalf of the wallet user. + +```typescript +signTransaction: ( + options: { + transaction: string | TransactionBCH, + sourceOutputs: (Input | Output | ContractInfo)[], + broadcast?: boolean, + userPrompt?: string + } +) => Promise<{ signedTransaction: string, signedTransactionHash: string } | undefined>; +``` + +Important to note is how the wallet knows which inputs to sign: + +>To signal that the wallet needs to sign an input, the app sets the corresponding input's `unlockingBytecode` to empty Uint8Array. + +## signTransaction Example + +### Create wcTransactionObj + +Example code from the 'Cash-Ninjas' minting dapp repository, [link to source code](https://github.com/cashninjas/ninjas.cash/blob/main/js/mint.js). + +```javascript +import { Contract } from "cashscript"; +import { hexToBin, decodeTransaction } from "@bitauth/libauth"; + +async function transactionWalletConnect(){ + // use the CashScript SDK to build a transaction + const rawTransactionHex = await transaction.build(); + const decodedTransaction = decodeTransaction(hexToBin(rawTransactionHex)); + + // set input unlockingBytecode to empty Uint8Array for wallet signing + decodedTransaction.inputs[1].unlockingBytecode = Uint8Array.from([]); + + // construct list SourceOutputs, see source code + const listSourceOutputs = constructSourceOuputs(decodedTransaction, utxoInfo, contract) + + // wcTransactionObj to pass to signTransaction endpoint + const wcTransactionObj = { + transaction: decodedTransaction, + sourceOutputs: listSourceOutputs, + broadcast: true, + userPrompt: "Mint Cash-Ninja NFT" + }; + + // pass wcTransactionObj to WalletConnect client + const signResult = await signTransaction(wcTransactionObj); + + // Handle signResult success / failure +} +``` + +### signTransaction Client interaction + +Below is an implementation of `signTransaction` used earlier, this is where the communication with the client for 'signTransaction' takes place. See the source code for `signClient`, `connectedChain` and `session` details. + +```javascript +import SignClient from '@walletconnect/sign-client'; +import { stringify } from "@bitauth/libauth"; + +async function signTransaction(options){ + try { + const result = await signClient.request({ + chainId: connectedChain, + topic: session.topic, + request: { + method: "bch_signTransaction", + params: JSON.parse(stringify(options)), + }, + }); + return result; + } catch (error) { + return undefined; + } +} +``` diff --git a/website/docs/language/contracts.md b/website/docs/language/contracts.md index 271c8a6b..35bccd6e 100644 --- a/website/docs/language/contracts.md +++ b/website/docs/language/contracts.md @@ -5,10 +5,10 @@ title: Contract Structure Contracts in CashScript are somewhat similar to classes in object-oriented languages. A notable difference is that there is no mutable state. So once a contract is instantiated with certain parameters, these values cannot change. Instead, functions can be called on the contract that act on the contract's values to spend money from the contract. The extension of CashScript source code files is `.cash`, and the structure of these source files is explained below. ## Pragma -A contract file may start with a pragma directive to indicate the CashScript version the contract was written for. This ensures that a contract is not compiled with an unsupported compiler version, which could cause unintended side effects. +A contract file may start with a pragma directive to indicate the CashScript version the contract was written for. This ensures that a contract is not compiled with an unsupported compiler version. The pragma directive follows regular [semantic versioning (SemVer)](https://semver.npmjs.com/) rules. -:::note -The pragma directive follows regular [semantic versioning rules](https://semver.npmjs.com/). +:::caution +Contract authors should be careful when allowing a range of versions to check that no breaking changes to the compiler were introduced in these versions which would result in different bytecode and smart contract address. ::: #### Example @@ -82,7 +82,7 @@ contract P2PKH(bytes20 pkh) { ### Variable declaration Variables can be declared by specifying their type and name. All variables need to be initialised at the time of their declaration, but can be reassigned later on — unless specifying the `constant` keyword. Since CashScript is strongly typed and has no type inference, it is not possible to use keywords such as `var` or `let` to declare variables. -:::caution +:::note CashScript disallows variable shadowing and unused variables. ::: diff --git a/website/docs/language/examples.md b/website/docs/language/examples.md index 47024987..6d49ff62 100644 --- a/website/docs/language/examples.md +++ b/website/docs/language/examples.md @@ -2,31 +2,7 @@ title: Examples --- -An extensive collection of examples is available in the [GitHub repository](https://github.com/CashScript/cashscript/tree/master/examples). Below we discuss a few of these examples in more details and go through their functionality. These examples focus mainly on the CashScript syntax, while the [Examples page](/docs/sdk/examples) in the sdk section focuses more on the use of the SDK. - -## Transfer With Timeout -One interesting use case of Bitcoin Cash is using it for *paper tips*. With paper tips, you send a small amount of money to an address, and print the corresponding private key on a piece of paper. Then you can hand out these pieces of paper as a tip or gift to people in person. In practice, however, people might not know what to do with these gifts or they might lose or forget about it. - -As an alternative, a smart contract can be used for these kinds of gifts. This smart contract allows the recipient to claim their gift at any time, but if they don't claim it in time, the sender can reclaim it. - -```solidity -pragma cashscript ^0.10.0; - -contract TransferWithTimeout(pubkey sender, pubkey recipient, int timeout) { - // Require recipient's signature to match - function transfer(sig recipientSig) { - require(checkSig(recipientSig, recipient)); - } - - // Require timeout time to be reached and sender's signature to match - function timeout(sig senderSig) { - require(checkSig(senderSig, sender)); - require(tx.time >= timeout); - } -} -``` - -For an example of how to put this contract to use in a JavaScript application, see the [SDK examples page](/docs/sdk/examples#transfer-with-timeout) +An extensive collection of examples is available in the [GitHub repository](https://github.com/CashScript/cashscript/tree/master/examples). Below we discuss a few of these examples in more details and go through their functionality. This example page focuses on the CashScript syntax, while the [SDK Examples page](/docs/sdk/examples) in the SDK section focuses on use of the SDK to build an application. ## HodlVault For better or worse, HODLing and waiting for price increases is one of the main things people want to do with their cryptocurrency. But it can be difficult to hold on to your cryptocurrency when the price is going down. So to prevent weak hands from getting the best of you, it's better to store your stash in a smart contract that enforces HODLing for you. @@ -66,6 +42,9 @@ contract HodlVault(pubkey ownerPk, pubkey oraclePk, int minBlock, int priceTarge } ``` +For how to put the HodlVault contract to use in a Typescript application, see the [SDK examples page](/docs/sdk/examples#hodlvault). + + ## Licho's Mecenas Donations are a great way to support the projects you love, and periodic donations can incentivise continuous improvement to the product. But platforms like Patreon generally take fees of 10%+ and don't accept cryptocurrencies. Instead you can create a peer-to-peer smart contract that allows a recipient to withdraw a specific amount every month. @@ -74,6 +53,8 @@ The contract works by checking that a UTXO is at least 30 days old, after which Due to the nature of covenants, we have to be very specific about the outputs (amounts and destinations) of the transaction. This also means that we have to account for the special case where the remaining contract balance is lower than the `pledge` amount, meaning no remainder should be sent back. Finally, we have to account for a small fee that has to be taken from the contract's balance to pay the miners. ```solidity +pragma cashscript ^0.10.0; + contract Mecenas(bytes20 recipient, bytes20 funder, int pledge, int period) { function receive() { require(tx.age >= period); @@ -107,4 +88,51 @@ contract Mecenas(bytes20 recipient, bytes20 funder, int pledge, int period) { } ``` +## AMM DEX + +AMM DEX contract based on [the Cauldron DEX contract](https://www.cauldron.quest/_files/ugd/ae85be_b1dc04d2b6b94ab5a200e3d8cd197aa3.pdf), you can read more details about the contract design there. + +Compared to the manually written and hand-optimized opcodes version of the contract, the CashScript compiled bytecode has just 5 extra opcodes overhead (7 extra bytes). + +```solidity +pragma cashscript ^0.10.0; + +contract DexContract(bytes20 poolOwnerPkh) { + function swap() { + // Verify it is the correct token category + bytes inputToken = tx.inputs[this.activeInputIndex].tokenCategory; + bytes outputToken = tx.outputs[this.activeInputIndex].tokenCategory; + require(inputToken == outputToken); + + // Enforce version 2 + // Enforcing version is to make sure that tools that + // use this contract stay compatible, when and if + // transaction format changes in the future. + require(tx.version == 2); + + // Verify that this contract lives on on the output with the same input as this contract. + bytes inputBytecode = tx.inputs[this.activeInputIndex].lockingBytecode; + bytes outputBytecode = tx.outputs[this.activeInputIndex].lockingBytecode; + require(inputBytecode == outputBytecode); + + // Calculate target K + int targetK = tx.inputs[this.activeInputIndex].value * tx.inputs[this.activeInputIndex].tokenAmount; + + // Calculate fee for trade. Fee is ~0.3% + int tradeValue = abs(tx.inputs[this.activeInputIndex].value - tx.outputs[this.activeInputIndex].value); + int fee = (tradeValue * 3) / 1000; + + // Get effective output K when including the fee. + int effectiveOutputK = (tx.outputs[this.activeInputIndex].value - fee) * tx.outputs[this.activeInputIndex].tokenAmount; + + // Verify that effective K > target K + require(effectiveOutputK >= targetK); + } + function withdrawal(pubkey poolOwnerPk, sig poolOwnerSig) { + require(hash160(poolOwnerPk) == poolOwner); + require(checkSig(poolOwnerSig, poolOwnerPk)); + } +} +``` + More advanced examples on covenants, using NFTs to keep local state and issuing NFTs as receipts can be found in the [Covenants & Introspection Guide](/docs/guides/covenants). diff --git a/website/docs/language/functions.md b/website/docs/language/functions.md index 6f617172..d0740e10 100644 --- a/website/docs/language/functions.md +++ b/website/docs/language/functions.md @@ -1,5 +1,5 @@ --- -title: Global Functions & Operators +title: Global Functions --- CashScript has several built-in functions for things like cryptographic and arithmetic applications, and it includes many common arithmetic and other operators that you would expect in a programming language. @@ -99,29 +99,4 @@ bool checkDataSig(datasig s, bytes msg, pubkey pk) Checks that sig `s` is a valid signature for message `msg` and matches with public key `pk`. -## Operators -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. - -| Precedence | Description | Operator | -| ---------- | ----------------------------------- | ------------------------ | -| 1 | Parentheses | `()` | -| 2 | Type cast | `()` | -| 3 | Object instantiation | `new ()` | -| 4 | Function call | `()` | -| 5 | Tuple index | `[]` | -| 6 | Member access | `.` | -| 7 | Unary minus | `-` | -| 7 | Logical NOT | `!` | -| 8 | Multiplication, division and modulo | `*`, `/`, `%` | -| 9 | Addition and subtraction | `+`, `-` | -| 9 | String / bytes concatenation | `+` | -| 10 | Numeric comparison | `<`, `>`, `<=`, `>=` | -| 11 | Equality and inequality | `==`, `!=` | -| 12 | Bitwise AND | `&` | -| 13 | Bitwise XOR | `^` | -| 14 | Bitwise OR | \| | -| 15 | Logical AND | `&&` | -| 16 | Logical OR | \|\| | -| 17 | Assignment | `=` | - [bip146]: https://github.com/bitcoin/bips/blob/master/bip-0146.mediawiki diff --git a/website/docs/language/types.md b/website/docs/language/types.md index 2b8d5807..ca548665 100644 --- a/website/docs/language/types.md +++ b/website/docs/language/types.md @@ -1,5 +1,5 @@ --- -title: Types +title: Types & Operators --- CashScript is a statically typed language, which means that the type of each variable needs to be specified. Types can also be implicitly or explicitly cast to other types. For a quick reference of the various casting possibilities, see [Type Casting](#type-casting). @@ -186,3 +186,28 @@ VM numbers follow Script Number format (A.K.A. CSCriptNum), to convert VM number :::caution When casting bytes types to integer, you should be sure that the bytes value fits inside a 64-bit signed integer, or the script will fail. ::: + +## Operators +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. + +| Precedence | Description | Operator | +| ---------- | ----------------------------------- | ------------------------ | +| 1 | Parentheses | `()` | +| 2 | Type cast | `()` | +| 3 | Object instantiation | `new ()` | +| 4 | Function call | `()` | +| 5 | Tuple index | `[]` | +| 6 | Member access | `.` | +| 7 | Unary minus | `-` | +| 7 | Logical NOT | `!` | +| 8 | Multiplication, division and modulo | `*`, `/`, `%` | +| 9 | Addition and subtraction | `+`, `-` | +| 9 | String / bytes concatenation | `+` | +| 10 | Numeric comparison | `<`, `>`, `<=`, `>=` | +| 11 | Equality and inequality | `==`, `!=` | +| 12 | Bitwise AND | `&` | +| 13 | Bitwise XOR | `^` | +| 14 | Bitwise OR | \| | +| 15 | Logical AND | `&&` | +| 16 | Logical OR | \|\| | +| 17 | Assignment | `=` | diff --git a/website/docs/sdk/instantiation.md b/website/docs/sdk/instantiation.md index 28142d9d..4d7a3980 100644 --- a/website/docs/sdk/instantiation.md +++ b/website/docs/sdk/instantiation.md @@ -9,7 +9,7 @@ CashScript offers a TypeScript SDK, which can also be used easily in vanilla Jav Because of the separation of the compiler and the SDK, CashScript contracts can be integrated into other languages in the future. ::: -## Contract class +## Creating a Contract The `Contract` class is used to represent a CashScript contract in a JavaScript object. These objects can be used to retrieve information such as the contract's address and balance. They can also be used to interact with the contract by calling the contract's functions. ### Constructor @@ -54,6 +54,8 @@ const options = { provider, addressType} const contract = new Contract(P2PKH, contractArguments, options); ``` +## Contract Properties + ### address ```ts contract.address: string @@ -118,6 +120,8 @@ Returns the contract's redeem script encoded as a hex string. console.log(contract.bytecode) ``` +## Contract Methods + ### getBalance() ```ts async contract.getBalance(): Promise @@ -189,38 +193,3 @@ const contractUtxos = await contract.getUtxos(); transactionBuilder.addInput(contractUtxos[0], contract.unlock.spend()); ``` - -## SignatureTemplate -```ts -new SignatureTemplate(signer: Keypair | Uint8Array | string, hashtype?: HashType) -``` - -You may notice the `SignatureTemplate` object in the [example](#example-8) above. When a contract function has a `sig` parameter, it requires a cryptographic signature over the spending transaction. But to generate this signature, the transaction needs to be built first, which is not yet the case when a contract function is first called. - -So in the place of a signature, a `SignatureTemplate` can be passed, which will automatically generate the correct signature using the `signer` parameter. This signer can be any representation of a private key, including [BCHJS' `ECPair`][ecpair], [bitcore-lib-cash' `PrivateKey`][privatekey], [WIF strings][wif], or raw private key buffers. This ensures that any BCH library can be used. - -The default `hashtype` is `HashType.SIGHASH_ALL | HashType.SIGHASH_UTXOS` because this is the most secure option for smart contract use cases. - -```ts -export enum HashType { - SIGHASH_ALL = 0x01, - SIGHASH_NONE = 0x02, - SIGHASH_SINGLE = 0x03, - SIGHASH_UTXOS = 0x20, - SIGHASH_ANYONECANPAY = 0x80, -} -``` - -:::note -If you're using "old-style" covenants (using CashScript v0.6.0 or lower), you need to configure `HashType.SIGHASH_ALL` as the `hashtype` parameter for the SignatureTemplate. -::: - -#### Example -```ts -const wif = 'L4vmKsStbQaCvaKPnCzdRArZgdAxTqVx8vjMGLW5nHtWdRguiRi1'; -const sig = new SignatureTemplate(wif, HashType.SIGHASH_ALL | HashType.SIGHASH_UTXOS ); -``` - -[wif]: https://en.bitcoin.it/wiki/Wallet_import_format -[ecpair]: https://bchjs.fullstack.cash/#api-ECPair -[privatekey]: https://github.com/bitpay/bitcore/blob/master/packages/bitcore-lib-cash/docs/privatekey.md diff --git a/website/docs/sdk/signature-templates.md b/website/docs/sdk/signature-templates.md new file mode 100644 index 00000000..172756ac --- /dev/null +++ b/website/docs/sdk/signature-templates.md @@ -0,0 +1,86 @@ +--- +title: Signature Templates +--- + +When a contract function has a `sig` parameter, it needs a cryptographic signature from a private key for the spending transaction. +In place of a signature, a `SignatureTemplate` can be passed, which will automatically generate the correct signature once the transaction is built. + +## SignatureTemplate + +### Constructor + +```ts +new SignatureTemplate( + signer: Keypair | Uint8Array | string, + hashtype?: HashType, + signatureAlgorithm?: SignatureAlgorithm +) +``` + +In place of a signature, a `SignatureTemplate` can be passed, which will automatically generate the correct signature using the `signer` parameter. This signer can be any representation of a private key, including [BCHJS' `ECPair`][ecpair], [bitcore-lib-cash' `PrivateKey`][privatekey], [WIF strings][wif], or raw private key buffers. This ensures that any BCH library can be used. + +#### Example +```ts +const aliceWif = 'L4vmKsStbQaCvaKPnCzdRArZgdAxTqVx8vjMGLW5nHtWdRguiRi1'; +const aliceSignatureTemplate = new SignatureTemplate(aliceWif) + +const tx = await contract.functions + .transfer(aliceSignatureTemplate) + .to('bitcoincash:qrhea03074073ff3zv9whh0nggxc7k03ssh8jv9mkx', 10000n) + .send() +``` + +The `hashtype` and `signatureAlgorithm` options are covered under ['Advanced Usage'](/docs/sdk/signature-templates#advanced-usage). + +## Advanced Usage + +### HashType + +The default `hashtype` is `HashType.SIGHASH_ALL | HashType.SIGHASH_UTXOS` because this is the most secure option for smart contract use cases. + +```ts +export enum HashType { + SIGHASH_ALL = 0x01, + SIGHASH_NONE = 0x02, + SIGHASH_SINGLE = 0x03, + SIGHASH_UTXOS = 0x20, + SIGHASH_ANYONECANPAY = 0x80, +} +``` + +:::note +If you're using "old-style" covenants (using CashScript v0.6.0 or lower), you need to configure `HashType.SIGHASH_ALL` as the `hashtype` parameter for the SignatureTemplate. +::: + +#### Example +```ts +const wif = 'L4vmKsStbQaCvaKPnCzdRArZgdAxTqVx8vjMGLW5nHtWdRguiRi1'; + +const signatureTemplate = new SignatureTemplate( + wif, HashType.SIGHASH_ALL | HashType.SIGHASH_UTXOS +); +``` + +### SignatureAlgorithm + +The `signatureAlgorithm` parameter determines the cryptographic algorithm used for signing. By default, the modern and compact Schnorr algorithm is used. + +```ts +export enum SignatureAlgorithm { + ECDSA = 0x00, + SCHNORR = 0x01, +} +``` + +#### Example +```ts +const wif = 'L4vmKsStbQaCvaKPnCzdRArZgdAxTqVx8vjMGLW5nHtWdRguiRi1'; + +const hashType = HashType.SIGHASH_ALL | HashType.SIGHASH_UTXOS +const signatureAlgorithm = SignatureAlgorithm.SCHNORR +const signatureTemplate = new SignatureTemplate(wif, hashType,signatureAlgorithm); +``` + +[wif]: https://en.bitcoin.it/wiki/Wallet_import_format +[ecpair]: https://bchjs.fullstack.cash/#api-ECPair +[privatekey]: https://github.com/bitpay/bitcore/blob/master/packages/bitcore-lib-cash/docs/privatekey.md diff --git a/website/sidebars.js b/website/sidebars.js index 5b16c91c..d7f98d05 100755 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -34,6 +34,7 @@ module.exports = { label: 'TypeScript SDK', items: [ 'sdk/instantiation', + 'sdk/signature-templates', 'sdk/network-provider', 'sdk/transactions', 'sdk/transactions-advanced', @@ -47,6 +48,7 @@ module.exports = { items: [ 'guides/syntax-highlighting', 'guides/covenants', + 'guides/walletconnect', 'guides/debugging', 'guides/optimization' ],