Skip to content

Commit 9c5bed0

Browse files
authored
Add support for Cadence import aliasing (#2698)
* Create tests * Add logic for import aliasing * Add comment * Add import aliasing to config pkg * Add changeset * Add comments * Move and add to readme --------- Co-authored-by: Chase Fleming <1666730+chasefleming@users.noreply.github.com>
1 parent 3bf3490 commit 9c5bed0

File tree

7 files changed

+656
-150
lines changed

7 files changed

+656
-150
lines changed

.changeset/witty-beans-make.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@onflow/config": patch
3+
"@onflow/sdk": patch
4+
---
5+
6+
Add support for Cadence import aliasing

packages/config/README.md

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
# @onflow/config
2+
3+
Reactive configuration for Flow JS SDK and FCL
4+
5+
## Installation
6+
7+
```bash
8+
npm install @onflow/config
9+
```
10+
11+
## Usage
12+
13+
```javascript
14+
import {config} from "@onflow/sdk"
15+
16+
// Reactively subscribe to config changes
17+
config().subscribe(configData => console.log("CONFIG", configData))
18+
19+
// Set a config value
20+
config().put("foo", "bar")
21+
22+
// .put can be chained
23+
config()
24+
.put("foo", "bar")
25+
.put("baz", "rawr")
26+
27+
// Get a config value (it's async)
28+
var configValue = await config().get("woot")
29+
console.log(configValue) // undefined
30+
31+
// A fallback can be supplied for .get
32+
var configValue = await config().get("woot", "fallback")
33+
console.log(configValue) // "fallback"
34+
35+
config.put("woot", "woot")
36+
var configValue = await config().get("woot", "fallback")
37+
console.log(configValue) // "woot"
38+
39+
// Update a config value
40+
config().put("count", 1)
41+
var count = await config().get("count", 0)
42+
console.log(count) // 1
43+
44+
config().update("count", oldValue => oldValue + 1)
45+
var count = await config().get("count", 0)
46+
console.log(count) // 2
47+
48+
// Delete a config value
49+
config().delete("woot")
50+
var configValue = await config().get("woot", "fallback")
51+
console.log(configValue) // "fallback"
52+
53+
// Configs that match a pattern
54+
config()
55+
.put("scope.A", 1)
56+
.put("scope.B", 1)
57+
58+
var scopeValues = await config().where(/^scope\.\s+/)
59+
console.log(scopeValues) // { "scope.A": 1, "scope.B": 2 }
60+
```
61+
62+
## Loading flow.json
63+
64+
Before loading a `flow.json`, you must set the network:
65+
66+
```javascript
67+
import { config } from "@onflow/config"
68+
69+
// Set network (required before loading flow.json)
70+
config().put("flow.network", "testnet")
71+
72+
// Load flow.json
73+
await config().load({ flowJSON: require('./flow.json') })
74+
```
75+
76+
## Import Aliases
77+
78+
Import aliases allow you to deploy the same contract to multiple addresses with different names, enabling version management and multi-instance deployments.
79+
80+
### flow.json Configuration
81+
82+
```json
83+
{
84+
"contracts": {
85+
"FUSD": {
86+
"source": "./contracts/FUSD.cdc",
87+
"aliases": {
88+
"testnet": "0x9a0766d93b6608b7"
89+
}
90+
},
91+
"FUSD1": {
92+
"source": "./contracts/FUSD.cdc",
93+
"aliases": {
94+
"testnet": "0xe223d8a629e49c68"
95+
},
96+
"canonical": "FUSD"
97+
}
98+
}
99+
}
100+
```
101+
102+
### How It Works
103+
104+
When `config.load(flowJSON)` is called:
105+
106+
1. **Contract addresses are extracted** based on the current network
107+
2. **Canonical references are extracted** from the `canonical` field
108+
3. **Values are stored in config**:
109+
```typescript
110+
system.contracts.FUSD = "0x9a0766d93b6608b7"
111+
system.contracts.FUSD1 = "0xe223d8a629e49c68"
112+
system.contracts.FUSD1.canonical = "FUSD"
113+
```
114+
115+
### Import Resolution
116+
117+
When resolving Cadence imports:
118+
119+
- `import "FUSD"``import FUSD from 0x9a0766d93b6608b7` (no canonical)
120+
- `import "FUSD1"``import FUSD as FUSD1 from 0xe223d8a629e49c68` (with canonical)
121+
122+
The `canonical` field tells the resolver that `FUSD1` is an alias of the `FUSD` contract, so it generates the `import X as Y` syntax.
123+
124+
### Use Cases
125+
126+
**Multiple Versions:**
127+
```json
128+
{
129+
"contracts": {
130+
"FungibleToken": {
131+
"source": "./contracts/FungibleToken.cdc",
132+
"aliases": { "testnet": "0xf233dcee88fe0abe" }
133+
},
134+
"FungibleTokenV2": {
135+
"source": "./contracts/FungibleToken.cdc",
136+
"aliases": { "testnet": "0x9a0766d93b6608b7" },
137+
"canonical": "FungibleToken"
138+
}
139+
}
140+
}
141+
```
142+
143+
**Multiple Instances:**
144+
```json
145+
{
146+
"contracts": {
147+
"Token1": {
148+
"source": "./contracts/Token.cdc",
149+
"aliases": { "testnet": "0x1111" },
150+
"canonical": "Token"
151+
},
152+
"Token2": {
153+
"source": "./contracts/Token.cdc",
154+
"aliases": { "testnet": "0x2222" },
155+
"canonical": "Token"
156+
}
157+
}
158+
}
159+
```
160+
161+
### Dependencies
162+
163+
The `canonical` field also works with dependencies:
164+
165+
```json
166+
{
167+
"dependencies": {
168+
"FungibleTokenV2": {
169+
"source": "mainnet://f233dcee88fe0abe.FungibleToken",
170+
"hash": "abc123...",
171+
"aliases": {
172+
"testnet": "0xf233dcee88fe0abe"
173+
},
174+
"canonical": "FungibleToken"
175+
}
176+
}
177+
}
178+
```
179+
180+
## Known Configuration Values
181+
182+
### Access Node
183+
184+
- `accessNode.api` _(default: emulator url)_ -- Where FCL will communicate with the Flow blockchain.
185+
- `accessNode.key` _(default: null)_ -- Some Access Nodes require an API key.
186+
187+
```javascript
188+
import {config} from "@onflow/fcl"
189+
190+
if (process.env.NODE_ENV === "production") {
191+
config()
192+
.put("accessNode.api", process.env.ACCESS_NODE_API)
193+
.put("accessNode.key", process.env.ACCESS_NODE_KEY)
194+
}
195+
```
196+
197+
### Decode
198+
199+
`decoder.*` -- Custom decoders for parsing JSON-CDC
200+
201+
```javascript
202+
import {config, query} from "@onflow/fcl"
203+
204+
function Woot({x, y}) {
205+
this.x = x
206+
this.y = y
207+
}
208+
209+
config()
210+
.put("decoder.Woot", woot => new Woot(woot))
211+
212+
var data = await fcl.query({
213+
cadence: `
214+
pub struct Woot {
215+
pub var x: Int
216+
pub var y: Int
217+
218+
init(x: Int, y: Int) {
219+
self.x = x
220+
self.y = y
221+
}
222+
}
223+
224+
pub fun main(): [Woot] {
225+
return [Woot(x: 1, y: 2), Woot(x: 3, y: 4), Woot(x: 5, y: 6)]
226+
}
227+
`
228+
})
229+
230+
console.log(data) // [ Woot{x:1, y:2}, Woot{x:3, y:4}, Woot{x:5, y:6} ]
231+
```
232+
233+
### Wallets
234+
235+
`wallet.discovery` _(default: FCL wallet discovery service url)_ -- Where FCL will attempt to authenticate
236+
237+
```javascript
238+
import {config} from "@onflow/fcl"
239+
240+
if (process.env.NODE_ENV === "development") {
241+
// Use dev wallet during development
242+
config()
243+
.put("discovery.wallet", "http://localhost:8701/flow/authenticate")
244+
}
245+
```
246+
247+
## API Reference
248+
249+
### `config()`
250+
251+
Returns the config instance.
252+
253+
### `config().put(key, value)`
254+
255+
Sets a configuration value. Can be chained.
256+
257+
### `config().get(key, fallback?)`
258+
259+
Gets a configuration value, optionally with a fallback. Returns a Promise.
260+
261+
### `config().update(key, updateFn)`
262+
263+
Updates a configuration value using a function that receives the old value.
264+
265+
### `config().load({ flowJSON })`
266+
267+
Loads contract addresses and canonical references from a flow.json file.
268+
269+
**Parameters:**
270+
- `flowJSON`: Flow JSON object or array of Flow JSON objects
271+
272+
**Requirements:**
273+
- `flow.network` must be set before calling `load()`
274+
275+
### `config().delete(key)`
276+
277+
Deletes a configuration value.
278+
279+
### `config().all()`
280+
281+
Returns all configuration values as an object.
282+
283+
### `config().where(pattern)`
284+
285+
Returns configuration values matching a regex pattern.
286+
287+
### `config().subscribe(callback)`
288+
289+
Subscribes to configuration changes. Returns an unsubscribe function.
290+
291+
## See Also
292+
293+
- [Flow CLI Documentation](https://developers.flow.com/tools/flow-cli)
294+
- [Flow JavaScript SDK](https://developers.flow.com/tools/fcl-js)
295+
- [flow.json Configuration](https://developers.flow.com/tools/flow-cli/flow.json)

0 commit comments

Comments
 (0)