Skip to content

Commit d4dfee1

Browse files
committed
feat: add iota_account2
1 parent f409c20 commit d4dfee1

File tree

2 files changed

+174
-0
lines changed

2 files changed

+174
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[package]
2+
name = "iota_account2"
3+
edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move
4+
# license = "" # e.g., "MIT", "GPL", "Apache 2.0"
5+
# authors = ["..."] # e.g., ["Joe Smith ([email protected])", "John Snow ([email protected])"]
6+
7+
[dependencies]
8+
Iota = { local = "../../../crates/iota-framework/packages/iota-framework" }
9+
10+
# For remote import, use the `{ git = "...", subdir = "...", rev = "..." }`.
11+
# Revision can be a branch, a tag, and a commit hash.
12+
# MyRemotePackage = { git = "https://some.remote/host.git", subdir = "remote/path", rev = "main" }
13+
14+
# For local dependencies use `local = path`. Path is relative to the package root
15+
# Local = { local = "../path/to" }
16+
17+
# To resolve a version conflict and force a specific version for dependency
18+
# override use `override = true`
19+
# Override = { local = "../conflicting/version", override = true }
20+
21+
[addresses]
22+
iota_account2 = "0x0"
23+
24+
# Named addresses will be accessible in Move as `@name`. They're also exported:
25+
# for example, `std = "0x1"` is exported by the Standard Library.
26+
# alice = "0xA11CE"
27+
28+
[dev-dependencies]
29+
# The dev-dependencies section allows overriding dependencies for `--test` and
30+
# `--dev` modes. You can introduce test-only dependencies here.
31+
# Local = { local = "../path/to/dev-build" }
32+
33+
[dev-addresses]
34+
# The dev-addresses section allows overwriting named addresses for the `--test`
35+
# and `--dev` modes.
36+
# alice = "0xB0B"
37+
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
module iota_account2::iota_account;
2+
3+
use iota::account::{Self, AuthenticatorInfoV1};
4+
use iota::auth_context::AuthContext;
5+
use iota::dynamic_field;
6+
use iota::ecdsa_k1;
7+
use iota::ecdsa_r1;
8+
use iota::ed25519;
9+
10+
/// A dynamic field name for the account owner public key.
11+
const IOTACCOUNT_OWNER_PUBKEY: vector<u8> = b"IOTACCOUNT_OWNER_PUBKEY";
12+
13+
/// This struct represents an IOTA account on-chain.
14+
/// It holds all the related data as dynamic fields to simplify updates and migrations.
15+
public struct IOTAccount has key {
16+
id: UID,
17+
}
18+
19+
// --------------------------------------- Creation ---------------------------------------
20+
21+
/// Creates a new `IOTAccount` as a shared object with the given authenticator.
22+
///
23+
/// `authenticator` is expect to have the following signature:
24+
///
25+
/// public fun authenticate(self: &IOTAccount, signature: vector<u8>, _: &AuthContext, _: &TxContext) { ... }
26+
///
27+
/// And it is expected to verify the `signature` against the public key stored in the account.
28+
///
29+
/// There are several ready-made authenticators available in this module:
30+
/// - `authenticate_ed25519`
31+
/// - `authenticate_secp256k1`
32+
/// - `authenticate_secp256r1`
33+
public fun create(pubkey: vector<u8>, authenticator: AuthenticatorInfoV1, ctx: &mut TxContext) {
34+
let mut account = IOTAccount { id: object::new(ctx) };
35+
36+
// Check the flag in `pubkey` is the same as the input scheme.
37+
//assert!(check_scheme(pubkey, scheme));
38+
39+
let account_id = &mut account.id;
40+
41+
// Add the account owner public key as a dynamic field.
42+
dynamic_field::add(account_id, IOTACCOUNT_OWNER_PUBKEY, pubkey);
43+
44+
// Add the authenticator info as a dynamic field.
45+
dynamic_field::add(account_id, account::authenticator_df_name(), authenticator);
46+
47+
// Turn the account object into a mutable shared object.
48+
iota::transfer::share_object(account);
49+
}
50+
51+
// --------------------------------------- Field Operations ---------------------------------------
52+
53+
/// Adds a new dynamic field to the account.
54+
public fun add_field<Name: copy + drop + store, Value: store>(
55+
self: &mut IOTAccount,
56+
name: Name,
57+
value: Value,
58+
ctx: &TxContext,
59+
) {
60+
// Check that the sender of this TX is the account.
61+
assert!(self.id.uid_to_address() == ctx.sender());
62+
63+
// Add a new field.
64+
dynamic_field::add(&mut self.id, name, value);
65+
}
66+
67+
/// Removes a dynamic field from the account.
68+
public fun remove_field<Name: copy + drop + store, Value: store>(
69+
self: &mut IOTAccount,
70+
name: Name,
71+
ctx: &TxContext,
72+
): Value {
73+
// Check that the sender of this TX is the account.
74+
assert!(self.id.uid_to_address() == ctx.sender());
75+
76+
// Remove a new field.
77+
dynamic_field::remove(&mut self.id, name)
78+
}
79+
80+
public fun borrow_field<Name: copy + drop + store, Value: store>(
81+
self: &IOTAccount,
82+
name: Name,
83+
ctx: &TxContext,
84+
): &Value {
85+
let id = &self.id;
86+
// Check that the sender of this TX is the account.
87+
assert!(id.uid_to_address() == ctx.sender());
88+
89+
dynamic_field::borrow(&self.id, name)
90+
}
91+
92+
public fun borrow_field_mut<Name: copy + drop + store, Value: store>(
93+
self: &mut IOTAccount,
94+
name: Name,
95+
ctx: &TxContext,
96+
): &mut Value {
97+
let id = &self.id;
98+
// Check that the sender of this TX is the account.
99+
assert!(id.uid_to_address() == ctx.sender());
100+
101+
dynamic_field::borrow_mut(&mut self.id, name)
102+
}
103+
104+
// --------------------------------------- Authentication ---------------------------------------
105+
106+
/// Ed25519 signature authenticator.
107+
public fun authenticate_ed25519(
108+
self: &IOTAccount,
109+
signature: vector<u8>,
110+
_: &AuthContext,
111+
ctx: &TxContext,
112+
) {
113+
let pubkey: &vector<u8> = borrow_field(self, IOTACCOUNT_OWNER_PUBKEY, ctx);
114+
assert!(ed25519::ed25519_verify(&signature, pubkey, ctx.digest()));
115+
}
116+
117+
/// Secp256k1 signature authenticator.
118+
public fun authenticate_secp256k1(
119+
self: &IOTAccount,
120+
signature: vector<u8>,
121+
_: &AuthContext,
122+
ctx: &TxContext,
123+
) {
124+
let pubkey: &vector<u8> = borrow_field(self, IOTACCOUNT_OWNER_PUBKEY, ctx);
125+
assert!(ecdsa_k1::secp256k1_verify(&signature, pubkey, ctx.digest(), 0));
126+
}
127+
128+
/// Secp256r1 signature authenticator.
129+
public fun authenticate_secp256r1(
130+
self: &IOTAccount,
131+
signature: vector<u8>,
132+
_: &AuthContext,
133+
ctx: &TxContext,
134+
) {
135+
let pubkey: &vector<u8> = borrow_field(self, IOTACCOUNT_OWNER_PUBKEY, ctx);
136+
assert!(ecdsa_r1::secp256r1_verify(&signature, pubkey, ctx.digest(), 0));
137+
}

0 commit comments

Comments
 (0)