Skip to content

Commit b029f0f

Browse files
eric-stacksgitbook-bot
authored andcommitted
GITBOOK-65: add withdrawal flow to usdcx guide
1 parent cac2b2d commit b029f0f

File tree

3 files changed

+125
-56
lines changed

3 files changed

+125
-56
lines changed

docs/build/README.md

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -33,64 +33,44 @@ If you're here on this page, hopefully you've already gotten a good sense of _wh
3333

3434
The Stacks documentation is organized into a set of top-level sections, each aligned to a distinct stage of a developer’s journey—from learning core concepts to building applications and operating infrastructure.
3535

36-
<details>
37-
38-
<summary><strong>Learn</strong></summary>
39-
40-
**How does the Stacks network work?**\
41-
The [Learn](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/) section focuses on building a strong conceptual foundation. It explains how Stacks functions as a Bitcoin layer 2, providing clarity and context around the network’s design and mechanics.
36+
{% tabs %}
37+
{% tab title="Learn" %}
38+
**How does the Stacks network&#x20;**_**actually**_**&#x20;work?**\
39+
The [Learn](https://app.gitbook.com/s/H74xqoobupBWwBsVMJhK/) section focuses on building a strong academic foundation. It explains how Stacks functions as a Bitcoin layer 2, providing clarity and context around the network’s design and mechanics.
4240

4341
Topics include Proof of Transfer (PoX), Bitcoin finality, block production, the transaction lifecycle, and more. If you want a deep understanding of how Stacks anchors to Bitcoin and why it works the way it does, this is the best place to start.
42+
{% endtab %}
4443

45-
</details>
46-
47-
<details>
48-
49-
<summary><strong>Build</strong></summary>
50-
44+
{% tab title="Build" %}
5145
**How do you build on Stacks?**\
52-
The Build section (you're on it!) is for developers—both new and experienced—who want to start writing, deploying, and interacting with Stacks applications.
46+
This section is for experienced developers, but are new to Stacks, who are in the exploratory phase of understanding the general workflow of building apps on Stacks. These guides focus on accomplishing specific tasks—writing contracts, integrating wallets, working with sBTC or USDC—without extensive explainers.
5347

5448
It includes curated quick starts for smart contract development with Clarinet and frontend development with Stacks.js, along with step-by-step guides covering common use cases such as integrating sBTC, onboarding users, working with price oracles, and more.
49+
{% endtab %}
5550

56-
If you’re new to building on Stacks, this section provides a practical, hands-on introduction to the ecosystem.
57-
58-
</details>
59-
60-
<details>
61-
62-
<summary><strong>Operate</strong></summary>
63-
51+
{% tab title="Operate" %}
6452
**How do you run Stacks infrastructure?**\
6553
The [Operate](https://app.gitbook.com/s/4cpTb2lbw0LAOuMHrvhA/) section is designed for node operators and infrastructure providers. It covers how to run and manage Stacks nodes, signers, and miners.
6654

6755
If you’re responsible for operating or maintaining Stacks-related infrastructure, this section contains the resources you’ll need.
56+
{% endtab %}
6857

69-
</details>
70-
71-
<details>
72-
73-
<summary><strong>Reference</strong></summary>
74-
58+
{% tab title="Reference" %}
7559
**Where do you look up technical details?**\
7660
The [Reference](https://app.gitbook.com/s/GVj1Z9vMuEOMe7oH7Wnq/node-operations/readme) section contains authoritative technical documentation for Stacks devtools and APIs. This includes function and type definitions for Clarity and Stacks.js, API endpoint schemas, and interactive API playgrounds.
7761

7862
If you’re an experienced Stacks developer looking to quickly reference a specific method, type, or API response, this section is built for fast lookup and precision.
63+
{% endtab %}
7964

80-
</details>
81-
82-
<details>
83-
84-
<summary><strong>Tutorials</strong></summary>
85-
86-
**Looking for a more guided, learning-first experience?**\
87-
The [Tutorials](https://app.gitbook.com/s/skGYu79qDNfITOqDNU3s/) section is designed for readers who want structured, long-form lessons rather than quick answers.
65+
{% tab title="Tutorials" %}
66+
**Looking for a more guided, lesson-oriented experience?**\
67+
The [Tutorials](https://app.gitbook.com/s/skGYu79qDNfITOqDNU3s/) section is designed for complete beginner developers who want structured, long-form lessons rather than quick answers.
8868

8969
These tutorials provide step-by-step walkthroughs alongside in-depth explanations of the underlying concepts. The goal isn’t just to help you complete a task, but to help you understand _why_ things work the way they do as you build.
9070

91-
If you’re completely new to Stacks—or prefer a classroom-style, concept-driven learning experience—this section is the best place to start.
92-
93-
</details>
71+
If you’re a complete beginner and prefer a classroom-style, concept-driven learning experience—this section is the best place to start.
72+
{% endtab %}
73+
{% endtabs %}
9474

9575
***
9676

docs/build/more-guides/bridging-usdcx.md

Lines changed: 106 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,49 +25,58 @@ Current work is underway to abstract this entire flow via Circle's Bridge Kit SD
2525
5. Approve xReserve as a spender of your USDC.
2626
6. Execute deposit to the remote chain Stacks.
2727

28+
**Withdrawal**
29+
30+
1. Prepare contract call arguments
31+
2. Invoke `burn` function from the `.usdcx-v1` contract
32+
2833
### Key Tools To Use
2934

3035
* [viem](https://viem.sh/) - A Typescript-first library that interfaces with Ethereum.
3136
* [stacks.js](/broken/pages/dH5waQhE6Vb7rhcrUG7z) - A js library that helps developers build Stacks apps by handling transactions, wallet authentication, and smart contract interactions.
37+
* [Circle Faucet](https://faucet.circle.com/) - Get testnet USDC
38+
* [Ethereum Sepolia faucet](https://cloud.google.com/application/web3/faucet/ethereum/sepolia) - Get testnet ETH
3239

3340
***
3441

3542
## Complete Code
3643

3744
If you want to jump straight to the full implementation, the complete working code used in this guide is shown below.
3845

39-
#### Deposit
40-
4146
{% tabs %}
4247
{% tab title="index.ts" %}
4348
This script bridges USDC from Ethereum Sepolia testnet to Stacks testnet by first approving the xReserve contract to spend USDC, then calling `depositToRemote` to initiate the cross-chain transfer. It encodes the Stacks recipient address into the bytes32 format required by the Ethereum contract and submits both transactions to the Sepolia network. The Stacks attestation service will receive this event and mint the equivalent amount to the specified Stacks address.
4449

45-
{% code expandable="true" %}
46-
```typescript
47-
import "dotenv/config";
50+
<pre class="language-typescript" data-expandable="true"><code class="lang-typescript">import "dotenv/config";
4851
import {
4952
createWalletClient,
5053
createPublicClient,
5154
http,
5255
parseUnits,
56+
pad
5357
} from "viem";
5458
import { privateKeyToAccount } from "viem/accounts";
5559
import { sepolia } from "viem/chains";
5660
import { bytes32FromBytes, remoteRecipientCoder } from "./helpers";
61+
import { makeContractCall, Cl, Pc, broadcastTransaction } from '@stacks/transactions'
5762

5863
// ============ Configuration constants ============
5964
const config = {
6065
// Public Ethereum Sepolia RPC and your private wallet key
6166
ETH_RPC_URL: process.env.RPC_URL || "https://ethereum-sepolia.publicnode.com",
62-
PRIVATE_KEY: process.env.PRIVATE_KEY,
67+
PRIVATE_KEY: process.env.ETHEREUM_PRIVATE_KEY,
6368

6469
// Contract addresses on testnet
6570
X_RESERVE_CONTRACT: "008888878f94C0d87defdf0B07f46B93C1934442",
6671
ETH_USDC_CONTRACT: "1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
72+
STACKS_USDC:
73+
"0x00000000061a6d78de7b0625dfbfc16c3a8a5735f6dc3dc3f2ce057573646378",
6774

6875
// Deposit parameters for Stacks
6976
STACKS_DOMAIN: 10003, // Stacks domain ID
77+
ETHEREUM_DOMAIN: 0, // Ethereum domain ID
7078
STACKS_RECIPIENT: "ST1F1M4YP67NV360FBYR28V7C599AC46F8C4635SH", // Address to receive minted USDCx on Stacks
79+
ETHEREUM_RECIPIENT: "9F685cc614148f35efC238F5DFC977e08ed6bA86", // Address to receive withdrawn USDC on Ethereum
7180
DEPOSIT_AMOUNT: "1.00",
7281
MAX_FEE: "0",
7382
};
@@ -111,8 +120,8 @@ const ERC20_ABI = [
111120
];
112121

113122

114-
async function main() {
115-
if (!config.PRIVATE_KEY) {
123+
<strong>async function deposit() {
124+
</strong> if (!config.PRIVATE_KEY) {
116125
throw new Error("PRIVATE_KEY must be set in your .env file");
117126
}
118127

@@ -165,7 +174,7 @@ async function main() {
165174
Number(usdcBalance) / 1e6
166175
).toFixed(6)} USDC)`,
167176
);
168-
if (usdcBalance < value) {
177+
if (usdcBalance &#x3C; value) {
169178
throw new Error(
170179
`Insufficient USDC balance. Required: ${(Number(value) / 1e6).toFixed(
171180
6,
@@ -207,13 +216,33 @@ async function main() {
207216
);
208217
}
209218

210-
// ============ Call the main function ============
211-
main().catch((error) => {
212-
console.error("❌ Error:", error);
213-
process.exit(1);
214-
});
215-
```
216-
{% endcode %}
219+
<strong>async function withdraw() {
220+
</strong> let amount = 4800000 // in micro USDCx (6 decimals)
221+
222+
let functionArgs = [
223+
Cl.uint(amount), // amount in micro USDC
224+
Cl.uint(config.ETHEREUM_DOMAIN), // native domain for Ethereum
225+
Cl.bufferFromHex(pad(`0x${config.ETHEREUM_RECIPIENT}`, { size: 32 })) // native recipient
226+
]
227+
228+
let postCondition_1 = Pc.principal(config.STACKS_RECIPIENT)
229+
.willSendEq(amount)
230+
.ft('ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.usdcx', 'usdcx-token')
231+
232+
let transaction = await makeContractCall({
233+
contractName: 'usdcx-v1',
234+
contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
235+
functionName: 'burn',
236+
functionArgs,
237+
network: 'testnet',
238+
postConditions: [postCondition_1],
239+
postConditionMode: 'deny',
240+
senderKey: process.env.STACKS_PRIVATE_KEY,
241+
})
242+
243+
let result = await broadcastTransaction({transaction, network: 'testnet'})
244+
}
245+
</code></pre>
217246
{% endtab %}
218247

219248
{% tab title="helpers.ts" %}
@@ -275,8 +304,6 @@ Before beginning, make sure you:
275304

276305
* Create a wallet on Ethereum Sepolia.
277306
* Create a Stacks testnet wallet.
278-
* Get testnet USDC from the [Circle Faucet](https://faucet.circle.com/).
279-
* Get testnet ETH from a public [Ethereum Sepolia faucet](https://cloud.google.com/application/web3/faucet/ethereum/sepolia).
280307

281308
{% stepper %}
282309
{% step %}
@@ -590,3 +617,64 @@ These are example transactions on testnet:
590617
* Stacks: [Minting USDCx](https://explorer.hiro.so/txid/0x12ad17401bf89d1bb1489623203b489b059609187eae2c5cebb898a89bdb926f?chain=testnet\&tab=overview)
591618
{% endstep %}
592619
{% endstepper %}
620+
621+
***
622+
623+
## Walkthrough (Withdrawal)
624+
625+
{% hint style="danger" %}
626+
**Limit:** Up to **50 burn intents per request** (max **10 per batch**, max **5 batches**). Submitting more than 50 intents in a single transaction request may lead to failed processing and **risk of fund loss**.
627+
{% endhint %}
628+
629+
{% stepper %}
630+
{% step %}
631+
### Prepare contract call arguments
632+
633+
Before invoking the `burn` function of the `.usdcx-v1` contract, you'll need to determine the amount of USDCx to withdraw and the native recipient address that'll receive the USDC on the other chain.
634+
635+
An Ethereum address is technically only 20 bytes but the `native-recipient` needs to be a 32 byte buffer. Pad left the address to 32 bytes.
636+
637+
```typescript
638+
let amount = 4800000 // in micro USDCx (6 decimals)
639+
640+
let functionArgs = [
641+
Cl.uint(amount), // amount in micro USDC
642+
Cl.uint(config.ETHEREUM_DOMAIN), // native domain for Ethereum
643+
Cl.bufferFromHex(pad(`0x${config.ETHEREUM_RECIPIENT}`, { size: 32 })) // native recipient
644+
]
645+
646+
let postCondition_1 = Pc.principal(config.STACKS_RECIPIENT)
647+
.willSendEq(amount)
648+
.ft('ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.usdcx', 'usdcx-token')
649+
```
650+
{% endstep %}
651+
652+
{% step %}
653+
### Execute withdrawal
654+
655+
Prepare the contract call transaction to invoke the `burn` function and broadcast the transaction payload.
656+
657+
```typescript
658+
let transaction = await makeContractCall({
659+
contractName: 'usdcx-v1',
660+
contractAddress: 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM',
661+
functionName: 'burn',
662+
functionArgs,
663+
network: 'testnet',
664+
postConditions: [postCondition_1],
665+
postConditionMode: 'deny',
666+
senderKey: process.env.STACKS_PRIVATE_KEY,
667+
})
668+
669+
let result = await broadcastTransaction({transaction, network: 'testnet'})
670+
```
671+
672+
The Stacks network's attestation service passes the burn intent message and signature to xReserve, managed by Circle. xReserve verifies the burn and issues a withdrawal attestation to release USDC to the user’s wallet.
673+
{% endstep %}
674+
{% endstepper %}
675+
676+
***
677+
678+
## Additional Resources
679+
680+
* \[[StacksDevs Livestream](https://x.com/StacksDevs/status/2011817589782249600)] A technical breakdown by the main builder behind Stacks' USDCx

docs/build/more-guides/c32check.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
description: Generating and decoding addresses on the Stacks blockchain.
3+
hidden: true
34
---
45

56
# c32check

0 commit comments

Comments
 (0)