Skip to content
This repository was archived by the owner on Aug 21, 2024. It is now read-only.

Commit 81afb7d

Browse files
authored
Update authorization docs to line up with contract examples (#106)
* Small fixes for token contract doc * Make authorization docs line up with the example
1 parent 38bc326 commit 81afb7d

File tree

2 files changed

+56
-71
lines changed

2 files changed

+56
-71
lines changed

docs/built-in-contracts/token-contract.mdx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,11 @@ which must provide authorization will vary depending on the unprivileged
5757
mutator. For example, a "grantor" can use `approve` to allow a "spender" to spend
5858
the grantor's money up to some limit. So for approve, the grantor must provide
5959
authorization. Similarly, a "sender" can use `xfer` to send money to a
60-
"recipient". So for `xfer`, the sender must provide authorization. The
61-
authorization for an unprivileged mutator is a [KeyedAuthorization](#keyedauthorization)
62-
because the identity that is providing the authorization must be specified.
60+
"recipient". So for `xfer`, the sender must provide authorization.
6361

6462
Priviliged mutators require authorization from a specific privileged identity,
6563
known as the "administrator". For example, only the administrator can `mint` more
6664
of the asset. Similarly, only the administrator can appoint a new administrator.
67-
The authorization for a privileged mutator is an [Authorization](#authorization)
68-
because the identity that is providing the authorization is known to be the
69-
administrator.
7065

7166
### Replay prevention
7267

@@ -91,17 +86,11 @@ pub fn approve(&self, from: &Keypair, spender: &Identifier, amount: &BigInt) {
9186
let from_id = to_ed25519(&self.env, from);
9287
let nonce = self.nonce(&from_id);
9388

94-
let mut args: Vec<RawVal> = Vec::new(&self.env);
95-
args.push_back(from_id.clone().into_val(&self.env));
96-
args.push_back(nonce.clone().into_val(&self.env));
97-
args.push_back(spender.clone().into_val(&self.env));
98-
args.push_back(amount.clone().into_val(&self.env));
99-
10089
let msg = SignaturePayload::V0(SignaturePayloadV0 {
10190
function: symbol!("approve"),
10291
contract: self.contract_id.clone(),
10392
network: self.env.ledger().network_passphrase(),
104-
args,
93+
args: (from_id, &nonce, spender, amount).into_val(&self.env),
10594
});
10695

10796
let auth = Signature::Ed25519(Ed25519Signature {

docs/examples/authorization.mdx

Lines changed: 54 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -42,31 +42,29 @@ test test::bad_data - should panic ... ok
4242
#[derive(Clone)]
4343
#[contracttype]
4444
pub enum DataKey {
45-
Acc(Identifier),
45+
SavedNum(Identifier),
4646
Nonce(Identifier),
4747
Admin,
4848
}
4949

5050
fn read_nonce(e: &Env, id: Identifier) -> BigInt {
5151
let key = DataKey::Nonce(id);
52-
if let Some(nonce) = e.contract_data().get(key) {
53-
nonce.unwrap()
54-
} else {
55-
BigInt::zero(e)
56-
}
52+
e.contract_data()
53+
.get(key)
54+
.unwrap_or_else(|| Ok(BigInt::zero(e)))
55+
.unwrap()
5756
}
58-
struct WrappedAuth(Signature);
57+
struct NonceForSignature(Signature);
5958

60-
impl NonceAuth for WrappedAuth {
59+
impl NonceAuth for NonceForSignature {
6160
fn read_nonce(e: &Env, id: Identifier) -> BigInt {
6261
read_nonce(e, id)
6362
}
6463

6564
fn read_and_increment_nonce(&self, e: &Env, id: Identifier) -> BigInt {
6665
let key = DataKey::Nonce(id.clone());
6766
let nonce = Self::read_nonce(e, id);
68-
e.contract_data()
69-
.set(key, nonce.clone() + BigInt::from_u32(e, 1));
67+
e.contract_data().set(key, &nonce + 1);
7068
nonce
7169
}
7270

@@ -75,12 +73,11 @@ impl NonceAuth for WrappedAuth {
7573
}
7674
}
7775

78-
pub struct AuthContract;
76+
pub struct ExampleContract;
7977

80-
#[cfg_attr(feature = "export", contractimpl)]
81-
#[cfg_attr(not(feature = "export"), contractimpl(export = false))]
82-
impl AuthContract {
83-
// Sets the admin identifier
78+
#[contractimpl]
79+
impl ExampleContract {
80+
/// Set the admin identifier. May be called only once.
8481
pub fn set_admin(e: Env, admin: Identifier) {
8582
if e.contract_data().has(DataKey::Admin) {
8683
panic!("admin is already set")
@@ -89,41 +86,41 @@ impl AuthContract {
8986
e.contract_data().set(DataKey::Admin, admin);
9087
}
9188

92-
// Saves data that corresponds to an Identifier, with that Identifiers authorization
93-
pub fn save_data(e: Env, auth: Signature, nonce: BigInt, num: BigInt) {
94-
let auth_id = auth.get_identifier(&e);
89+
/// Save the number for an authenticated [Identifier].
90+
pub fn save_num(e: Env, sig: Signature, nonce: BigInt, num: BigInt) {
91+
let auth_id = sig.get_identifier(&e);
9592

9693
check_auth(
9794
&e,
98-
&WrappedAuth(auth),
95+
&NonceForSignature(sig),
9996
nonce.clone(),
100-
Symbol::from_str("save_data"),
101-
(auth_id.clone(), nonce, num.clone()).into_val(&e),
97+
symbol!("save_num"),
98+
(&auth_id, nonce, &num).into_val(&e),
10299
);
103100

104-
e.contract_data().set(DataKey::Acc(auth_id), num);
101+
e.contract_data().set(DataKey::SavedNum(auth_id), num);
105102
}
106103

107104
// The admin can write data for any Identifier
108-
pub fn overwrite(e: Env, auth: Signature, nonce: BigInt, id: Identifier, num: BigInt) {
109-
let auth_id = auth.get_identifier(&e);
105+
pub fn overwrite(e: Env, sig: Signature, nonce: BigInt, id: Identifier, num: BigInt) {
106+
let auth_id = sig.get_identifier(&e);
110107
if auth_id != e.contract_data().get_unchecked(DataKey::Admin).unwrap() {
111108
panic!("not authorized by admin")
112109
}
113110

114111
check_auth(
115112
&e,
116-
&WrappedAuth(auth),
113+
&NonceForSignature(sig),
117114
nonce.clone(),
118-
Symbol::from_str("overwrite"),
119-
(auth_id, nonce, id.clone(), num.clone()).into_val(&e),
115+
symbol!("overwrite"),
116+
(auth_id, nonce, &id, &num).into_val(&e),
120117
);
121118

122-
e.contract_data().set(DataKey::Acc(id), num);
119+
e.contract_data().set(DataKey::SavedNum(id), num);
123120
}
124121

125-
pub fn nonce(e: Env, to: Identifier) -> BigInt {
126-
read_nonce(&e, to)
122+
pub fn nonce(e: Env, id: Identifier) -> BigInt {
123+
read_nonce(&e, id)
127124
}
128125
}
129126
```
@@ -182,7 +179,7 @@ pub struct AccountSignatures {
182179
}
183180
```
184181

185-
A Stellar account identity can provide authorization by signing an appropripate
182+
A Stellar account identity can provide authorization by signing an appropriate
186183
message with the private keys associated with the signers of that Stellar
187184
account. The total signing weight of the signers must exceed the medium
188185
threshold of that Stellar account. The authorization is a vector, where each
@@ -249,31 +246,30 @@ below that we have a `DataKey` for the nonce tied to an `Identifier`, and this
249246
#[derive(Clone)]
250247
#[contracttype]
251248
pub enum DataKey {
252-
Acc(Identifier),
249+
SavedNum(Identifier),
253250
Nonce(Identifier),
254251
Admin,
255252
}
256253

257254
fn read_nonce(e: &Env, id: Identifier) -> BigInt {
258255
let key = DataKey::Nonce(id);
259-
if let Some(nonce) = e.contract_data().get(key) {
260-
nonce.unwrap()
261-
} else {
262-
BigInt::zero(e)
263-
}
256+
e.contract_data()
257+
.get(key)
258+
.unwrap_or_else(|| Ok(BigInt::zero(e)))
259+
.unwrap()
264260
}
265-
struct WrappedAuth(Signature);
266261

267-
impl NonceAuth for WrappedAuth {
262+
struct NonceForSignature(Signature);
263+
264+
impl NonceAuth for NonceForSignature {
268265
fn read_nonce(e: &Env, id: Identifier) -> BigInt {
269266
read_nonce(e, id)
270267
}
271268

272269
fn read_and_increment_nonce(&self, e: &Env, id: Identifier) -> BigInt {
273270
let key = DataKey::Nonce(id.clone());
274271
let nonce = Self::read_nonce(e, id);
275-
e.contract_data()
276-
.set(key, nonce.clone() + BigInt::from_u32(e, 1));
272+
e.contract_data().set(key, &nonce + 1);
277273
nonce
278274
}
279275

@@ -284,32 +280,32 @@ impl NonceAuth for WrappedAuth {
284280
```
285281

286282
### Check authorization in contract function
287-
The `save_data` function stores data in a `DataKey::Acc` tied to an `Identifier`
283+
The `save_num` function stores a number in a `DataKey::SavedNum` tied to an `Identifier`
288284
with it's authorization.
289285

290286
The `check_auth` method in the SDK is used for signature verification, and here
291287
are the important authorization takeaways from the example below -
292288
1. The `nonce` is included in the list of parameters for the contract function.
293-
2. The `Signature` is passed into `check_auth` wrapped in `WrappedAuth`.
289+
2. The `Signature` is passed into `check_auth` wrapped in `NonceForSignature`.
294290
3. The `function` parameter to `check_auth` is the name of the invoked function.
295291
4. The last argument passed to `check_auth` is a list of arguments that are
296292
expected in the signed payload. The interesting thing to note here is that it
297-
includes the `Identifier` from the `auth` and the nonce.
293+
includes the `Identifier` from the `sig` and the nonce.
298294

299295
```rust
300-
// Saves data that corresponds to an Identifier, with that Identifiers authorization
301-
pub fn save_data(e: Env, auth: Signature, nonce: BigInt, num: BigInt) {
302-
let auth_id = auth.get_identifier(&e);
296+
/// Save the number for an authenticated [Identifier].
297+
pub fn save_num(e: Env, sig: Signature, nonce: BigInt, num: BigInt) {
298+
let auth_id = sig.get_identifier(&e);
303299

304300
check_auth(
305301
&e,
306-
&WrappedAuth(auth),
302+
&NonceForSignature(sig),
307303
nonce.clone(),
308-
Symbol::from_str("save_data"),
309-
(auth_id.clone(), nonce, num.clone()).into_val(&e),
304+
symbol!("save_num"),
305+
(&auth_id, nonce, &num).into_val(&e),
310306
);
311307

312-
e.contract_data().set(DataKey::Acc(auth_id), num);
308+
e.contract_data().set(DataKey::SavedNum(auth_id), num);
313309
}
314310
```
315311

@@ -329,22 +325,22 @@ pub fn set_admin(e: Env, admin: Identifier) {
329325
e.contract_data().set(DataKey::Admin, admin);
330326
}
331327

332-
// The admin can write data for any Identifier
333-
pub fn overwrite(e: Env, auth: Signature, nonce: BigInt, id: Identifier, num: BigInt) {
334-
let auth_id = auth.get_identifier(&e);
328+
// The admin can write the number for any [Identifier]
329+
pub fn overwrite(e: Env, sig: Signature, nonce: BigInt, id: Identifier, num: BigInt) {
330+
let auth_id = sig.get_identifier(&e);
335331
if auth_id != e.contract_data().get_unchecked(DataKey::Admin).unwrap() {
336332
panic!("not authorized by admin")
337333
}
338334

339335
check_auth(
340336
&e,
341-
&WrappedAuth(auth),
337+
&NonceForSignature(sig),
342338
nonce.clone(),
343-
Symbol::from_str("overwrite"),
344-
(auth_id, nonce, id.clone(), num.clone()).into_val(&e),
339+
symbol!("overwrite"),
340+
(auth_id, nonce, &id, &num).into_val(&e),
345341
);
346342

347-
e.contract_data().set(DataKey::Acc(id), num);
343+
e.contract_data().set(DataKey::SavedNum(id), num);
348344
}
349345
```
350346

0 commit comments

Comments
 (0)