Skip to content

Commit 3d8b84d

Browse files
committed
Merge remote-tracking branch 'origin/develop' into monitor-dc-auto-top-liveness
2 parents c1b18ce + 7000cbe commit 3d8b84d

40 files changed

Lines changed: 1302 additions & 282 deletions
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: "Localnet accounts"
2+
description: "Restore or fetch the account dumps localnet loads instead of cloning at boot"
3+
runs:
4+
using: "composite"
5+
steps:
6+
# Keyed on Anchor.toml because that is where the address list lives, so editing an
7+
# entry refetches. The key also rolls weekly so the dumps are refreshed rather than
8+
# kept forever.
9+
- id: week
10+
run: echo "week=$(date -u +%G-%V)" >> "$GITHUB_OUTPUT"
11+
shell: bash
12+
- uses: actions/cache@v4
13+
with:
14+
path: accounts
15+
key: localnet-accounts-${{ steps.week.outputs.week }}-${{ hashFiles('Anchor.toml') }}
16+
# A cache hit makes this a no-op; the script skips any file already present, and
17+
# re-fetches only what a partial restore left missing.
18+
- run: ./scripts/fetch-localnet-accounts.sh
19+
shell: bash

.github/actions/setup/action.yaml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ runs:
77
# serve corrupt indexes and fail apt-get update; nothing here needs them.
88
- run: sudo rm -f /etc/apt/sources.list.d/microsoft-prod* /etc/apt/sources.list.d/azure-cli*
99
shell: bash
10-
- run: sudo apt-get update
10+
# apt has no timeout by default, so a mirror that accepts the connection and then
11+
# stalls hangs the step until the job's own cap. Observed repeatedly: a fetch of
12+
# archive.ubuntu.com InRelease going silent for 44 minutes. Retries cover a mirror
13+
# that fails outright. `timeout-minutes` is not available on composite-action steps,
14+
# so the bound is set once in apt.conf.d and every later apt-get in the job inherits it.
15+
- run: |
16+
printf 'Acquire::http::Timeout "30";\nAcquire::https::Timeout "30";\nAcquire::Retries "3";\n' | sudo tee /etc/apt/apt.conf.d/99ci-timeouts
17+
sudo apt-get update
1118
shell: bash
1219
- run: sudo apt-get install -y pkg-config build-essential libudev-dev
1320
shell: bash
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: "Start localnet"
2+
description: "Start anchor localnet in the background and wait for it to report healthy"
3+
runs:
4+
using: "composite"
5+
steps:
6+
- name: Start Anchor Localnet
7+
# Redirect to a file and record the pid: `cmd &` returns 0 whatever the validator
8+
# does, so without these a validator that dies on startup leaves the step green and
9+
# its output attached to a shell that has already exited.
10+
shell: bash
11+
run: |
12+
~/.cargo/bin/anchor localnet --skip-build \
13+
--provider.wallet ~/.config/solana/id.json > /tmp/localnet.log 2>&1 &
14+
echo $! > /tmp/localnet.pid
15+
- name: Wait for localnet to start
16+
# A healthy validator answers within a poll or two (~5s), so this bound only ever
17+
# applies to a broken one. A vanished pid is reported with the log but is not itself fatal:
18+
# `anchor localnet` is a wrapper around solana-test-validator, so treating its exit
19+
# as terminal would fail a build whose validator is merely slow to come up.
20+
shell: bash
21+
run: |
22+
reported=0
23+
for i in $(seq 1 60); do
24+
if [[ "$(curl -s http://localhost:8899/health)" == "ok" ]]; then
25+
echo "localnet healthy after $i poll(s)"
26+
exit 0
27+
fi
28+
if [[ "$reported" == "0" ]] && ! kill -0 "$(cat /tmp/localnet.pid 2>/dev/null)" 2>/dev/null; then
29+
echo "::warning::anchor localnet is no longer running; polling until the bound anyway"
30+
cat /tmp/localnet.log || true
31+
reported=1
32+
fi
33+
sleep 5
34+
done
35+
echo "::error::localnet did not become healthy within 5 minutes"
36+
cat /tmp/localnet.log || true
37+
exit 1

.github/workflows/tests.yaml

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,16 @@ jobs:
1515
test-rust-lint:
1616
name: Test Rust Lint
1717
runs-on: ubuntu-latest
18+
timeout-minutes: 45
1819
steps:
1920
- uses: actions/checkout@v2
2021
- uses: ./.github/actions/setup/
22+
# Every other job takes its compiler from setup-anchor's `rustup default 1.85.0`; this one
23+
# does not run setup-anchor, so without a version here it takes whatever the runner image
24+
# ships and the gate drifts away from the code. It cannot simply reuse 1.85.0: the clippy
25+
# flags below name lints that only exist in a later release, and an unknown lint is itself
26+
# an error under `-D warnings`. Bump this deliberately, and expect new lints when you do.
27+
- run: rustup install 1.98.0 --component clippy,rustfmt --profile minimal && rustup default 1.98.0
2128
- uses: actions/cache@v4
2229
name: Cache Cargo registry + index
2330
id: cache-cargo-build
@@ -39,6 +46,7 @@ jobs:
3946
name: Check @helium/idls Changeset
4047
if: github.event_name == 'pull_request'
4148
runs-on: ubuntu-latest
49+
timeout-minutes: 45
4250
steps:
4351
- uses: actions/checkout@v3
4452
with:
@@ -130,6 +138,7 @@ jobs:
130138
test-unit:
131139
name: Rust Unit Tests
132140
runs-on: ubuntu-latest
141+
timeout-minutes: 45
133142
steps:
134143
- uses: actions/checkout@v2
135144
- uses: ./.github/actions/setup/
@@ -149,6 +158,7 @@ jobs:
149158
test-atomic-data-publisher:
150159
name: Atomic Data Publisher Tests
151160
runs-on: ubuntu-latest
161+
timeout-minutes: 45
152162
services:
153163
postgres:
154164
image: postgres:16
@@ -186,37 +196,35 @@ jobs:
186196
build:
187197
name: Build Anchor
188198
runs-on: ubuntu-latest
199+
timeout-minutes: 45
189200
steps:
190201
- uses: actions/checkout@v2
191202
- uses: ./.github/actions/build-anchor/
192203
with:
193204
testing: true
205+
- uses: ./.github/actions/localnet-accounts/
194206

195207
test-devflow:
196208
needs: build
197209
name: Test Development Workflow
198210
runs-on: ubuntu-latest
211+
timeout-minutes: 45
199212
steps:
200213
- uses: actions/checkout@v3
201214
- uses: ./.github/actions/build-anchor/
202215
with:
203216
testing: true
204217
- uses: ./.github/actions/setup-ts/
205-
- name: Start Anchor Localnet
206-
run: ~/.cargo/bin/anchor localnet --skip-build --provider.wallet ~/.config/solana/id.json & sleep 2
207-
- name: Wait for localnet to start
208-
run: |
209-
while [[ "$(curl -s http://localhost:8899/health)" != "ok" ]]; do
210-
echo "Waiting for local Anchor network to start..."
211-
sleep 5
212-
done
218+
- uses: ./.github/actions/localnet-accounts/
219+
- uses: ./.github/actions/start-localnet/
213220
- name: Run bootstrap script
214221
run: ./scripts/bootstrap.sh
215222

216223
test-helium-vote-service:
217224
needs: build
218225
name: Test Helium Vote Service
219226
runs-on: ubuntu-latest
227+
timeout-minutes: 45
220228
steps:
221229
- uses: actions/checkout@v3
222230
- uses: ./.github/actions/build-anchor/
@@ -229,6 +237,7 @@ jobs:
229237
needs: build
230238
name: Test Docker Builds
231239
runs-on: ubuntu-latest
240+
timeout-minutes: 45
232241
strategy:
233242
fail-fast: false
234243
matrix:
@@ -284,6 +293,7 @@ jobs:
284293
needs: build
285294
name: Test Rust Builds
286295
runs-on: ubuntu-latest
296+
timeout-minutes: 45
287297
strategy:
288298
fail-fast: false
289299
matrix:
@@ -305,6 +315,7 @@ jobs:
305315
needs: build
306316
name: Test Anchor Contracts
307317
runs-on: ubuntu-latest
318+
timeout-minutes: 45
308319
strategy:
309320
fail-fast: false
310321
matrix:
@@ -328,6 +339,7 @@ jobs:
328339
- tests/mini-fanout-bankrun.ts
329340
- tests/welcome-pack.ts
330341
- tests/dc-auto-topoff.ts
342+
- tests/dc-auto-topoff-bankrun.ts
331343
- tests/tuktuk-dca.ts
332344
- tests/priority-fees.ts
333345
steps:
@@ -336,14 +348,8 @@ jobs:
336348
with:
337349
testing: true
338350
- uses: ./.github/actions/setup-ts/
339-
- name: Start Anchor Localnet
340-
run: ~/.cargo/bin/anchor localnet --skip-build --provider.wallet ~/.config/solana/id.json & sleep 2
341-
- name: Wait for localnet to start
342-
run: |
343-
while [[ "$(curl -s http://localhost:8899/health)" != "ok" ]]; do
344-
echo "Waiting for local Anchor network to start..."
345-
sleep 5
346-
done
351+
- uses: ./.github/actions/localnet-accounts/
352+
- uses: ./.github/actions/start-localnet/
347353
- run: ANCHOR_WALLET=${HOME}/.config/solana/id.json pnpm exec ts-mocha -p ./tsconfig.test.json -t 1000000 --exit $TEST
348354
env:
349355
TESTING: true

Anchor.toml

Lines changed: 92 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -64,99 +64,127 @@ test = "pnpm exec ts-mocha -p ./tsconfig.test.json -t 1000000 tests/**/*.ts"
6464
[test]
6565
startup_wait = 20000
6666

67-
[test.validator]
68-
url = "https://api.mainnet-beta.solana.com"
69-
bind_address = "127.0.0.1"
67+
# Programs are preloaded from .so dumps rather than cloned. Loading them as raw
68+
# account pairs instead exhausts the validator's program cache.
7069

71-
[[test.validator.clone]]
72-
address = "tuktukUrfhXT6ZT77QTU8RQtvgL967uRuVagWF57zVA" # tuktuk
70+
[[test.genesis]]
71+
address = "tuktukUrfhXT6ZT77QTU8RQtvgL967uRuVagWF57zVA" # tuktuk
72+
program = "accounts/tuktukUrfhXT6ZT77QTU8RQtvgL967uRuVagWF57zVA.so"
7373

74-
[[test.validator.clone]]
75-
address = "HGBovqKte26DbEMBma3T1TvvdmAFYSSgjncRoKECqfXq" # tuktuk config
74+
[[test.genesis]]
75+
address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" # token-metadata
76+
program = "accounts/metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s.so"
7677

77-
[[test.validator.clone]]
78-
address = "GkUxZMcw2RbwZ64VL3MvBtYNV8zim3y7UfzabFTybAUJ" # tuktuk-idl
78+
[[test.genesis]]
79+
address = "BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY" # bubblegum
80+
program = "accounts/BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY.so"
7981

80-
[[test.validator.clone]]
81-
address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" # token-metadata
82+
[[test.genesis]]
83+
address = "noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV" # noop
84+
program = "accounts/noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV.so"
8285

83-
[[test.validator.clone]]
84-
address = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" # associated-token-program
86+
[[test.genesis]]
87+
address = "cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK" # account compression
88+
program = "accounts/cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK.so"
8589

86-
[[test.validator.clone]]
87-
address = "BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY" # bubblegum
90+
[[test.genesis]]
91+
address = "hgovkRU6Ghe1Qoyb54HdSLdqN7VtxaifBzRmh9jtd3S" # spl governance program
92+
program = "accounts/hgovkRU6Ghe1Qoyb54HdSLdqN7VtxaifBzRmh9jtd3S.so"
8893

89-
[[test.validator.clone]]
90-
address = "noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV" # noop
94+
[[test.genesis]]
95+
address = "propFYxqmVcufMhk5esNMrexq2ogHbbC2kP9PU1qxKs" # Proposal
96+
program = "accounts/propFYxqmVcufMhk5esNMrexq2ogHbbC2kP9PU1qxKs.so"
9197

92-
[[test.validator.clone]]
93-
address = "4DdmDswskDxXGpwHrXUfn2CNUm9rt21ac79GHNTN3J33" # hnt feed needed for dc auto top
98+
[[test.genesis]]
99+
address = "nprx42sXf5rpVnwBWEdRg1d8tuCWsTuVLys1pRWwE6p" # NFT Proxy
100+
program = "accounts/nprx42sXf5rpVnwBWEdRg1d8tuCWsTuVLys1pRWwE6p.so"
94101

95-
[[test.validator.clone]]
96-
address = "He5mhwVQQNvjFxqjEjFDb7enJWFwFJ7Rq7zknqBz89A5" # pro-receiver-owned HNT/USD feed for the data-credits mint pin and tuktuk-dca
102+
[[test.genesis]]
103+
address = "orgdXvHVLkWgBYerptASkAwkZAE563CJUu717dMNx5f" # Org program
104+
program = "accounts/orgdXvHVLkWgBYerptASkAwkZAE563CJUu717dMNx5f.so"
97105

98-
[[test.validator.clone]]
99-
address = "6HAuqASbHEh4w4REJEUUUCginTLfj1kwCh215ZLtMkrT" # pro-receiver-owned USDC/USD price feed for tuktuk-dca
106+
[[test.genesis]]
107+
address = "stcfiqW3fwD9QCd8Bqr1NBLrs7dftZHBQe7RiMMA4aM" # State controller program
108+
program = "accounts/stcfiqW3fwD9QCd8Bqr1NBLrs7dftZHBQe7RiMMA4aM.so"
100109

101-
[[test.validator.clone]]
102-
address = "cmtDvXumGCrqC1Age74AVPhSRVXJMd8PJS91L8KbNCK" # account compression
110+
[[test.genesis]]
111+
address = "rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ" # Pyth price oracle program
112+
program = "accounts/rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ.so"
103113

104-
[[test.validator.clone]]
105-
address = "hgovkRU6Ghe1Qoyb54HdSLdqN7VtxaifBzRmh9jtd3S" # spl governance program
114+
[[test.genesis]]
115+
address = "HDwcJBJXjL9FpJ7UBsYBtaDjsBUhuLCUYoz3zr8SWWaQ" # Wormhole
116+
program = "accounts/HDwcJBJXjL9FpJ7UBsYBtaDjsBUhuLCUYoz3zr8SWWaQ.so"
106117

107-
[[test.validator.clone]]
108-
address = "ENmcpFCpxN1CqyUjuog9yyUVfdXBKF3LVCwLr7grJZpk" # required by spl governance
118+
[[test.genesis]]
119+
address = "SMPLecH534NA9acpos4G6x7uf3LWbCAwZQE9e8ZekMu" # Squads multisig program
120+
program = "accounts/SMPLecH534NA9acpos4G6x7uf3LWbCAwZQE9e8ZekMu.so"
109121

110-
[[test.validator.clone]]
111-
address = "propFYxqmVcufMhk5esNMrexq2ogHbbC2kP9PU1qxKs" # Proposal
122+
[test.validator]
123+
bind_address = "127.0.0.1"
112124

113-
[[test.validator.clone]]
114-
address = "66t3XARU6Ja3zj91gDZ2KoNLJHEMTYPSKqJWYb6PJJBA" # Proposal IDL
125+
[[test.validator.account]]
126+
address = "HGBovqKte26DbEMBma3T1TvvdmAFYSSgjncRoKECqfXq" # tuktuk config
127+
filename = "accounts/HGBovqKte26DbEMBma3T1TvvdmAFYSSgjncRoKECqfXq.json"
115128

116-
[[test.validator.clone]]
117-
address = "nprx42sXf5rpVnwBWEdRg1d8tuCWsTuVLys1pRWwE6p" # NFT Proxy
129+
[[test.validator.account]]
130+
address = "GkUxZMcw2RbwZ64VL3MvBtYNV8zim3y7UfzabFTybAUJ" # tuktuk-idl
131+
filename = "accounts/GkUxZMcw2RbwZ64VL3MvBtYNV8zim3y7UfzabFTybAUJ.json"
118132

119-
[[test.validator.clone]]
120-
address = "CNjepJnCPddZwd8xGS3M2QpZuCbfVRNvi3jfBehKHKHw" # NFT Proxy IDL
133+
[[test.validator.account]]
134+
address = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" # associated-token-program
135+
filename = "accounts/ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL.json"
121136

122-
[[test.validator.clone]]
123-
address = "orgdXvHVLkWgBYerptASkAwkZAE563CJUu717dMNx5f" # Org program
137+
[[test.validator.account]]
138+
address = "4DdmDswskDxXGpwHrXUfn2CNUm9rt21ac79GHNTN3J33" # hnt feed needed for dc auto top
139+
filename = "accounts/4DdmDswskDxXGpwHrXUfn2CNUm9rt21ac79GHNTN3J33.json"
124140

125-
[[test.validator.clone]]
126-
address = "CjVhwk3gdDXB8iUZCUP9M6QaRvoBGkM7FX9qAf6Qm4sG" # Org program IDL
141+
[[test.validator.account]]
142+
address = "He5mhwVQQNvjFxqjEjFDb7enJWFwFJ7Rq7zknqBz89A5" # pro-receiver-owned HNT/USD feed for the data-credits mint pin and tuktuk-dca
143+
filename = "accounts/He5mhwVQQNvjFxqjEjFDb7enJWFwFJ7Rq7zknqBz89A5.json"
127144

128-
[[test.validator.clone]]
129-
address = "stcfiqW3fwD9QCd8Bqr1NBLrs7dftZHBQe7RiMMA4aM" # State controller program
145+
[[test.validator.account]]
146+
address = "6HAuqASbHEh4w4REJEUUUCginTLfj1kwCh215ZLtMkrT" # pro-receiver-owned USDC/USD price feed for tuktuk-dca
147+
filename = "accounts/6HAuqASbHEh4w4REJEUUUCginTLfj1kwCh215ZLtMkrT.json"
130148

131-
[[test.validator.clone]]
132-
address = "GPQNABq6s63uqzHRwZN9e2GcxtzG4yLP5AnJer7DkB9E" # State controller IDL
149+
[[test.validator.account]]
150+
address = "ENmcpFCpxN1CqyUjuog9yyUVfdXBKF3LVCwLr7grJZpk" # required by spl governance
151+
filename = "accounts/ENmcpFCpxN1CqyUjuog9yyUVfdXBKF3LVCwLr7grJZpk.json"
133152

134-
# Pyth price oracle program
135-
[[test.validator.clone]]
136-
address = "rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ"
153+
[[test.validator.account]]
154+
address = "66t3XARU6Ja3zj91gDZ2KoNLJHEMTYPSKqJWYb6PJJBA" # Proposal IDL
155+
filename = "accounts/66t3XARU6Ja3zj91gDZ2KoNLJHEMTYPSKqJWYb6PJJBA.json"
137156

138-
# Wormhole
139-
[[test.validator.clone]]
140-
address = "HDwcJBJXjL9FpJ7UBsYBtaDjsBUhuLCUYoz3zr8SWWaQ"
157+
[[test.validator.account]]
158+
address = "CNjepJnCPddZwd8xGS3M2QpZuCbfVRNvi3jfBehKHKHw" # NFT Proxy IDL
159+
filename = "accounts/CNjepJnCPddZwd8xGS3M2QpZuCbfVRNvi3jfBehKHKHw.json"
141160

142-
[[test.validator.clone]]
143-
address = "5gxPdahvSzcKySxXxPuRXZZ9s6h8hZ88XDVKavWpaQGn" # Wormhole guardian set index 4
161+
[[test.validator.account]]
162+
address = "CjVhwk3gdDXB8iUZCUP9M6QaRvoBGkM7FX9qAf6Qm4sG" # Org program IDL
163+
filename = "accounts/CjVhwk3gdDXB8iUZCUP9M6QaRvoBGkM7FX9qAf6Qm4sG.json"
144164

145-
[[test.validator.clone]]
146-
address = "HTczusLJSAhMJKYrxLjSUUyW7YDsBuyfBG8Tj1KJsgni" # Wormhole guardian set index 5
165+
[[test.validator.account]]
166+
address = "GPQNABq6s63uqzHRwZN9e2GcxtzG4yLP5AnJer7DkB9E" # State controller IDL
167+
filename = "accounts/GPQNABq6s63uqzHRwZN9e2GcxtzG4yLP5AnJer7DkB9E.json"
147168

148-
[[test.validator.clone]]
149-
address = "HstYgN21fgNmutTVXjBw54n4ryvP3WrCFbMAjnbdbTzf" # Wormhole guardian set index 6
169+
[[test.validator.account]]
170+
address = "5gxPdahvSzcKySxXxPuRXZZ9s6h8hZ88XDVKavWpaQGn" # Wormhole guardian set index 4
171+
filename = "accounts/5gxPdahvSzcKySxXxPuRXZZ9s6h8hZ88XDVKavWpaQGn.json"
150172

151-
[[test.validator.clone]]
152-
address = "6GaHgiaQg9Pg346xHq9m7vQ9rJtnH83gQKqJoiAxQa7D" # Wormhole guardian set index 7
173+
[[test.validator.account]]
174+
address = "HTczusLJSAhMJKYrxLjSUUyW7YDsBuyfBG8Tj1KJsgni" # Wormhole guardian set index 5
175+
filename = "accounts/HTczusLJSAhMJKYrxLjSUUyW7YDsBuyfBG8Tj1KJsgni.json"
153176

154-
[[test.validator.clone]]
155-
address = "DaWUKXCyXsnzcvLUyeJRWou8KTn7XtadgTsdhJ6RHS7b"
177+
[[test.validator.account]]
178+
address = "HstYgN21fgNmutTVXjBw54n4ryvP3WrCFbMAjnbdbTzf" # Wormhole guardian set index 6
179+
filename = "accounts/HstYgN21fgNmutTVXjBw54n4ryvP3WrCFbMAjnbdbTzf.json"
180+
181+
[[test.validator.account]]
182+
address = "6GaHgiaQg9Pg346xHq9m7vQ9rJtnH83gQKqJoiAxQa7D" # Wormhole guardian set index 7
183+
filename = "accounts/6GaHgiaQg9Pg346xHq9m7vQ9rJtnH83gQKqJoiAxQa7D.json"
156184

157-
# Squads multisig program
158-
[[test.validator.clone]]
159-
address = "SMPLecH534NA9acpos4G6x7uf3LWbCAwZQE9e8ZekMu"
185+
[[test.validator.account]]
186+
address = "DaWUKXCyXsnzcvLUyeJRWou8KTn7XtadgTsdhJ6RHS7b"
187+
filename = "accounts/DaWUKXCyXsnzcvLUyeJRWou8KTn7XtadgTsdhJ6RHS7b.json"
160188

161189
# [[test.validator.clone]]
162190
# address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"

0 commit comments

Comments
 (0)