@openzeppelin/wizard-stellar 0.6.3 → 0.6.5
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.
- package/README.md +4 -0
- package/dist/account.d.ts +19 -0
- package/dist/account.d.ts.map +1 -0
- package/dist/account.js +251 -0
- package/dist/account.js.map +1 -0
- package/dist/add-upgradeable.d.ts +9 -0
- package/dist/add-upgradeable.d.ts.map +1 -1
- package/dist/add-upgradeable.js +25 -0
- package/dist/add-upgradeable.js.map +1 -1
- package/dist/api.d.ts +7 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +6 -1
- package/dist/api.js.map +1 -1
- package/dist/build-generic.d.ts +4 -0
- package/dist/build-generic.d.ts.map +1 -1
- package/dist/build-generic.js +3 -0
- package/dist/build-generic.js.map +1 -1
- package/dist/contract.d.ts +21 -2
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +11 -0
- package/dist/contract.js.map +1 -1
- package/dist/fungible.d.ts.map +1 -1
- package/dist/fungible.js +1 -1
- package/dist/fungible.js.map +1 -1
- package/dist/generate/account.d.ts +3 -0
- package/dist/generate/account.d.ts.map +1 -0
- package/dist/generate/account.js +21 -0
- package/dist/generate/account.js.map +1 -0
- package/dist/generate/sources.d.ts.map +1 -1
- package/dist/generate/sources.js +6 -0
- package/dist/generate/sources.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/kind.js +1 -0
- package/dist/kind.js.map +1 -1
- package/dist/print.js +39 -9
- package/dist/print.js.map +1 -1
- package/dist/utils/compile-test.d.ts.map +1 -1
- package/dist/utils/compile-test.js +1 -0
- package/dist/utils/compile-test.js.map +1 -1
- package/dist/zip-rust.d.ts.map +1 -1
- package/dist/zip-rust.js +14 -1
- package/dist/zip-rust.js.map +1 -1
- package/dist/zip-shared.d.ts +14 -0
- package/dist/zip-shared.d.ts.map +1 -1
- package/dist/zip-shared.js +212 -1
- package/dist/zip-shared.js.map +1 -1
- package/package.json +1 -1
- package/src/account.ts +319 -0
- package/src/add-upgradeable.ts +29 -0
- package/src/api.ts +12 -0
- package/src/build-generic.ts +6 -0
- package/src/contract.ts +24 -2
- package/src/fungible.ts +1 -1
- package/src/generate/account.ts +21 -0
- package/src/generate/sources.ts +7 -0
- package/src/index.ts +2 -0
- package/src/kind.ts +1 -0
- package/src/print.ts +47 -18
- package/src/utils/compile-test.ts +1 -0
- package/src/zip-rust.ts +16 -4
- package/src/zip-shared.ts +231 -0
package/dist/zip-shared.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.workspaceCargo = exports.createRustLibFile = exports.printContractCargo = exports.addDependenciesWith = exports.printVaultRustTest = exports.printRustNameTest = exports.contractOptionsToContractName = void 0;
|
|
3
|
+
exports.workspaceCargo = exports.createRustLibFile = exports.printContractCargo = exports.addDependenciesWith = exports.printAccountRustTest = exports.printVaultRustTest = exports.printRustNameTest = exports.contractOptionsToContractName = void 0;
|
|
4
4
|
exports.getAddressArgs = getAddressArgs;
|
|
5
5
|
exports.getRequiredLibDependencies = getRequiredLibDependencies;
|
|
6
6
|
const version_1 = require("./utils/version");
|
|
@@ -98,9 +98,220 @@ fn initial_state() {
|
|
|
98
98
|
`;
|
|
99
99
|
};
|
|
100
100
|
exports.printVaultRustTest = printVaultRustTest;
|
|
101
|
+
// A smart account contacts its policy and verifier contracts while it is being
|
|
102
|
+
// constructed: `add_context_rule` installs every policy and canonicalizes every
|
|
103
|
+
// external signer key through its verifier. A test that registers the account
|
|
104
|
+
// therefore needs real contracts at those addresses, so the mocks below wrap the
|
|
105
|
+
// library's own logic, the same way the reference examples do.
|
|
106
|
+
const accountPolicies = {
|
|
107
|
+
'simple-threshold': {
|
|
108
|
+
struct: 'MockSimpleThresholdPolicy',
|
|
109
|
+
module: 'simple_threshold',
|
|
110
|
+
params: 'SimpleThresholdAccountParams',
|
|
111
|
+
},
|
|
112
|
+
'weighted-threshold': {
|
|
113
|
+
struct: 'MockWeightedThresholdPolicy',
|
|
114
|
+
module: 'weighted_threshold',
|
|
115
|
+
params: 'WeightedThresholdAccountParams',
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
// How many of each signer type the generated test deploys with. `weights` must
|
|
119
|
+
// have one entry per assembled signer, so the counts drive that too.
|
|
120
|
+
const testSignerCounts = {
|
|
121
|
+
delegated_signers: 2,
|
|
122
|
+
ed25519_keys: 1,
|
|
123
|
+
webauthn_keys: 1,
|
|
124
|
+
};
|
|
125
|
+
const testConstructorArgValues = {
|
|
126
|
+
delegated_signers: () => 'Vec::from_array(&env, [Address::generate(&env), Address::generate(&env)])',
|
|
127
|
+
ed25519_verifier: () => 'ed25519_verifier',
|
|
128
|
+
ed25519_keys: () => 'Vec::from_array(&env, [Bytes::from_slice(&env, &[1u8; 32])])',
|
|
129
|
+
webauthn_verifier: () => 'webauthn_verifier',
|
|
130
|
+
// A WebAuthn key is the 65-byte secp256r1 public key followed by an optional
|
|
131
|
+
// credential id; canonicalization reads the first 65 bytes.
|
|
132
|
+
webauthn_keys: () => 'Vec::from_array(&env, [Bytes::from_slice(&env, &[2u8; 65])])',
|
|
133
|
+
weights: signerCount => `Vec::from_array(&env, [${Array(signerCount).fill('1u32').join(', ')}])`,
|
|
134
|
+
threshold: () => '1u32',
|
|
135
|
+
threshold_policy: () => 'policy',
|
|
136
|
+
};
|
|
137
|
+
const MOCK_ED25519_VERIFIER = `
|
|
138
|
+
// Minimal Ed25519 verifier contract, for testing purposes only: a real
|
|
139
|
+
// deployment passes the address of a verifier contract it trusts.
|
|
140
|
+
#[contract]
|
|
141
|
+
pub struct MockEd25519Verifier;
|
|
142
|
+
|
|
143
|
+
#[contractimpl]
|
|
144
|
+
impl Verifier for MockEd25519Verifier {
|
|
145
|
+
type KeyData = BytesN<32>;
|
|
146
|
+
type SigData = BytesN<64>;
|
|
147
|
+
|
|
148
|
+
fn verify(
|
|
149
|
+
e: &Env,
|
|
150
|
+
signature_payload: Bytes,
|
|
151
|
+
key_data: BytesN<32>,
|
|
152
|
+
sig_data: BytesN<64>,
|
|
153
|
+
) -> bool {
|
|
154
|
+
ed25519::verify(e, &signature_payload, &key_data, &sig_data)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
fn canonicalize_key(e: &Env, key_data: BytesN<32>) -> Bytes {
|
|
158
|
+
ed25519::canonicalize_key(e, &key_data)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
fn batch_canonicalize_key(e: &Env, keys_data: Vec<BytesN<32>>) -> Vec<Bytes> {
|
|
162
|
+
ed25519::batch_canonicalize_key(e, &keys_data)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
`;
|
|
166
|
+
const MOCK_WEBAUTHN_VERIFIER = `
|
|
167
|
+
// Minimal WebAuthn (passkey) verifier contract, for testing purposes only: a
|
|
168
|
+
// real deployment passes the address of a verifier contract it trusts.
|
|
169
|
+
#[contract]
|
|
170
|
+
pub struct MockWebauthnVerifier;
|
|
171
|
+
|
|
172
|
+
#[contractimpl]
|
|
173
|
+
impl Verifier for MockWebauthnVerifier {
|
|
174
|
+
type KeyData = Bytes;
|
|
175
|
+
type SigData = Bytes;
|
|
176
|
+
|
|
177
|
+
fn verify(e: &Env, signature_payload: Bytes, key_data: Bytes, sig_data: Bytes) -> bool {
|
|
178
|
+
let sig_struct =
|
|
179
|
+
WebAuthnSigData::from_xdr(e, &sig_data).expect("WebAuthnSigData with correct format");
|
|
180
|
+
let pub_key: BytesN<65> =
|
|
181
|
+
extract_from_bytes(e, &key_data, 0..65).expect("65-byte public key to be extracted");
|
|
182
|
+
|
|
183
|
+
webauthn::verify(e, &signature_payload, &pub_key, &sig_struct)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
fn canonicalize_key(e: &Env, key_data: Bytes) -> Bytes {
|
|
187
|
+
webauthn::canonicalize_key(e, &key_data)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
fn batch_canonicalize_key(e: &Env, keys_data: Vec<Bytes>) -> Vec<Bytes> {
|
|
191
|
+
webauthn::batch_canonicalize_key(e, &keys_data)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
`;
|
|
195
|
+
const printMockPolicyContract = (policy) => {
|
|
196
|
+
const { struct, module, params } = accountPolicies[policy];
|
|
197
|
+
return `
|
|
198
|
+
// Minimal policy contract, for testing purposes only: the account installs its
|
|
199
|
+
// policies during construction, so the test needs one deployed at that address.
|
|
200
|
+
// A real deployment passes the address of a policy contract it trusts.
|
|
201
|
+
#[contract]
|
|
202
|
+
pub struct ${struct};
|
|
203
|
+
|
|
204
|
+
#[contractimpl]
|
|
205
|
+
impl Policy for ${struct} {
|
|
206
|
+
type AccountParams = ${module}::${params};
|
|
207
|
+
|
|
208
|
+
fn enforce(
|
|
209
|
+
e: &Env,
|
|
210
|
+
context: Context,
|
|
211
|
+
authenticated_signers: Vec<Signer>,
|
|
212
|
+
context_rule: ContextRule,
|
|
213
|
+
smart_account: Address,
|
|
214
|
+
) {
|
|
215
|
+
${module}::enforce(e, &context, &authenticated_signers, &context_rule, &smart_account)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
fn install(
|
|
219
|
+
e: &Env,
|
|
220
|
+
install_params: Self::AccountParams,
|
|
221
|
+
context_rule: ContextRule,
|
|
222
|
+
smart_account: Address,
|
|
223
|
+
) {
|
|
224
|
+
${module}::install(e, &install_params, &context_rule, &smart_account)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
fn uninstall(e: &Env, context_rule: ContextRule, smart_account: Address) {
|
|
228
|
+
${module}::uninstall(e, &context_rule, &smart_account)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
`;
|
|
232
|
+
};
|
|
233
|
+
const printAccountRustTest = (c, policy) => {
|
|
234
|
+
const argNames = (c.constructorArgs || []).map(arg => arg.name);
|
|
235
|
+
const signerCount = Object.entries(testSignerCounts).reduce((total, [argName, count]) => (argNames.includes(argName) ? total + count : total), 0);
|
|
236
|
+
const hasEd25519 = argNames.includes('ed25519_keys');
|
|
237
|
+
const hasWebauthn = argNames.includes('webauthn_keys');
|
|
238
|
+
const hasPolicy = policy !== false;
|
|
239
|
+
// Every argument is spelled on its own line: the assembled tuple is otherwise
|
|
240
|
+
// far too long to read.
|
|
241
|
+
const registerArgs = argNames
|
|
242
|
+
.map(argName => ` ${testConstructorArgValues[argName](signerCount)},`)
|
|
243
|
+
.join('\n');
|
|
244
|
+
const hasMocks = hasEd25519 || hasWebauthn || hasPolicy;
|
|
245
|
+
const sorobanImports = [
|
|
246
|
+
...(hasPolicy ? ['auth::Context'] : []),
|
|
247
|
+
...(hasMocks ? ['contract', 'contractimpl'] : []),
|
|
248
|
+
'testutils::Address as _',
|
|
249
|
+
...(hasWebauthn ? ['xdr::FromXdr'] : []),
|
|
250
|
+
'Address',
|
|
251
|
+
...(hasEd25519 || hasWebauthn ? ['Bytes', 'BytesN'] : []),
|
|
252
|
+
'Env',
|
|
253
|
+
'Vec',
|
|
254
|
+
];
|
|
255
|
+
// Kept on separate lines so that enabling both verifiers does not import
|
|
256
|
+
// `Verifier` twice.
|
|
257
|
+
const libImports = [
|
|
258
|
+
...(hasPolicy
|
|
259
|
+
? [
|
|
260
|
+
`use stellar_accounts::policies::{ ${accountPolicies[policy].module}, Policy };`,
|
|
261
|
+
'use stellar_accounts::smart_account::{ ContextRule, Signer };',
|
|
262
|
+
]
|
|
263
|
+
: []),
|
|
264
|
+
...(hasEd25519 || hasWebauthn ? ['use stellar_accounts::verifiers::Verifier;'] : []),
|
|
265
|
+
...(hasEd25519 ? ['use stellar_accounts::verifiers::ed25519;'] : []),
|
|
266
|
+
...(hasWebauthn
|
|
267
|
+
? [
|
|
268
|
+
'use stellar_accounts::verifiers::utils::extract_from_bytes;',
|
|
269
|
+
'use stellar_accounts::verifiers::webauthn::{ self, WebAuthnSigData };',
|
|
270
|
+
]
|
|
271
|
+
: []),
|
|
272
|
+
];
|
|
273
|
+
const mockContracts = [
|
|
274
|
+
...(hasEd25519 ? [MOCK_ED25519_VERIFIER] : []),
|
|
275
|
+
...(hasWebauthn ? [MOCK_WEBAUTHN_VERIFIER] : []),
|
|
276
|
+
...(hasPolicy ? [printMockPolicyContract(policy)] : []),
|
|
277
|
+
];
|
|
278
|
+
const registrations = [
|
|
279
|
+
...(hasEd25519 ? [' let ed25519_verifier = env.register(MockEd25519Verifier, ());'] : []),
|
|
280
|
+
...(hasWebauthn ? [' let webauthn_verifier = env.register(MockWebauthnVerifier, ());'] : []),
|
|
281
|
+
...(hasPolicy ? [` let policy = env.register(${accountPolicies[policy].struct}, ());`] : []),
|
|
282
|
+
];
|
|
283
|
+
return `#![cfg(test)]
|
|
284
|
+
|
|
285
|
+
extern crate std;
|
|
286
|
+
|
|
287
|
+
use soroban_sdk::{ ${sorobanImports.join(', ')} };
|
|
288
|
+
${libImports.map(libImport => `${libImport}\n`).join('')}
|
|
289
|
+
use crate::contract::{ ${c.name}, ${c.name}Client };
|
|
290
|
+
${mockContracts.join('')}
|
|
291
|
+
#[test]
|
|
292
|
+
fn initial_state() {
|
|
293
|
+
let env = Env::default();
|
|
294
|
+
${hasPolicy ? ' env.mock_all_auths();\n' : ''}
|
|
295
|
+
${registrations.map(registration => `${registration}\n`).join('')}
|
|
296
|
+
let contract_addr = env.register(
|
|
297
|
+
${c.name},
|
|
298
|
+
(
|
|
299
|
+
${registerArgs}
|
|
300
|
+
),
|
|
301
|
+
);
|
|
302
|
+
let client = ${c.name}Client::new(&env, &contract_addr);
|
|
303
|
+
|
|
304
|
+
assert_eq!(client.get_context_rules_count(), 1);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Add more tests below
|
|
308
|
+
`;
|
|
309
|
+
};
|
|
310
|
+
exports.printAccountRustTest = printAccountRustTest;
|
|
101
311
|
const libDependencies = [
|
|
102
312
|
'stellar-tokens',
|
|
103
313
|
'stellar-access',
|
|
314
|
+
'stellar-accounts',
|
|
104
315
|
'stellar-contract-utils',
|
|
105
316
|
'stellar-governance',
|
|
106
317
|
'stellar-macros',
|
package/dist/zip-shared.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zip-shared.js","sourceRoot":"","sources":["../src/zip-shared.ts"],"names":[],"mappings":";;;AAYA,wCAIC;
|
|
1
|
+
{"version":3,"file":"zip-shared.js","sourceRoot":"","sources":["../src/zip-shared.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openzeppelin/wizard-stellar",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.5",
|
|
4
4
|
"description": "A boilerplate generator to get started with OpenZeppelin Stellar Soroban Contracts",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": "https://github.com/OpenZeppelin/contracts-wizard",
|
package/src/account.ts
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { ContractBuilder } from './contract';
|
|
2
|
+
import { addSelfAuthUpgradeable } from './add-upgradeable';
|
|
3
|
+
import { defineFunctions } from './utils/define-functions';
|
|
4
|
+
import type { CommonOptions } from './common-options';
|
|
5
|
+
import { withCommonDefaults, defaults as commonDefaults } from './common-options';
|
|
6
|
+
import { setInfo } from './set-info';
|
|
7
|
+
import { printContract } from './print';
|
|
8
|
+
import { OptionsError } from './error';
|
|
9
|
+
|
|
10
|
+
export const policyOptions = [false, 'simple-threshold', 'weighted-threshold'] as const;
|
|
11
|
+
|
|
12
|
+
export type Policy = (typeof policyOptions)[number];
|
|
13
|
+
|
|
14
|
+
// Verifier and policy contracts are deployment arguments, not wizard inputs: one
|
|
15
|
+
// wasm then works on both networks. The generated code points at the Stellar
|
|
16
|
+
// Registry, a third-party index of deployed contracts, so that whoever deploys
|
|
17
|
+
// has somewhere to start looking. Vetting the contract is up to them.
|
|
18
|
+
const REGISTRY_HINT = [
|
|
19
|
+
'Take one you trust from the Stellar Registry:',
|
|
20
|
+
'https://testnet.rgstry.xyz (testnet) or https://stellar.rgstry.xyz (mainnet).',
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
// Error code for the single runtime check the generated constructor performs.
|
|
24
|
+
// Kept clear of the library's ranges: `stellar_accounts` uses 3000+ for smart
|
|
25
|
+
// account errors and 3200+ for policy errors.
|
|
26
|
+
const WEIGHTS_LENGTH_MISMATCH_ERROR = 1;
|
|
27
|
+
|
|
28
|
+
export const defaults: Required<AccountOptions> = {
|
|
29
|
+
name: 'MyAccount',
|
|
30
|
+
delegatedSigners: true,
|
|
31
|
+
ed25519Signers: false,
|
|
32
|
+
webauthnSigners: false,
|
|
33
|
+
policy: 'simple-threshold',
|
|
34
|
+
executionEntryPoint: true,
|
|
35
|
+
upgradeable: false,
|
|
36
|
+
info: commonDefaults.info,
|
|
37
|
+
} as const;
|
|
38
|
+
|
|
39
|
+
export function printAccount(opts: AccountOptions = defaults): string {
|
|
40
|
+
return printContract(buildAccount(opts));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface AccountOptions extends CommonOptions {
|
|
44
|
+
name: string;
|
|
45
|
+
delegatedSigners?: boolean;
|
|
46
|
+
ed25519Signers?: boolean;
|
|
47
|
+
webauthnSigners?: boolean;
|
|
48
|
+
policy?: Policy;
|
|
49
|
+
executionEntryPoint?: boolean;
|
|
50
|
+
upgradeable?: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function withDefaults(opts: AccountOptions): Required<AccountOptions> {
|
|
54
|
+
return {
|
|
55
|
+
...opts,
|
|
56
|
+
...withCommonDefaults(opts),
|
|
57
|
+
delegatedSigners: opts.delegatedSigners ?? defaults.delegatedSigners,
|
|
58
|
+
ed25519Signers: opts.ed25519Signers ?? defaults.ed25519Signers,
|
|
59
|
+
webauthnSigners: opts.webauthnSigners ?? defaults.webauthnSigners,
|
|
60
|
+
policy: opts.policy ?? defaults.policy,
|
|
61
|
+
executionEntryPoint: opts.executionEntryPoint ?? defaults.executionEntryPoint,
|
|
62
|
+
upgradeable: opts.upgradeable ?? defaults.upgradeable,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function buildAccount(opts: AccountOptions): ContractBuilder {
|
|
67
|
+
const c = new ContractBuilder(opts.name);
|
|
68
|
+
|
|
69
|
+
const allOpts = withDefaults(opts);
|
|
70
|
+
|
|
71
|
+
// A context rule may legally hold only policies, but such an account could
|
|
72
|
+
// never authenticate anything, so a signer type is required here.
|
|
73
|
+
if (!allOpts.delegatedSigners && !allOpts.ed25519Signers && !allOpts.webauthnSigners) {
|
|
74
|
+
throw new OptionsError({
|
|
75
|
+
delegatedSigners: 'At least one signer type is required',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
addBase(c, allOpts);
|
|
80
|
+
|
|
81
|
+
if (allOpts.executionEntryPoint) {
|
|
82
|
+
addExecutionEntryPoint(c);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (allOpts.upgradeable) {
|
|
86
|
+
addSelfAuthUpgradeable(c);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
setInfo(c, allOpts.info);
|
|
90
|
+
|
|
91
|
+
return c;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// External signer types differ only in which verifier contract validates their
|
|
95
|
+
// signatures, so they share a constructor argument shape.
|
|
96
|
+
const externalSigners: { option: 'ed25519Signers' | 'webauthnSigners'; prefix: string; label: string }[] = [
|
|
97
|
+
{ option: 'ed25519Signers', prefix: 'ed25519', label: 'Ed25519' },
|
|
98
|
+
{ option: 'webauthnSigners', prefix: 'webauthn', label: 'WebAuthn' },
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
function contextRuleName(policy: Policy): string {
|
|
102
|
+
switch (policy) {
|
|
103
|
+
case false:
|
|
104
|
+
return 'default';
|
|
105
|
+
case 'simple-threshold':
|
|
106
|
+
return 'multisig';
|
|
107
|
+
case 'weighted-threshold':
|
|
108
|
+
return 'weighted-multisig';
|
|
109
|
+
default: {
|
|
110
|
+
const _: never = policy;
|
|
111
|
+
throw new Error('Unknown value for `policy`');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function addBase(c: ContractBuilder, opts: Required<AccountOptions>) {
|
|
117
|
+
c.addUseClause('soroban_sdk', 'contract');
|
|
118
|
+
c.addUseClause('soroban_sdk', 'contractimpl');
|
|
119
|
+
c.addUseClause('soroban_sdk', 'Address');
|
|
120
|
+
c.addUseClause('soroban_sdk', 'Env');
|
|
121
|
+
c.addUseClause('soroban_sdk', 'Map');
|
|
122
|
+
c.addUseClause('soroban_sdk', 'String');
|
|
123
|
+
c.addUseClause('soroban_sdk', 'Val');
|
|
124
|
+
c.addUseClause('soroban_sdk', 'Vec');
|
|
125
|
+
c.addUseClause('soroban_sdk::auth', 'Context');
|
|
126
|
+
c.addUseClause('soroban_sdk::auth', 'CustomAccountInterface');
|
|
127
|
+
c.addUseClause('soroban_sdk::crypto', 'Hash');
|
|
128
|
+
c.addUseClause('stellar_accounts::smart_account', 'self', { alias: 'smart_account' });
|
|
129
|
+
c.addUseClause('stellar_accounts::smart_account', 'AuthPayload');
|
|
130
|
+
// `ContextRule` is the return type of several `SmartAccount` methods, which the
|
|
131
|
+
// contracttrait macro needs in scope even though the generated code never
|
|
132
|
+
// names it.
|
|
133
|
+
c.addUseClause('stellar_accounts::smart_account', 'ContextRule');
|
|
134
|
+
c.addUseClause('stellar_accounts::smart_account', 'ContextRuleType');
|
|
135
|
+
c.addUseClause('stellar_accounts::smart_account', 'Signer');
|
|
136
|
+
c.addUseClause('stellar_accounts::smart_account', 'SmartAccount');
|
|
137
|
+
c.addUseClause('stellar_accounts::smart_account', 'SmartAccountError');
|
|
138
|
+
|
|
139
|
+
// The arguments the signers are read from, in assembly order: what `weights`
|
|
140
|
+
// is positionally aligned with.
|
|
141
|
+
const signerArgs: string[] = [];
|
|
142
|
+
const signerLines: string[] = ['let mut signers = Vec::new(e);'];
|
|
143
|
+
|
|
144
|
+
if (opts.delegatedSigners) {
|
|
145
|
+
signerArgs.push('delegated_signers');
|
|
146
|
+
c.addConstructorArgument({ name: 'delegated_signers', type: 'Vec<Address>' });
|
|
147
|
+
signerLines.push(
|
|
148
|
+
'for account in delegated_signers.iter() {',
|
|
149
|
+
' signers.push_back(Signer::Delegated(account));',
|
|
150
|
+
'}',
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
for (const { option, prefix, label } of externalSigners) {
|
|
155
|
+
if (!opts[option]) continue;
|
|
156
|
+
|
|
157
|
+
signerArgs.push(`${prefix}_keys`);
|
|
158
|
+
c.addUseClause('soroban_sdk', 'Bytes');
|
|
159
|
+
// Verifier contracts are stateless, immutable and shareable, so one address
|
|
160
|
+
// per signature type serves every key of that type.
|
|
161
|
+
c.addConstructorArgument({
|
|
162
|
+
name: `${prefix}_verifier`,
|
|
163
|
+
type: 'Address',
|
|
164
|
+
comment: [`${label} verifier contract, shared by every ${label} key.`, ...REGISTRY_HINT],
|
|
165
|
+
});
|
|
166
|
+
c.addConstructorArgument({ name: `${prefix}_keys`, type: 'Vec<Bytes>' });
|
|
167
|
+
signerLines.push(
|
|
168
|
+
`for key in ${prefix}_keys.iter() {`,
|
|
169
|
+
` signers.push_back(Signer::External(${prefix}_verifier.clone(), key));`,
|
|
170
|
+
'}',
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Adding the policy after the signers keeps the signer arguments first, which
|
|
175
|
+
// is the order `weights` is aligned with.
|
|
176
|
+
const policyCode = addPolicy(c, opts, signerArgs);
|
|
177
|
+
|
|
178
|
+
c.addConstructorCodeBlock([...signerLines, '']);
|
|
179
|
+
c.addConstructorCodeBlock([...policyCode, '']);
|
|
180
|
+
// The trait's `add_context_rule` requires auth from the account itself, which
|
|
181
|
+
// cannot be satisfied before any rule exists, so the constructor goes through
|
|
182
|
+
// the module-level function instead.
|
|
183
|
+
c.addConstructorCodeBlock([
|
|
184
|
+
'smart_account::add_context_rule(',
|
|
185
|
+
' e,',
|
|
186
|
+
' &ContextRuleType::Default,',
|
|
187
|
+
` &String::from_str(e, "${contextRuleName(opts.policy)}"),`,
|
|
188
|
+
' None,',
|
|
189
|
+
' &signers,',
|
|
190
|
+
' &policies,',
|
|
191
|
+
');',
|
|
192
|
+
]);
|
|
193
|
+
|
|
194
|
+
c.addTraitFunction(
|
|
195
|
+
{
|
|
196
|
+
traitName: 'CustomAccountInterface',
|
|
197
|
+
structName: c.name,
|
|
198
|
+
tags: ['contractimpl'],
|
|
199
|
+
assocType: ['type Error = SmartAccountError;', 'type Signature = AuthPayload;'],
|
|
200
|
+
priority: 0,
|
|
201
|
+
},
|
|
202
|
+
functions.__check_auth,
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
// Every `SmartAccount` method authorizes with
|
|
206
|
+
// `e.current_contract_address().require_auth()`, which routes back into
|
|
207
|
+
// `__check_auth` and the context rules, so the library defaults are kept as is.
|
|
208
|
+
c.addTraitImplBlock({
|
|
209
|
+
traitName: 'SmartAccount',
|
|
210
|
+
structName: c.name,
|
|
211
|
+
tags: ['contractimpl(contracttrait)'],
|
|
212
|
+
priority: 1,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Adds the policy constructor arguments and returns the code that builds the
|
|
218
|
+
* policy map passed to `add_context_rule`.
|
|
219
|
+
*/
|
|
220
|
+
function addPolicy(c: ContractBuilder, opts: Required<AccountOptions>, signerArgs: string[]): string[] {
|
|
221
|
+
if (opts.policy === false) {
|
|
222
|
+
return ['let policies: Map<Address, Val> = Map::new(e);'];
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
c.addUseClause('soroban_sdk', 'IntoVal');
|
|
226
|
+
|
|
227
|
+
const lines: string[] = [];
|
|
228
|
+
let installParam: string;
|
|
229
|
+
|
|
230
|
+
if (opts.policy === 'weighted-threshold') {
|
|
231
|
+
c.addUseClause('soroban_sdk', 'panic_with_error');
|
|
232
|
+
c.addUseClause('stellar_accounts::policies::weighted_threshold', 'WeightedThresholdAccountParams');
|
|
233
|
+
c.addError('WeightsLengthMismatch', WEIGHTS_LENGTH_MISMATCH_ERROR);
|
|
234
|
+
// A flat vector rather than a `Map<Signer, u32>` so that callers never have
|
|
235
|
+
// to spell out `Signer` values, which is the point of the typed
|
|
236
|
+
// per-signer-type arguments. The assembly order fixes the signer indices,
|
|
237
|
+
// so whoever deploys the contract needs to know it.
|
|
238
|
+
c.addConstructorArgument({
|
|
239
|
+
name: 'weights',
|
|
240
|
+
type: 'Vec<u32>',
|
|
241
|
+
comment:
|
|
242
|
+
signerArgs.length === 1
|
|
243
|
+
? [`One weight per signer, positionally aligned with \`${signerArgs[0]}\`.`]
|
|
244
|
+
: [
|
|
245
|
+
'One weight per signer, positionally aligned with the signers assembled',
|
|
246
|
+
`from ${signerArgs.join(', ')}, in that order.`,
|
|
247
|
+
],
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
lines.push(
|
|
251
|
+
'if weights.len() != signers.len() {',
|
|
252
|
+
` panic_with_error!(e, ${c.name}Error::WeightsLengthMismatch);`,
|
|
253
|
+
'}',
|
|
254
|
+
'',
|
|
255
|
+
'let mut signer_weights: Map<Signer, u32> = Map::new(e);',
|
|
256
|
+
'for (i, signer) in signers.iter().enumerate() {',
|
|
257
|
+
' signer_weights.set(signer, weights.get_unchecked(i as u32));',
|
|
258
|
+
'}',
|
|
259
|
+
'',
|
|
260
|
+
);
|
|
261
|
+
installParam = 'WeightedThresholdAccountParams { signer_weights, threshold }';
|
|
262
|
+
} else {
|
|
263
|
+
c.addUseClause('stellar_accounts::policies::simple_threshold', 'SimpleThresholdAccountParams');
|
|
264
|
+
installParam = 'SimpleThresholdAccountParams { threshold }';
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// The threshold is a deployment argument because it is only valid relative to
|
|
268
|
+
// the number of signers, which is not known when the contract is generated.
|
|
269
|
+
c.addConstructorArgument({ name: 'threshold', type: 'u32' });
|
|
270
|
+
c.addConstructorArgument({
|
|
271
|
+
name: 'threshold_policy',
|
|
272
|
+
type: 'Address',
|
|
273
|
+
comment: [
|
|
274
|
+
`${opts.policy === 'weighted-threshold' ? 'Weighted threshold' : 'Simple threshold'} policy contract.`,
|
|
275
|
+
...REGISTRY_HINT,
|
|
276
|
+
],
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
lines.push(
|
|
280
|
+
'let mut policies: Map<Address, Val> = Map::new(e);',
|
|
281
|
+
'policies.set(',
|
|
282
|
+
' threshold_policy,',
|
|
283
|
+
` ${installParam}.into_val(e),`,
|
|
284
|
+
');',
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
return lines;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Direct contract-to-contract calls are always authorized in Soroban, so an
|
|
291
|
+
// account needs this entry point to reach contracts it owns, such as its own
|
|
292
|
+
// policies, without the call re-entering `__check_auth`.
|
|
293
|
+
function addExecutionEntryPoint(c: ContractBuilder) {
|
|
294
|
+
c.addUseClause('stellar_accounts::smart_account', 'ExecutionEntryPoint');
|
|
295
|
+
// `execute` takes the target function name as a `Symbol`, which the
|
|
296
|
+
// contracttrait macro needs in scope.
|
|
297
|
+
c.addUseClause('soroban_sdk', 'Symbol');
|
|
298
|
+
|
|
299
|
+
c.addTraitImplBlock({
|
|
300
|
+
traitName: 'ExecutionEntryPoint',
|
|
301
|
+
structName: c.name,
|
|
302
|
+
tags: ['contractimpl(contracttrait)'],
|
|
303
|
+
priority: 2,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export const functions = defineFunctions({
|
|
308
|
+
// CustomAccountInterface Trait
|
|
309
|
+
__check_auth: {
|
|
310
|
+
args: [
|
|
311
|
+
{ name: 'e', type: 'Env' },
|
|
312
|
+
{ name: 'signature_payload', type: 'Hash<32>' },
|
|
313
|
+
{ name: 'signatures', type: 'AuthPayload' },
|
|
314
|
+
{ name: 'auth_contexts', type: 'Vec<Context>' },
|
|
315
|
+
],
|
|
316
|
+
returns: 'Result<(), Self::Error>',
|
|
317
|
+
code: ['smart_account::do_check_auth(&e, &signature_payload, &signatures, &auth_contexts)'],
|
|
318
|
+
},
|
|
319
|
+
});
|
package/src/add-upgradeable.ts
CHANGED
|
@@ -4,6 +4,35 @@ import { requireAccessControl } from './set-access-control';
|
|
|
4
4
|
import type { BaseFunction, ContractBuilder } from './contract';
|
|
5
5
|
import { defineFunctions } from './utils/define-functions';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Makes the contract upgradeable, authorized by the contract itself rather than
|
|
9
|
+
* by an access control role.
|
|
10
|
+
*
|
|
11
|
+
* Used by smart accounts, where authorization always flows through
|
|
12
|
+
* `__check_auth` and the account's context rules: an `Ownable`/`AccessControl`
|
|
13
|
+
* gate would add a second, weaker authorization path.
|
|
14
|
+
*/
|
|
15
|
+
export function addSelfAuthUpgradeable(c: ContractBuilder) {
|
|
16
|
+
c.addUseClause('soroban_sdk', 'Address');
|
|
17
|
+
c.addUseClause('soroban_sdk', 'BytesN');
|
|
18
|
+
c.addUseClause('stellar_contract_utils::upgradeable', 'self', { alias: 'upgradeable' });
|
|
19
|
+
c.addUseClause('stellar_contract_utils::upgradeable', 'Upgradeable');
|
|
20
|
+
|
|
21
|
+
c.addTraitFunction(
|
|
22
|
+
{
|
|
23
|
+
traitName: 'Upgradeable',
|
|
24
|
+
structName: c.name,
|
|
25
|
+
tags: ['contractimpl'],
|
|
26
|
+
section: 'Utils',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'upgrade',
|
|
30
|
+
args: [getSelfArg(), { name: 'new_wasm_hash', type: 'BytesN<32>' }, { name: '_operator', type: 'Address' }],
|
|
31
|
+
code: ['e.current_contract_address().require_auth()', 'upgradeable::upgrade(e, &new_wasm_hash)'],
|
|
32
|
+
},
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
7
36
|
export function addUpgradeable(c: ContractBuilder, access: Access, explicitImplementations: boolean) {
|
|
8
37
|
const functions = defineFunctions({
|
|
9
38
|
upgrade: {
|
package/src/api.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CommonContractOptions, CommonOptions } from './common-options';
|
|
2
|
+
import type { AccountOptions } from './account';
|
|
2
3
|
import type { FungibleOptions } from './fungible';
|
|
3
4
|
import type { GovernorOptions } from './governor';
|
|
4
5
|
import type { NonFungibleOptions } from './non-fungible';
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
defaults as nonFungibledefaults,
|
|
30
31
|
isAccessControlRequired as nonFungibleIsAccessControlRequired,
|
|
31
32
|
} from './non-fungible';
|
|
33
|
+
import { printAccount, defaults as accountDefaults } from './account';
|
|
32
34
|
|
|
33
35
|
export interface WizardContractAPI<Options extends CommonOptions> {
|
|
34
36
|
/**
|
|
@@ -50,12 +52,22 @@ export interface AccessControlAPI<Options extends CommonContractOptions> {
|
|
|
50
52
|
isAccessControlRequired: (opts: Partial<Options>) => boolean;
|
|
51
53
|
}
|
|
52
54
|
|
|
55
|
+
/**
|
|
56
|
+
* A smart account authorizes everything through `__check_auth` and its context
|
|
57
|
+
* rules, so it has no `access` option and therefore no `AccessControlAPI`.
|
|
58
|
+
*/
|
|
59
|
+
export type Account = WizardContractAPI<AccountOptions>;
|
|
53
60
|
export type Fungible = WizardContractAPI<FungibleOptions> & AccessControlAPI<FungibleOptions>;
|
|
54
61
|
export type Governor = WizardContractAPI<GovernorOptions> & AccessControlAPI<GovernorOptions>;
|
|
55
62
|
export type NonFungible = WizardContractAPI<NonFungibleOptions> & AccessControlAPI<NonFungibleOptions>;
|
|
56
63
|
export type Stablecoin = WizardContractAPI<StablecoinOptions> & AccessControlAPI<StablecoinOptions>;
|
|
57
64
|
export type Vault = WizardContractAPI<VaultOptions> & AccessControlAPI<VaultOptions>;
|
|
58
65
|
|
|
66
|
+
export const account: Account = {
|
|
67
|
+
print: printAccount,
|
|
68
|
+
defaults: accountDefaults,
|
|
69
|
+
};
|
|
70
|
+
|
|
59
71
|
export const fungible: Fungible = {
|
|
60
72
|
print: printFungible,
|
|
61
73
|
defaults: fungibledefaults,
|
package/src/build-generic.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { AccountOptions } from './account';
|
|
2
|
+
import { buildAccount } from './account';
|
|
1
3
|
import type { FungibleOptions } from './fungible';
|
|
2
4
|
import { buildFungible } from './fungible';
|
|
3
5
|
import type { GovernorOptions } from './governor';
|
|
@@ -10,6 +12,7 @@ import type { VaultOptions } from './vault';
|
|
|
10
12
|
import { buildVault } from './vault';
|
|
11
13
|
|
|
12
14
|
export interface KindedOptions {
|
|
15
|
+
Account: { kind: 'Account' } & AccountOptions;
|
|
13
16
|
Fungible: { kind: 'Fungible' } & FungibleOptions;
|
|
14
17
|
Governor: { kind: 'Governor' } & GovernorOptions;
|
|
15
18
|
NonFungible: { kind: 'NonFungible' } & NonFungibleOptions;
|
|
@@ -21,6 +24,9 @@ export type GenericOptions = KindedOptions[keyof KindedOptions];
|
|
|
21
24
|
|
|
22
25
|
export function buildGeneric(opts: GenericOptions) {
|
|
23
26
|
switch (opts.kind) {
|
|
27
|
+
case 'Account':
|
|
28
|
+
return buildAccount(opts);
|
|
29
|
+
|
|
24
30
|
case 'Fungible':
|
|
25
31
|
return buildFungible(opts);
|
|
26
32
|
|