Skip to content

Commit 986a64d

Browse files
committed
feat: add sbtc contract and initialization
1 parent e34ca57 commit 986a64d

File tree

9 files changed

+332
-52
lines changed

9 files changed

+332
-52
lines changed

Clarinet.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ cache_dir = './.cache'
99
contract_id = 'SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard'
1010

1111
[[project.requirements]]
12-
contract_id = "SP126XFZQ3ZHYM6Q6KAQZMMJSDY91A8BTT6AD08RV.stackflow-token-0-6-0.stackflow-token"
12+
contract_id = "SP126XFZQ3ZHYM6Q6KAQZMMJSDY91A8BTT6AD08RV.stackflow-token-0-6-0"
13+
14+
[[project.requirements]]
15+
contract_id = "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-deposit"
1316

1417
[contracts.reservoir]
1518
path = 'contracts/reservoir.clar'
@@ -21,6 +24,11 @@ path = 'contracts/stackflow.clar'
2124
clarity_version = 4
2225
epoch = "3.3"
2326

27+
[contracts.stackflow-sbtc]
28+
path = 'contracts/stackflow.clar'
29+
clarity_version = 4
30+
epoch = "3.3"
31+
2432
[contracts.stackflow-token]
2533
path = 'contracts/stackflow-token.clar'
2634
clarity_version = 4

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,15 @@ For Clarinet devnet, set the observer in `settings/Devnet.toml`:
519519
stacks_node_events_observers = ["host.docker.internal:8787"]
520520
```
521521

522+
Devnet contracts and initialization plan:
523+
524+
1. deployment plan: `deployments/default.devnet-plan.yaml` (publishes `stackflow` and `stackflow-sbtc`)
525+
2. the same devnet plan also runs post-deploy `init` contract calls:
526+
- `stackflow` with `none` token (STX mode)
527+
- `stackflow-sbtc` with `ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sbtc-token`
528+
3. optional/manual fallback: `./init-stackflow.sh`
529+
4. full plan details: `deployments/DEVNET_STACKFLOW_SBTC_PLAN.md`
530+
522531
Open the built-in UI in your browser:
523532

524533
```text
@@ -601,7 +610,9 @@ It includes forms/buttons for:
601610
4. `force-cancel`
602611
5. structured transfer message signing + payload JSON builder
603612
6. principal resolution for `.btc` names (for example `brice.btc`) via BNSv2 API
604-
7. preset Stackflow contract selection with token auto-fill for official STX/sBTC mainnet contracts
613+
7. network-aware preset Stackflow contract selection with token auto-fill:
614+
- devnet: `ST1...stackflow` and `ST1...stackflow-sbtc`
615+
- mainnet: official `stackflow-0-6-0` and `stackflow-sbtc-0-6-0`
605616

606617
To publish with GitHub Pages (no build step):
607618

deployments/default.devnet-plan.yaml

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,41 @@ plan:
1818
epoch: '2.0'
1919
- id: 1
2020
transactions:
21+
- transaction-type: requirement-publish
22+
contract-id: SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-registry
23+
remap-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
24+
remap-principals:
25+
SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
26+
cost: 112090
27+
path: .cache/requirements/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-registry.clar
28+
clarity-version: 3
29+
- transaction-type: requirement-publish
30+
contract-id: SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
31+
remap-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
32+
remap-principals:
33+
SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
34+
cost: 47590
35+
path: .cache/requirements/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token.clar
36+
clarity-version: 3
37+
- transaction-type: requirement-publish
38+
contract-id: SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-deposit
39+
remap-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
40+
remap-principals:
41+
SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
42+
cost: 41510
43+
path: .cache/requirements/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-deposit.clar
44+
clarity-version: 3
45+
epoch: '3.0'
46+
- id: 2
47+
transactions:
48+
- transaction-type: requirement-publish
49+
contract-id: SP126XFZQ3ZHYM6Q6KAQZMMJSDY91A8BTT6AD08RV.stackflow-token-0-6-0
50+
remap-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
51+
remap-principals:
52+
SP126XFZQ3ZHYM6Q6KAQZMMJSDY91A8BTT6AD08RV: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
53+
cost: 43920
54+
path: .cache/requirements/SP126XFZQ3ZHYM6Q6KAQZMMJSDY91A8BTT6AD08RV.stackflow-token-0-6-0.clar
55+
clarity-version: 4
2156
- transaction-type: contract-publish
2257
contract-name: stackflow-token
2358
expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
@@ -35,7 +70,14 @@ plan:
3570
- transaction-type: contract-publish
3671
contract-name: stackflow
3772
expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
38-
cost: 520800
73+
cost: 519850
74+
path: contracts/stackflow.clar
75+
anchor-block-only: true
76+
clarity-version: 4
77+
- transaction-type: contract-publish
78+
contract-name: stackflow-sbtc
79+
expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
80+
cost: 519850
3981
path: contracts/stackflow.clar
4082
anchor-block-only: true
4183
clarity-version: 4
@@ -46,4 +88,20 @@ plan:
4688
path: contracts/test-token.clar
4789
anchor-block-only: true
4890
clarity-version: 4
91+
- id: 3
92+
transactions:
93+
- transaction-type: contract-call
94+
contract-id: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.stackflow
95+
expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
96+
method: init
97+
parameters:
98+
- none
99+
cost: 10000
100+
- transaction-type: contract-call
101+
contract-id: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.stackflow-sbtc
102+
expected-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
103+
method: init
104+
parameters:
105+
- "(some 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sbtc-token)"
106+
cost: 10000
49107
epoch: '3.3'

deployments/default.simnet-plan.yaml

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,34 @@ plan:
6565
- transaction-type: emulated-contract-publish
6666
contract-name: sip-010-trait-ft-standard
6767
emulated-sender: SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE
68-
path: ./.cache/requirements/SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.clar
68+
path: .cache/requirements/SP3FBR2AGK5H9QBDH3EEN6DF8EK8JY7RX8QJ5SVTE.sip-010-trait-ft-standard.clar
6969
clarity-version: 1
7070
epoch: '2.0'
7171
- id: 1
7272
transactions:
73+
- transaction-type: emulated-contract-publish
74+
contract-name: sbtc-registry
75+
emulated-sender: SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4
76+
path: .cache/requirements/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-registry.clar
77+
clarity-version: 3
78+
- transaction-type: emulated-contract-publish
79+
contract-name: sbtc-token
80+
emulated-sender: SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4
81+
path: .cache/requirements/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token.clar
82+
clarity-version: 3
83+
- transaction-type: emulated-contract-publish
84+
contract-name: sbtc-deposit
85+
emulated-sender: SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4
86+
path: .cache/requirements/SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-deposit.clar
87+
clarity-version: 3
88+
epoch: '3.0'
89+
- id: 2
90+
transactions:
91+
- transaction-type: emulated-contract-publish
92+
contract-name: stackflow-token-0-6-0
93+
emulated-sender: SP126XFZQ3ZHYM6Q6KAQZMMJSDY91A8BTT6AD08RV
94+
path: .cache/requirements/SP126XFZQ3ZHYM6Q6KAQZMMJSDY91A8BTT6AD08RV.stackflow-token-0-6-0.clar
95+
clarity-version: 4
7396
- transaction-type: emulated-contract-publish
7497
contract-name: stackflow-token
7598
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
@@ -85,6 +108,11 @@ plan:
85108
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
86109
path: contracts/stackflow.clar
87110
clarity-version: 4
111+
- transaction-type: emulated-contract-publish
112+
contract-name: stackflow-sbtc
113+
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM
114+
path: contracts/stackflow.clar
115+
clarity-version: 4
88116
- transaction-type: emulated-contract-publish
89117
contract-name: test-token
90118
emulated-sender: ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM

docs/app.js

Lines changed: 98 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,49 @@ const DEFAULT_API_BY_NETWORK = {
2222

2323
const STACKFLOW_MESSAGE_VERSION = "0.6.0";
2424
const BNSV2_API_BASE = "https://api.bnsv2.com";
25-
const CONTRACT_PRESETS = {
26-
"stx-mainnet": {
27-
contractId: "SP126XFZQ3ZHYM6Q6KAQZMMJSDY91A8BTT6AD08RV.stackflow-0-6-0",
28-
tokenContract: "",
29-
},
30-
"sbtc-mainnet": {
31-
contractId: "SP126XFZQ3ZHYM6Q6KAQZMMJSDY91A8BTT6AD08RV.stackflow-sbtc-0-6-0",
32-
tokenContract: "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token",
33-
},
25+
const CONTRACT_PRESETS_BY_NETWORK = {
26+
devnet: [
27+
{
28+
key: "stx-devnet",
29+
label: "STX (devnet default)",
30+
contractId: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.stackflow",
31+
tokenContract: "",
32+
},
33+
{
34+
key: "sbtc-devnet",
35+
label: "sBTC (devnet default)",
36+
contractId: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.stackflow-sbtc",
37+
tokenContract: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.test-token",
38+
},
39+
],
40+
testnet: [
41+
{
42+
key: "stx-testnet",
43+
label: "STX (testnet default)",
44+
contractId: "ST126XFZQ3ZHYM6Q6KAQZMMJSDY91A8BTT59ZTE2J.stackflow-0-6-0",
45+
tokenContract: "",
46+
},
47+
{
48+
key: "sbtc-testnet",
49+
label: "sBTC (testnet default)",
50+
contractId: "ST126XFZQ3ZHYM6Q6KAQZMMJSDY91A8BTT59ZTE2J.stackflow-sbtc-0-6-0",
51+
tokenContract: "",
52+
},
53+
],
54+
mainnet: [
55+
{
56+
key: "stx-mainnet",
57+
label: "STX (mainnet default)",
58+
contractId: "SP126XFZQ3ZHYM6Q6KAQZMMJSDY91A8BTT6AD08RV.stackflow-0-6-0",
59+
tokenContract: "",
60+
},
61+
{
62+
key: "sbtc-mainnet",
63+
label: "sBTC (mainnet default)",
64+
contractId: "SP126XFZQ3ZHYM6Q6KAQZMMJSDY91A8BTT6AD08RV.stackflow-sbtc-0-6-0",
65+
tokenContract: "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token",
66+
},
67+
],
3468
};
3569

3670
const elements = {
@@ -482,22 +516,46 @@ function updateNetworkDefaults() {
482516
}
483517
}
484518

485-
function getPresetKeyByValues(contractId, tokenContract) {
519+
function getPresetsForNetwork(network = readNetwork()) {
520+
return CONTRACT_PRESETS_BY_NETWORK[network] || [];
521+
}
522+
523+
function findPresetByKey(presetKey, network = readNetwork()) {
524+
return getPresetsForNetwork(network).find((preset) => preset.key === presetKey) || null;
525+
}
526+
527+
function renderPresetOptions(network = readNetwork()) {
528+
const presets = getPresetsForNetwork(network);
529+
const selected = normalizedText(elements.contractPreset.value) || "custom";
530+
const options = [
531+
...presets.map((preset) => `<option value="${preset.key}">${preset.label}</option>`),
532+
'<option value="custom">Custom (manual)</option>',
533+
];
534+
elements.contractPreset.innerHTML = options.join("");
535+
536+
if (presets.some((preset) => preset.key === selected) || selected === "custom") {
537+
elements.contractPreset.value = selected;
538+
} else {
539+
elements.contractPreset.value = "custom";
540+
}
541+
}
542+
543+
function getPresetKeyByValues(contractId, tokenContract, network = readNetwork()) {
486544
const contractText = normalizedText(contractId);
487545
const tokenText = normalizedText(tokenContract);
488-
for (const [presetKey, preset] of Object.entries(CONTRACT_PRESETS)) {
546+
for (const preset of getPresetsForNetwork(network)) {
489547
if (
490548
normalizedText(preset.contractId) === contractText &&
491549
normalizedText(preset.tokenContract) === tokenText
492550
) {
493-
return presetKey;
551+
return preset.key;
494552
}
495553
}
496554
return "custom";
497555
}
498556

499557
function applyContractPreset(presetKey, { log = true } = {}) {
500-
const preset = CONTRACT_PRESETS[presetKey];
558+
const preset = findPresetByKey(presetKey);
501559
if (!preset) {
502560
return;
503561
}
@@ -821,10 +879,28 @@ function wireEvents() {
821879
elements.buildPayload.addEventListener("click", handleBuildPayload);
822880
elements.copyOutput.addEventListener("click", handleCopyOutput);
823881
elements.network.addEventListener("change", () => {
882+
const previousPresetKey = elements.contractPreset.value;
824883
elements.stacksApiUrl.value = DEFAULT_API_BY_NETWORK[readNetwork()];
884+
renderPresetOptions();
885+
if (previousPresetKey !== "custom") {
886+
const presets = getPresetsForNetwork();
887+
if (presets.length > 0) {
888+
elements.contractPreset.value = presets[0].key;
889+
applyContractPreset(presets[0].key);
890+
}
891+
return;
892+
}
893+
elements.contractPreset.value = getPresetKeyByValues(
894+
elements.contractId.value,
895+
elements.tokenContract.value,
896+
);
825897
});
826898
elements.contractPreset.addEventListener("change", () => {
827-
applyContractPreset(elements.contractPreset.value);
899+
const presetKey = elements.contractPreset.value;
900+
if (presetKey === "custom") {
901+
return;
902+
}
903+
applyContractPreset(presetKey);
828904
});
829905
elements.contractId.addEventListener("input", () => {
830906
elements.contractPreset.value = getPresetKeyByValues(
@@ -843,9 +919,15 @@ function wireEvents() {
843919
async function bootstrap() {
844920
wireEvents();
845921
updateNetworkDefaults();
922+
renderPresetOptions();
846923
if (!normalizedText(elements.contractId.value) && !normalizedText(elements.tokenContract.value)) {
847-
elements.contractPreset.value = "stx-mainnet";
848-
applyContractPreset("stx-mainnet", { log: false });
924+
const presets = getPresetsForNetwork();
925+
if (presets.length > 0) {
926+
elements.contractPreset.value = presets[0].key;
927+
applyContractPreset(presets[0].key, { log: false });
928+
} else {
929+
elements.contractPreset.value = "custom";
930+
}
849931
} else {
850932
elements.contractPreset.value = getPresetKeyByValues(
851933
elements.contractId.value,

docs/index.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ <h2>Config</h2>
3939
<label>
4040
Contract Preset
4141
<select id="contract-preset">
42-
<option value="stx-mainnet">STX (mainnet default)</option>
43-
<option value="sbtc-mainnet">sBTC (mainnet default)</option>
4442
<option value="custom">Custom (manual)</option>
4543
</select>
4644
</label>

init-stackflow.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,8 @@ set -euo pipefail
88

99
STACKS_NETWORK="${STACKS_NETWORK:-devnet}" \
1010
STACKS_API_URL="${STACKS_API_URL:-http://localhost:3999}" \
11+
STACKFLOW_INIT_MODE="${STACKFLOW_INIT_MODE:-devnet-both}" \
1112
STACKFLOW_CONTRACT_ID="${STACKFLOW_CONTRACT_ID:-ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.stackflow}" \
13+
STACKFLOW_SBTC_CONTRACT_ID="${STACKFLOW_SBTC_CONTRACT_ID:-ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.stackflow-sbtc}" \
14+
STACKFLOW_SBTC_TOKEN_CONTRACT_ID="${STACKFLOW_SBTC_TOKEN_CONTRACT_ID:-ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.test-token}" \
1215
npm run init:stackflow

scripts/deploy.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ const CONTRACTS = [
4747
kind: "stackflow",
4848
file: "../contracts/stackflow.clar",
4949
},
50+
{
51+
name: `stackflow-sbtc-${VERSION_TAG}`,
52+
kind: "stackflow",
53+
file: "../contracts/stackflow.clar",
54+
},
5055
{
5156
name: `reservoir-${VERSION_TAG}`,
5257
kind: "reservoir",

0 commit comments

Comments
 (0)