Skip to content

Commit

Permalink
wip: factory
Browse files Browse the repository at this point in the history
  • Loading branch information
gagdiez committed Sep 4, 2024
1 parent b70459c commit 629b1b2
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 90 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ crate-type = ["cdylib", "rlib"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
near-sdk = { version = "5.1.0", features = ["unstable"] }
near-sdk = { version = "5.3.0", features = ["unstable"] }
near-contract-standards = "5.3.0"

[dev-dependencies]
near-sdk = { version = "5.1.0", features = ["unit-testing"] }
near-sdk = { version = "5.3.0", features = ["unit-testing"] }
near-workspaces = { version = "0.10.0", features = ["unstable"] }
tokio = { version = "1.12.0", features = ["full"] }
serde_json = "1"
Expand Down
88 changes: 32 additions & 56 deletions src/deploy.rs
Original file line number Diff line number Diff line change
@@ -1,87 +1,63 @@
use near_sdk::serde::Serialize;
use near_sdk::{env, log, near, AccountId, NearToken, Promise, PromiseError, PublicKey};
use near_sdk::{env, json_types::U128, log, near, require, AccountId, NearToken, Promise, PromiseError, PublicKey};
use near_contract_standards::fungible_token::metadata::FungibleTokenMetadata;

use crate::{Contract, ContractExt, NEAR_PER_STORAGE, NO_DEPOSIT, TGAS};
use crate::{Contract, ContractExt, FT_CONTRACT, NEAR_PER_STORAGE, NO_DEPOSIT, TGAS};

#[derive(Serialize)]
#[serde(crate = "near_sdk::serde")]
struct DonationInitArgs {
beneficiary: AccountId,

#[near(serializers = [json])]
pub struct TokenArgs {
owner_id: AccountId,
total_supply: U128,
metadata: FungibleTokenMetadata,
}

#[near]
impl Contract {

fn get_required(&self, args: &TokenArgs) -> u128 {
((FT_WASM_CODE.len() + EXTRA_BYTES + args.try_to_vec().unwrap().len() * 2) as NearToken)
* STORAGE_PRICE_PER_BYTE)
.into()
}

#[payable]
pub fn create_factory_subaccount_and_deploy(
pub fn create_token(
&mut self,
name: String,
beneficiary: AccountId,
public_key: Option<PublicKey>,
args: TokenArgs,
) -> Promise {
args.metadata.assert_valid();
let token_id = args.metadata.symbol.to_ascii_lowercase();

require!(is_valid_token_id(&token_id), "Invalid Symbol");

// Assert the sub-account is valid
let current_account = env::current_account_id().to_string();
let subaccount: AccountId = format!("{name}.{current_account}").parse().unwrap();
let token_account_id = format!("{}.{}", token_id, env::current_account_id());
assert!(
env::is_valid_account_id(subaccount.as_bytes()),
"Invalid subaccount"
env::is_valid_account_id(token_account_id.as_bytes()),
"Token Account ID is invalid"
);

// Assert enough tokens are attached to create the account and deploy the contract
let attached = env::attached_deposit();
let required = self.get_required(&args);

let code = self.code.clone().unwrap();
let contract_bytes = code.len() as u128;
let minimum_needed = NEAR_PER_STORAGE.saturating_mul(contract_bytes);
assert!(
attached >= minimum_needed,
attached >= required,
"Attach at least {minimum_needed} yⓃ"
);

let init_args = near_sdk::serde_json::to_vec(&DonationInitArgs { beneficiary }).unwrap();
let init_args = near_sdk::serde_json::to_vec(args).unwrap();

let mut promise = Promise::new(subaccount.clone())
.create_account()
.transfer(attached)
.deploy_contract(code)
.deploy_contract(FT_CONTRACT)
.function_call(
"init".to_owned(),
"new".to_owned(),
init_args,
NO_DEPOSIT,
TGAS.saturating_mul(5),
TGAS.saturating_mul(50),
);

// Add full access key is the user passes one
if let Some(pk) = public_key {
promise = promise.add_full_access_key(pk);
}

// Add callback
promise.then(
Self::ext(env::current_account_id()).create_factory_subaccount_and_deploy_callback(
subaccount,
env::predecessor_account_id(),
attached,
),
)
}

#[private]
pub fn create_factory_subaccount_and_deploy_callback(
&mut self,
account: AccountId,
user: AccountId,
attached: NearToken,
#[callback_result] create_deploy_result: Result<(), PromiseError>,
) -> bool {
if let Ok(_result) = create_deploy_result {
log!(format!("Correctly created and deployed to {account}"));
return true;
};

log!(format!(
"Error creating {account}, returning {attached}yⓃ to {user}"
));
Promise::new(user).transfer(attached);
false
}
}
Binary file removed src/donation-contract/donation.wasm
Binary file not shown.
Binary file added src/ft-contract/ft.wasm
Binary file not shown.
16 changes: 3 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,19 @@ use near_sdk::store::LazyOption;
use near_sdk::{near, Gas, NearToken};

mod deploy;
mod manager;

const NEAR_PER_STORAGE: NearToken = NearToken::from_yoctonear(10u128.pow(18)); // 10e18yⓃ
const DEFAULT_CONTRACT: &[u8] = include_bytes!("./donation-contract/donation.wasm");
const FT_CONTRACT: &[u8] = include_bytes!("./ft-contract/ft.wasm");
const TGAS: Gas = Gas::from_tgas(1); // 10e12yⓃ
const NO_DEPOSIT: NearToken = NearToken::from_near(0); // 0yⓃ

// Define the contract structure
#[near(contract_state)]
pub struct Contract {
// Since a contract is something big to store, we use LazyOptions
// this way it is not deserialized on each method call
code: LazyOption<Vec<u8>>,
// Please note that it is much more efficient to **not** store this
// code in the state, and directly use `DEFAULT_CONTRACT`
// However, this does not enable to update the stored code.
}
pub struct Contract { }

// Define the default, which automatically initializes the contract
impl Default for Contract {
fn default() -> Self {
Self {
code: LazyOption::new("code".as_bytes(), Some(DEFAULT_CONTRACT.to_vec())),
}
Self { }
}
}
19 changes: 0 additions & 19 deletions src/manager.rs

This file was deleted.

0 comments on commit 629b1b2

Please sign in to comment.