Merge branch 'master' into feat/use-2.1

This commit is contained in:
Aaron Blankstein
2022-08-04 12:41:49 -05:00
committed by GitHub
12 changed files with 631 additions and 44 deletions

270
NFT_USE_CASE.md Normal file
View File

@@ -0,0 +1,270 @@
# NFT Use Case Demo
## Introduction
In this demo, you will learn how to:
1. Publish an NFT contract on the Stacks (L1) chain & hyperchain (L2) respectively.
2. Register NFT asset with the hyperchain interface contract.
3. Mint an NFT on the L1 chain.
4. Deposit that NFT to the hyperchain.
5. Transfer the NFT in the hyperchain.
6. Withdraw the NFT back to the L1 chain, which has two steps.
This guide will follow the list above, step by step.
It is also possible to mint assets directly on the hyperchain, and withdraw them onto the L1. This bonus step is mentioned
at the end of step 5.
## Hyperchains Background
A hyperchain is a network that is separate from the Stacks chain. A hyperchain can be thought of as a layer-2 (L2),
and the Stacks chain can be thought of as a layer-1 (L1). The hyperchain interfaces with the Stacks chain via a smart
contract that is specific to the hyperchain. Different hyperchain networks will use distinct Stacks contracts as an interface.
This interface contract has several functions that allow it to act as an intermediary between the Stacks chain and
some particular hyperchain. These functions include but are not limited to:
- `commit-block`: Called by hyperchain miners to record block hashes and withdrawal state on the Stacks chain.
- `deposit-ft-asset` / `deposit-stx` / `deposit-nft-asset`: Called by users to deposit assets into the hyperchains
contract. The Hyperchain "listens" for calls to these functions, and performs a mint on the hyperchains to
replicate this state. Meanwhile, on the L1, the assets live in the contract.
- `withdraw-ft-asset` / `withdraw-stx` / `withdraw-nft-asset`: Called by miners to withdraw assets from the hyperchain.
In an upcoming update to the hyperchains repo, this function will be called by users directly.
In order to register new allowed assets, a valid miner may call `setup-allowed-contracts`, `register-ft-contract`, or `register-nft-contract`.
The transaction sender must be part of the miners list defined in the hyperchains contract.
## Setup
Make sure you have `clarinet` installed locally, and that it is at version 0.33.0 or above.
If you do not have clarinet, you can find installation instructions [here](https://github.com/hirosystems/clarinet).
Let's create a new clarinet project. This will create a new directory with a Clarinet project initialized.
```
clarinet new nft-use-case
```
Let us copy contract files and scripts over from the `stacks-hyperchains` repository into the `nft-use-case` directory.
If you don't already have the stacks-hyperchains repository, you can [clone it](https://github.com/hirosystems/stacks-hyperchains).
Here's the command to clone the stacks-hyperchains repository:
```
git clone https://github.com/hirosystems/stacks-hyperchains.git
```
Set the environment variable `HYPERCHAIN_PATH` to the location of the stacks-hyperchains repository on your computer.
```
export HYPERCHAIN_PATH=<YOUR_PATH_HERE>
```
Now, we can copy files from the stacks-hyperchains repository. These files are contracts which will define the layer-1
and layer-2 Clarity traits for NFTs and fungible tokens, implement an NFT in layer-1 and layer-2, and some NodeJS scripts for
helping to deploy the contracts.
```
mkdir nft-use-case/contracts-l2
mkdir nft-use-case/scripts
cp $HYPERCHAIN_PATH/core-contracts/contracts/helper/simple-nft.clar nft-use-case/contracts/
cp $HYPERCHAIN_PATH/core-contracts/contracts/helper/trait-standards.clar nft-use-case/contracts/
cp $HYPERCHAIN_PATH/core-contracts/contracts/helper/simple-nft-l2.clar nft-use-case/contracts-l2/
cp $HYPERCHAIN_PATH/core-contracts/contracts/helper/trait-standards.clar nft-use-case/contracts-l2/
cp $HYPERCHAIN_PATH/contrib/scripts/nft-use-case/* nft-use-case/scripts/
cd nft-use-case/scripts
```
To use the scripts in this demo, we need to install some NodeJS libraries.
Before running the following instructions, make sure you have [node](https://nodejs.org/en/) installed.
```
npm install
```
The `Devnet.toml` file in the `nft-use-case` directory is responsible for configuring the `clarinet integrate`
local network. Make the following change in `settings/Devnet.toml` to enable the hyperchain:
```
[devnet]
...
enable_hyperchain_node = true
```
Let's spin up a hyperchain node. Before you call this, make sure that you have a working installation of Docker running
locally.
```
clarinet integrate
```
Before we publish any transactions, you will need to set up some environment variables.
These environment variables contain the address and private key of the hyperchain miner, two user addresses
and private keys, and the RPC URL which we can query for hyperchain state.
Open a separate terminal window, navigate to the directory `nft-use-case/scripts`, and enter the following.
```
export AUTH_HC_MINER_ADDR=ST3AM1A56AK2C1XAFJ4115ZSV26EB49BVQ10MGCS0
export AUTH_HC_MINER_KEY=7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01
export USER_ADDR=ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND
export USER_KEY=f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701
export ALT_USER_ADDR=ST2REHHS5J3CERCRBEPMGH7921Q6PYKAADT7JP2VB
export ALT_USER_KEY=3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801
export HYPERCHAIN_URL="http://localhost:30443"
```
## Step 1: Publish the NFT contract to the Stacks L1 and the Hyperchain
Once the Stacks node and the hyperchain node boots up (use the indicators in the top right panel to determine this), we can
start to interact with the chains. To begin with, we want to publish NFT contracts onto both the L1 and L2. When the user
deposits their L1 NFT onto the hyperchain, their asset gets minted by the L2 NFT contract.
The publish script takes in four arguments: the name of the contract to be published, the filename for the contract
source code, the layer on which to broadcast the transaction (1 or 2), and the nonce of the transaction.
First, publish the layer 1 contracts. You can enter this command (and the following transaction commands) in the same
terminal window as you entered the environment variables. Make sure you are in the `scripts` directory.
These transactions are called by the principal `USER_ADDR`.
```
node ./publish_tx.js trait-standards ../contracts/trait-standards.clar 1 0
node ./publish_tx.js simple-nft-l1 ../contracts/simple-nft.clar 1 1
```
Verify that the contracts were published by using the Clarinet console.
For the layer 1 contracts, you should see the following in the "transactions" region in a recent block.
🟩 deployed: ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND.trait-standards (ok true)
🟩 deployed: ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND.simple-nft-l1 (ok true)
Then, publish the layer 2 contracts. Note, it might take a minute for the hyperchain node to start accepting transactions,
so these commands could fail if you send them too early (but you can always re-try when the node is ready).
These transactions are called by the principal `USER_ADDR`.
```
node ./publish_tx.js trait-standards ../contracts-l2/trait-standards.clar 2 0
node ./publish_tx.js simple-nft-l2 ../contracts-l2/simple-nft-l2.clar 2 1
```
To verify that the layer 2 transactions were processed, grep the hyperchains log for the transaction IDs
of *each* hyperchain transaction.
The transaction ID is logged to the console after the call to `publish_tx` - make sure this is the ID you grep for.
```
docker logs hyperchain-node.nft-use-case.devnet 2>&1 | grep "17901e5ad0587d414d5bb7b1c24c3d17bb1533f5025d154719ba1a2a0f570246"
```
Look for a log line similar to the following in the results:
```
Jul 19 12:34:41.683519 INFO Tx successfully processed. (ThreadId(9), src/chainstate/stacks/miner.rs:235), event_name: transaction_result, tx_id: 17901e5ad0587d414d5bb7b1c24c3d17bb1533f5025d154719ba1a2a0f570246, event_type: success, payload: SmartContract
```
To ensure the contracts were successfully parsed and published, we will grep for the name of the contract and ensure there are no
error lines returned (not atypical for no lines to be returned at this step).
```
docker logs hyperchain-node.nft-use-case.devnet 2>&1 | grep "simple-nft-l2"
```
## Step 2: Register the new NFT asset in the interface hyperchain contract
Create the transaction to register the new NFT asset we just published. This must be called by a miner of the hyperchains contract.
Specifically, this transaction will be sent by `AUTH_HC_MINER_ADDR`.
```
node ./register_nft.js 0
```
Look for the following transaction confirmation in the Clarinet console in an upcoming block on the layer 1.
🟩 invoked: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.hyperchain::register-new-nft-contract(ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG.simple-nft-l1, "hyperchain-deposit-nft-token") (ok true)
## Step 3: Mint an NFT on the L1 Chain
Let's create a transaction to mint an NFT on the L1 chain. Once this transaction is processed, the principal `USER_ADDR`
will own an NFT.
```
node ./mint_nft.js 2
```
Verify that the transaction is acknowledged within the next few blocks in the Stacks explorer.
🟩 invoked: ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND.simple-nft-l1::gift-nft(ST2NEB84ASENDXKYGJPQW86YXQCEFEX2ZQPG87ND, u5) (ok true)
## Step 4: Deposit the NFT onto the Hyperchain
Now, we can call the deposit NFT function in the hyperchains interface contract. This
function is called by the principal `USER_ADDR`.
```
node ./deposit_nft.js 3
```
Verify that the transaction is acknowledged in the next few blocks of the L1 chain.
After the transaction is confirmed in an anchored block on the L1 (this means it is included in an explicitly
numbered block in the Clarinet console), you also may want to verify that the asset was successfully deposited
on the hyperchain by grepping for the deposit transaction ID.
```
docker logs hyperchain-node.nft-use-case.devnet 2>&1 | grep "8d042c14323cfd9d31e121cc48c2c641a8db01dce19a0f6dd531eb33689dff44"
```
Look for a line like:
```
Jul 19 12:51:02.396923 INFO ACCEPTED burnchain operation (ThreadId(8), src/chainstate/burn/db/sortdb.rs:3042), op: deposit_nft, l1_stacks_block_id: 8b5c4eb05afae6daaafdbd59aecaade6da1a8eab5eb1041062c6381cd7104b75, txid: 67cfd6220ed01c3aca3912c8f1ff55d374e5b3acadb3b995836ae913108e0514, l1_contract_id: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG.simple-nft-l1, hc_contract_id: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG.simple-nft-l2, hc_function_name: hyperchain-deposit-nft-token, id: 5, sender: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG
```
## Step 5: Transfer the NFT within the Hyperchain
On the hyperchains, the NFT should belong to the principal that sent the deposit transaction, `USER_ADDR`.
This principal can now transfer the NFT within the hyperchain. The principal `USER_ADDR` will now make a
transaction to transfer the NFT to `ALT_USER_ADDR`.
```
node ./transfer_nft.js 2
```
Grep for the transaction ID of the transfer transaction.
```
docker logs hyperchain-node.nft-use-case.devnet 2>&1 | grep "6acc2c756ddaed2c4cfb7351dd5930aa93ba923504be85e47db056c99a7e81aa"
```
Look for something like the following line:
```
Jul 19 13:04:43.177993 INFO Tx successfully processed. (ThreadId(9), src/chainstate/stacks/miner.rs:235), event_name: transaction_result, tx_id: 74949992488b2519e2d8408169f242c86a6cdacd927638bd4604b3b8d48ea187, event_type: success, payload: ContractCall
```
For a bonus step, you can try minting an NFT on the hyperchain. This would require calling the `gift-nft` function in the
contract `simple-nft-l2`. You can tweak the `transfer_nft.js` file to make this call.
## Step 6: Withdraw the NFT back to the L1 Chain
### Background on withdrawals
Withdrawals from the hyperchain are a 2-step process.
The owner of an asset must call `withdraw-ft?` / `withdraw-stx?` / `withdraw-nft?` in a Clarity contract on the hyperchain,
which destroys those assets on the hyperchain, and adds that particular withdrawal to a withdrawal data structure for that block.
The withdrawal data structure serves as a cryptographic record of the withdrawals in a particular block, and has an
overall associated hash. This hash is committed to the L1 interface contract via the `commit-block` function.
The second step involves calling the appropriate withdraw function in the hyperchains interface
contract on the L1 chain. You must also pass in the "proof" that corresponds to your withdrawal.
This proof includes the hash of the withdrawal data structure that this withdrawal was included in,
the hash of the withdrawal itself, and a list of hashes to be used to prove that the particular withdrawal is valid. Currently,
this function must be called by a hyperchain miner, but in an upcoming hyperchain release, the asset owner must call
this function.
### Step 6a: Withdraw the NFT on the hyperchain
Perform the withdrawal on the layer 2 by calling `withdraw-nft-asset` in the `simple-nft-l2` contract. This will be called
by the principal `ALT_USER_ADDR`.
```
node ./withdraw_nft_l2.js 0
```
Grep the hyperchain node to ensure success:
```
docker logs hyperchain-node.nft-use-case.devnet 2>&1 | grep "5b5407ab074b4d78539133fe72020b18d44535a586574d0bd1f668e05dc89c2f"
Jul 19 13:07:33.804109 INFO Tx successfully processed. (ThreadId(9), src/chainstate/stacks/miner.rs:235), event_name: transaction_result, tx_id: 3ff9b9b0f33dbd6087f302fa9a7a113466cf7700ba7785a741b391f5ec7c5ba4, event_type: success, payload: ContractCall
docker logs hyperchain-node.nft-use-case.devnet 2>&1 | grep "withdraw-nft-asset"
Jul 19 13:22:34.800652 INFO Contract-call successfully processed (ThreadId(8), src/chainstate/stacks/db/transactions.rs:731), contract_name: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG.simple-nft-l2, function_name: withdraw-nft-asset, function_args: [u5, ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC], return_value: (ok true), cost: ExecutionCost { write_length: 2, write_count: 2, read_length: 1647, read_count: 5, runtime: 2002000 }
```
In order to successfully complete the withdrawal on the L1, it is necessary to know the height at which the withdrawal occurred.
You can find the height of the withdrawal using grep:
```
docker logs hyperchain-node.nft-use-case.devnet 2>&1 | grep "Parsed L2 withdrawal event"
Jul 19 13:22:34.801290 INFO Parsed L2 withdrawal event (ThreadId(8), src/clarity_vm/withdrawal.rs:56), type: nft, block_height: 47, sender: ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05NNC, withdrawal_id: 0, asset_id: ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG.simple-nft-l2::nft-token
```
Get the withdrawal height by looking at the `block_height` in the returned line. There may be multiple lines returned
by the grep. Try the higher heights first, and work backward.
### Step 6b: Complete the withdrawal on the Stacks chain
Use the withdrawal height we just obtained from the grep and substitute that for `WITHDRAWAL_BLOCK_HEIGHT`.
You might need to wait a little bit for the hyperchain block to become official (even if
the grep already returned a result) for the transaction to succeed. If the hyperchain has not advanced sufficiently, you
may get the error `Supplied block height not found`. For now, this script assumes that the requested
withdrawal was the only one in the hyperchain block it was a part of (thus, you may run into issues using this script
if you are attempting to withdraw multiple assets in a short span of time).
```
node ./withdraw_nft_l1.js {WITHDRAWAL_BLOCK_HEIGHT} 1
```
Check for the success of this transaction in the Clarinet console:
🟩 invoked: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.hyperchain::withdraw-nft-asset(u5, ST2JHG361ZXG51QTKY2NQCVBPPRRE2KZB1HR05...
You can also navigate to the Stacks Explorer (the URL of this will be listed in the Clarinet console), and check that the expected
principal now owns the NFT (`ALT_USER_ADDR`). You can check this by clicking on the transaction corresponding to
`withdraw-nft-asset`.
That is the conclusion of this demo! If you have any issues with this demo, reach out on the Stacks Discord or leave an issue in the
stacks-hyperchains repository.

View File

@@ -1,43 +0,0 @@
[node]
# working_dir = "/dir/to/save/chainstate"
rpc_bind = "127.0.0.1:20443"
p2p_bind = "127.0.0.1:20444"
seed = "0000000000000000000000000000000000000000000000000000000000000000"
local_peer_seed = "0000000000000000000000000000000000000000000000000000000000000000"
miner = true
use_test_genesis_chainstate = true
[burnchain]
commit_anchor_block_within = 10_000
chain = "bitcoin"
mode = "mocknet"
[[ustx_balance]]
# secret key = aaf57b4730f713cf942bc63f0801c4a62abe5a6ac8e3da10389f9ca3420b0dc701
address = "ST18F1AHKW194BWQ3CEFDPWVRARA79RBGFEWSDQR8"
amount = 100000000000000
[[ustx_balance]]
# secret key = 0916e2eb04b5702e0e946081829cee67d3bb76e1792af506646843db9252ff4101
# this is also a miner present in the sample hyperchains contract
address = "ST2GE6HSXT81X9X3ATQ14WPT49X915R8X7FVERMBP"
amount = 100000000000000
[[ustx_balance]]
# secret key = 374b6734eaff979818c5f1367331c685459b03b1a2053310906d1408dc928a0001
address = "STB2BWB0K5XZGS3FXVTG3TKS46CQVV66NAK3YVN8"
amount = 100000000000000
[[ustx_balance]]
address = "STSTW15D618BSZQB85R058DS46THH86YQQY6XCB7"
amount = 100000000000000
[[events_observer]]
endpoint = "localhost:49303"
retry_count = 255
events_keys = ["*"]
[[events_observer]]
endpoint = "localhost:47303"
retry_count = 255
events_keys = ["*"]

View File

@@ -0,0 +1,47 @@
import {
makeContractCall,
AnchorMode,
standardPrincipalCV,
uintCV,
contractPrincipalCV,
PostConditionMode,
broadcastTransaction,
} from '@stacks/transactions';
import { StacksTestnet, HIRO_MOCKNET_DEFAULT } from '@stacks/network';
async function main() {
const network = new StacksTestnet({url: HIRO_MOCKNET_DEFAULT});
const senderKey = process.env.USER_KEY;
const addr = process.env.USER_ADDR;
const nonce = parseInt(process.argv[2]);
const txOptions = {
contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
contractName: 'hc-alpha',
functionName: 'deposit-nft-asset',
functionArgs: [
uintCV(5), // ID
standardPrincipalCV(addr), // sender
contractPrincipalCV(addr, 'simple-nft-l1'), // contract ID of nft contract on L1
contractPrincipalCV(addr, 'simple-nft-l2'), // contract ID of nft contract on L2
],
senderKey,
validateWithAbi: false,
network,
anchorMode: AnchorMode.Any,
fee: 10000,
postConditionMode: PostConditionMode.Allow,
nonce
};
const transaction = await makeContractCall(txOptions);
const txid = await broadcastTransaction(
transaction, network
);
console.log(txid);
}
main()

View File

@@ -0,0 +1,39 @@
import {
makeContractCall,
AnchorMode,
standardPrincipalCV,
uintCV,
PostConditionMode
} from '@stacks/transactions';
import { StacksTestnet, HIRO_MOCKNET_DEFAULT } from '@stacks/network';
async function main() {
const network = new StacksTestnet({url: HIRO_MOCKNET_DEFAULT});
const senderKey = process.env.USER_KEY;
const addr = process.env.USER_ADDR;
const nonce = parseInt(process.argv[2]);
const txOptions = {
contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
contractName: 'hc-alpha',
functionName: 'deposit-stx',
functionArgs: [
uintCV(500_000_000_000), // ID
standardPrincipalCV(addr), // sender
],
senderKey,
validateWithAbi: false,
network,
anchorMode: AnchorMode.Any,
fee: 10000,
postConditionMode: PostConditionMode.Allow,
nonce,
};
const transaction = await makeContractCall(txOptions);
console.log(transaction.serialize().toString('hex'));
}
main()

View File

@@ -0,0 +1,39 @@
import {
makeContractCall,
AnchorMode,
standardPrincipalCV,
uintCV,
broadcastTransaction,
} from '@stacks/transactions';
import { StacksTestnet, HIRO_MOCKNET_DEFAULT } from '@stacks/network';
async function main() {
const network = new StacksTestnet({url: HIRO_MOCKNET_DEFAULT});
const senderKey = process.env.USER_KEY;
const addr = process.env.USER_ADDR;
const nonce = parseInt(process.argv[2]);
const txOptions = {
contractAddress: addr,
contractName: 'simple-nft-l1',
functionName: 'gift-nft',
functionArgs: [standardPrincipalCV(addr), uintCV(5)],
senderKey,
validateWithAbi: false,
network,
anchorMode: AnchorMode.Any,
fee: 10000,
nonce
};
const transaction = await makeContractCall(txOptions);
const txid = await broadcastTransaction(
transaction, network
);
console.log(txid);
}
main()

View File

@@ -0,0 +1,12 @@
{
"type": "module",
"dependencies": {
"@stacks/network": "^4.3.2",
"@stacks/transactions": "^4.3.3"
},
"name": "use-case-module",
"version": "1.0.0",
"author": "Hiro PBC",
"license": "ISC",
"description": "Package for running NFT use case"
}

View File

@@ -0,0 +1,33 @@
import {
AnchorMode,
makeContractDeploy,
broadcastTransaction,
} from '@stacks/transactions';
import { StacksTestnet, HIRO_MOCKNET_DEFAULT } from '@stacks/network';
import { readFileSync } from 'fs';
async function main() {
const contractName = process.argv[2];
const contractFilename = process.argv[3];
const networkLayer = parseInt(process.argv[4]);
const nonce = parseInt(process.argv[5]);
const senderKey = process.env.USER_KEY;
const networkUrl = networkLayer == 2 ? process.env.HYPERCHAIN_URL : HIRO_MOCKNET_DEFAULT ;
const codeBody = readFileSync(contractFilename, { encoding: 'utf-8' });
const transaction = await makeContractDeploy({
codeBody, contractName, senderKey, network: new StacksTestnet({url: networkUrl}),
anchorMode: AnchorMode.Any, fee: 10000, nonce
});
const txid = await broadcastTransaction(
transaction, new StacksTestnet({url: networkUrl})
);
console.log(txid);
}
main()

View File

@@ -0,0 +1,39 @@
import {
makeContractCall,
AnchorMode,
contractPrincipalCV,
stringAsciiCV,
broadcastTransaction,
} from '@stacks/transactions';
import { StacksTestnet, HIRO_MOCKNET_DEFAULT } from '@stacks/network';
async function main() {
const network = new StacksTestnet({url: HIRO_MOCKNET_DEFAULT});
const senderKey = process.env.AUTH_HC_MINER_KEY;
const userAddr = process.env.USER_ADDR;
const nonce = parseInt(process.argv[2]);
const txOptions = {
contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
contractName: 'hc-alpha',
functionName: 'register-new-nft-contract',
functionArgs: [contractPrincipalCV(userAddr, 'simple-nft-l1'), stringAsciiCV("hyperchain-deposit-nft-token")],
senderKey,
validateWithAbi: false,
network,
anchorMode: AnchorMode.Any,
fee: 10000,
nonce,
};
const transaction = await makeContractCall(txOptions);
const txid = await broadcastTransaction(
transaction, network
);
console.log(txid);
}
main()

View File

@@ -0,0 +1,46 @@
import {
makeContractCall,
AnchorMode,
standardPrincipalCV,
uintCV,
PostConditionMode,
broadcastTransaction,
} from '@stacks/transactions';
import { StacksTestnet } from '@stacks/network';
async function main() {
const network = new StacksTestnet({url: process.env.HYPERCHAIN_URL});
const senderKey = process.env.USER_KEY;
const addr = process.env.USER_ADDR;
const alt_addr = process.env.ALT_USER_ADDR;
const nonce = parseInt(process.argv[2]);
const txOptions = {
contractAddress: addr,
contractName: 'simple-nft-l2',
functionName: 'transfer',
functionArgs: [
uintCV(5), // ID
standardPrincipalCV(addr), // sender
standardPrincipalCV(alt_addr), // recipient
],
senderKey,
validateWithAbi: false,
network,
anchorMode: AnchorMode.Any,
fee: 10000,
nonce,
postConditionMode: PostConditionMode.Allow
};
const transaction = await makeContractCall(txOptions);
const txid = await broadcastTransaction(
transaction, network
);
console.log(txid);
}
main()

View File

@@ -0,0 +1,60 @@
import {
makeContractCall,
deserializeCV,
AnchorMode,
standardPrincipalCV,
uintCV,
PostConditionMode,
contractPrincipalCV,
broadcastTransaction,
} from '@stacks/transactions';
import { StacksTestnet, HIRO_MOCKNET_DEFAULT } from '@stacks/network';
async function main() {
const network = new StacksTestnet({url: HIRO_MOCKNET_DEFAULT});
const hyperchainUrl = process.env.HYPERCHAIN_URL;
const senderKey = process.env.AUTH_HC_MINER_KEY;
const addr = process.env.ALT_USER_ADDR;
const contractAddr = process.env.USER_ADDR;
const withdrawalBlockHeight = process.argv[2];
const nonce = parseInt(process.argv[3]);
let json_merkle_entry = await fetch(`${hyperchainUrl}/v2/withdrawal/nft/${withdrawalBlockHeight}/${addr}/0/${contractAddr}/simple-nft-l2/nft-token/5`).then(x => x.json())
let cv_merkle_entry = {
withdrawal_leaf_hash: deserializeCV(json_merkle_entry.withdrawal_leaf_hash),
withdrawal_root: deserializeCV(json_merkle_entry.withdrawal_root),
sibling_hashes: deserializeCV(json_merkle_entry.sibling_hashes),
};
const txOptions = {
senderKey,
network,
anchorMode: AnchorMode.Any,
contractAddress: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM",
contractName: "hc-alpha",
functionName: "withdraw-nft-asset",
functionArgs: [
uintCV(5), // ID
standardPrincipalCV(addr), // recipient
contractPrincipalCV(contractAddr, 'simple-nft-l1'), // nft-contract
contractPrincipalCV(contractAddr, 'simple-nft-l1'), // nft-mint-contract
cv_merkle_entry.withdrawal_root, // withdrawal root
cv_merkle_entry.withdrawal_leaf_hash, // withdrawal leaf hash
cv_merkle_entry.sibling_hashes ], // sibling hashes
fee: 10000,
postConditionMode: PostConditionMode.Allow,
nonce,
}
const transaction = await makeContractCall(txOptions);
const txid = await broadcastTransaction(
transaction, network
);
console.log(txid);
}
main()

View File

@@ -0,0 +1,45 @@
import {
makeContractCall,
AnchorMode,
standardPrincipalCV,
uintCV,
broadcastTransaction,
PostConditionMode
} from '@stacks/transactions';
import { StacksTestnet } from '@stacks/network';
async function main() {
const network = new StacksTestnet({url: process.env.HYPERCHAIN_URL});
const senderKey = process.env.ALT_USER_KEY;
const contractAddr = process.env.USER_ADDR;
const addr = process.env.ALT_USER_ADDR;
const nonce = parseInt(process.argv[2]);
const txOptions = {
contractAddress: contractAddr,
contractName: 'simple-nft-l2',
functionName: 'withdraw-nft-asset',
functionArgs: [
uintCV(5), // ID
standardPrincipalCV(addr), // recipient
],
senderKey,
validateWithAbi: false,
network,
anchorMode: AnchorMode.Any,
fee: 10000,
nonce,
postConditionMode: PostConditionMode.Allow,
};
const transaction = await makeContractCall(txOptions);
const txid = await broadcastTransaction(
transaction, network
);
console.log(txid);
}
main()

View File

@@ -20,7 +20,7 @@
)
(define-read-only (get-token-uri (id uint))
(ok "unimplemented")
(ok (some "unimplemented"))
)
(define-public (transfer (id uint) (sender principal) (recipient principal))