solana-studio 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascripts/solana_studio/wallet_ops.js +70 -9
- data/lib/solana_studio/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a00c3f09eb98073668c9218045e49e705be6e803348ad9338e4295d32ca7c091
|
|
4
|
+
data.tar.gz: 16189d3a834e1880bbba0b37113823fdf95d4a690926d98f67120213818b70db
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 43e0a031a5fb9c2bcb451c4bddcf2df0e79a1c1722c60e57e9fcd302699434736bf363dd12a6f1ee7f847f447a1b3aeb792e557a7874edc419714a66a9a8b094
|
|
7
|
+
data.tar.gz: 8613a4f8bcead4253fb9b1814b1fbb008d9d1f9c3db4e1e8be33b5ca5fc005ce2b7b4226f136454a52f4ef66ccec59c22cf968d6f78762558e51355a2e2de056
|
|
@@ -11,11 +11,22 @@
|
|
|
11
11
|
//
|
|
12
12
|
// walletOps.define('contest_entry', {
|
|
13
13
|
// prepare: function (ctx) { ... return { transaction: <base58>, ...state }; },
|
|
14
|
-
// complete: function (ctx, result, state) { ... }
|
|
14
|
+
// complete: function (ctx, result, state) { ... },
|
|
15
|
+
// signOnly: true
|
|
15
16
|
// });
|
|
16
17
|
//
|
|
17
18
|
// walletOps.run('contest_entry', { contestId: 12 }, { provider: ... });
|
|
18
19
|
//
|
|
20
|
+
// `signOnly` IS A REQUIREMENT OF THE TRANSACTION, NOT A PREFERENCE ABOUT THE
|
|
21
|
+
// WALLET, and it is the intent's to declare because only the intent knows the
|
|
22
|
+
// shape of the bytes it prepared. A CO-SIGNED transaction — one whose second
|
|
23
|
+
// signer slot is deliberately empty because a server fills it — cannot be
|
|
24
|
+
// broadcast by the wallet: the chain would reject it for a missing required
|
|
25
|
+
// signature, and, worse, the signed bytes the server needs would never come
|
|
26
|
+
// back to the app, so the flow fails with nothing to retry. Declaring it makes
|
|
27
|
+
// the transaction's own requirement outrank the wallet's capability. Omit it
|
|
28
|
+
// and nothing changes: a wallet that can broadcast still does.
|
|
29
|
+
//
|
|
19
30
|
// THE ONE RULE A CALLER MUST FOLLOW: handlers are registered BY NAME at page
|
|
20
31
|
// load, not passed as closures. A closure is precisely what cannot survive the
|
|
21
32
|
// redirect — the page that held it no longer exists when the wallet answers. The
|
|
@@ -30,7 +41,8 @@
|
|
|
30
41
|
// WHAT THIS FILE DOES NOT DO: it does not broadcast. Signing and sending are
|
|
31
42
|
// different responsibilities with different failure modes, and the wallet that
|
|
32
43
|
// broadcasts differs per vendor (Phantom deprecated its send-side deeplink, so
|
|
33
|
-
// the app sends; Solflare and Backpack send for you)
|
|
44
|
+
// the app sends; Solflare and Backpack send for you) — and, where the intent
|
|
45
|
+
// declares `signOnly`, per TRANSACTION as well. `complete` is told which
|
|
34
46
|
// happened and owns the RPC, exactly as the existing flows already do.
|
|
35
47
|
(function (W) {
|
|
36
48
|
'use strict';
|
|
@@ -107,6 +119,23 @@
|
|
|
107
119
|
return Promise.resolve(handler.prepare(ctx)).then(function (prepared) {
|
|
108
120
|
var intent = { op: name, ctx: ctx, state: prepared };
|
|
109
121
|
|
|
122
|
+
// THE DECLARATION TRAVELS IN THE JOURNAL, NOT LOOKED UP FROM THE HANDLER
|
|
123
|
+
// AT THE FAR END, and that is the whole reason this line exists here
|
|
124
|
+
// rather than inside signingHop. The signing hop is taken from TWO
|
|
125
|
+
// places: this one, where the handler is certainly registered, and the
|
|
126
|
+
// connect callback, which is a DIFFERENT PAGE that may not have loaded
|
|
127
|
+
// the script that defined this intent. A handler lookup there would come
|
|
128
|
+
// back empty and silently fall through to the send-side default — the
|
|
129
|
+
// exact branch a co-signed transaction must never take. A boolean on the
|
|
130
|
+
// intent is JSON-serialisable, which is the one thing this file requires
|
|
131
|
+
// of anything that has to survive a redirect.
|
|
132
|
+
//
|
|
133
|
+
// Set ONLY when true, so the journal an undeclared intent writes is
|
|
134
|
+
// byte-identical to the one it wrote before this option existed. That is
|
|
135
|
+
// also why JOURNAL_VERSION does not move: no reader's expectations
|
|
136
|
+
// change, and bumping it would strand every trip already in flight.
|
|
137
|
+
if (handler.signOnly) intent.signOnly = true;
|
|
138
|
+
|
|
110
139
|
// Already connected? Go straight to signing. Otherwise connect first and
|
|
111
140
|
// carry the intent through — sessions do not expire on any of the three
|
|
112
141
|
// wallets, so this branch is taken once per user, not once per action.
|
|
@@ -145,18 +174,38 @@
|
|
|
145
174
|
return signingHop(provider, connected, opts);
|
|
146
175
|
}
|
|
147
176
|
|
|
148
|
-
// Which signing method this wallet gets is
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
//
|
|
177
|
+
// Which signing method this wallet gets is TWO questions asked in order, and
|
|
178
|
+
// the order is the point.
|
|
179
|
+
//
|
|
180
|
+
// FIRST, what does the TRANSACTION allow? A co-signed transaction has an
|
|
181
|
+
// empty signer slot the server fills, so the wallet must sign and hand the
|
|
182
|
+
// bytes back — broadcasting it is not a worse option, it is a broken one.
|
|
183
|
+
// An intent that knows this declares `signOnly` and that answer is final.
|
|
184
|
+
//
|
|
185
|
+
// SECOND, and only for everything else, what can the WALLET do? Phantom's
|
|
186
|
+
// send-side deeplink is deprecated, so it signs and the app broadcasts;
|
|
187
|
+
// Solflare and Backpack broadcast for you. Asking the provider keeps that
|
|
188
|
+
// fact in the profile table where it is asserted, rather than branching on a
|
|
189
|
+
// wallet name here.
|
|
190
|
+
//
|
|
191
|
+
// Asking them the other way round is the bug this replaced: capability alone
|
|
192
|
+
// sent every co-signed transaction to the wallet's broadcaster on any wallet
|
|
193
|
+
// that had one.
|
|
194
|
+
//
|
|
195
|
+
// A wallet with no signTransaction at all would be refused BY NAME by the
|
|
196
|
+
// provider's own capability gate rather than quietly broadcast here. No
|
|
197
|
+
// profile is in that state today (all three sign), and this is the branch
|
|
198
|
+
// that would have to be revisited if one ever were.
|
|
152
199
|
function signingHop(provider, journal, opts) {
|
|
200
|
+
var intent = journal.intent;
|
|
153
201
|
var payload = {
|
|
154
202
|
journal: journal,
|
|
155
|
-
transaction:
|
|
203
|
+
transaction: intent.state.transaction,
|
|
156
204
|
redirectLink: opts.redirectLink,
|
|
157
|
-
intent:
|
|
205
|
+
intent: intent
|
|
158
206
|
};
|
|
159
|
-
|
|
207
|
+
var signOnly = !!(intent && intent.signOnly);
|
|
208
|
+
return (!signOnly && provider.can('signAndSendTransaction'))
|
|
160
209
|
? provider.beginSignAndSendTransaction(payload)
|
|
161
210
|
: provider.beginSignTransaction(payload);
|
|
162
211
|
}
|
|
@@ -234,6 +283,18 @@
|
|
|
234
283
|
if (!handler || typeof handler.prepare !== 'function' || typeof handler.complete !== 'function') {
|
|
235
284
|
throw new Error('walletOps.define("' + name + '") needs both prepare and complete');
|
|
236
285
|
}
|
|
286
|
+
// REFUSED RATHER THAN COERCED, because every wrong answer here fails in
|
|
287
|
+
// the dangerous direction. A typo'd `signOnly: 'true'` read as truthy
|
|
288
|
+
// would sign-only a flow that wanted the wallet to broadcast; read
|
|
289
|
+
// strictly, it silently sends a co-signed transaction to a broadcaster.
|
|
290
|
+
// Neither is discoverable at the call site, and both surface as a chain
|
|
291
|
+
// error one page death later. So the option is a boolean or it is a bug.
|
|
292
|
+
if (handler.signOnly !== undefined && typeof handler.signOnly !== 'boolean') {
|
|
293
|
+
throw new Error(
|
|
294
|
+
'walletOps.define("' + name + '") signOnly must be true or false, got ' +
|
|
295
|
+
typeof handler.signOnly
|
|
296
|
+
);
|
|
297
|
+
}
|
|
237
298
|
handlers[name] = handler;
|
|
238
299
|
},
|
|
239
300
|
|
|
@@ -16,5 +16,5 @@ module SolanaStudio
|
|
|
16
16
|
# through the normal cycle. Splitting the version out is the same shape
|
|
17
17
|
# studio-engine already uses (lib/studio/version.rb) and hands each file back
|
|
18
18
|
# to its real owner: this one to the release, the gemspec to the PR.
|
|
19
|
-
VERSION = "0.9.
|
|
19
|
+
VERSION = "0.9.1"
|
|
20
20
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: solana-studio
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex McRitchie
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ed25519
|