Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "stellar-hello-world-contract"
description = "A simple hello world contract"
name = "guess-the-number"
description = "Admin sets up the pot, anyone can guess to win it"
edition.workspace = true
license.workspace = true
repository.workspace = true
Expand Down
52 changes: 52 additions & 0 deletions contracts/guess-the-number/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#![no_std]
use soroban_sdk::{contract, contractimpl, symbol_short, Address, BytesN, Env, Symbol};

#[contract]
pub struct GuessTheNumber;

const THE_NUMBER: Symbol = symbol_short!("n");
pub const ADMIN_KEY: &Symbol = &symbol_short!("ADMIN");

#[contractimpl]
impl GuessTheNumber {
pub fn __constructor(env: &Env, admin: Address) {
Self::set_admin(env, &admin);
}

/// Update the number. Only callable by admin.
pub fn reset(env: &Env) {
Self::require_admin(env);
let new_number: u64 = env.prng().gen_range(1..=10);
env.storage().instance().set(&THE_NUMBER, &new_number);
}

/// Guess a number between 1 and 10
pub fn guess(env: &Env, a_number: u64) -> bool {
a_number == env.storage().instance().get::<_, u64>(&THE_NUMBER).unwrap()
}

/// Upgrade the contract to new wasm. Only callable by admin.
pub fn upgrade(env: &Env, new_wasm_hash: BytesN<32>) {
Self::require_admin(env);
env.deployer().update_current_contract_wasm(new_wasm_hash);
}

fn admin(env: &Env) -> Option<Address> {
env.storage().instance().get(ADMIN_KEY)
}

fn set_admin(env: &Env, admin: &Address) {
// Check if admin is already set
if env.storage().instance().has(ADMIN_KEY) {
panic!("admin already set");
}
env.storage().instance().set(ADMIN_KEY, admin);
}

fn require_admin(env: &Env) {
let admin = Self::admin(env).expect("admin not set");
admin.require_auth();
}
}

mod test;
64 changes: 64 additions & 0 deletions contracts/guess-the-number/src/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#![cfg(test)]
extern crate std;

use super::*;
use soroban_sdk::{
testutils::{Address as _, MockAuth, MockAuthInvoke},
Address, Env, IntoVal, Val, Vec,
};

#[test]
fn only_admin_can_reset() {
let env = &Env::default();

let admin = Address::generate(env);
let user = Address::generate(env);

let client = generate_client(env, &admin);

set_caller(&client, "reset", &user, ());
assert!(client.try_reset().is_err());

set_caller(&client, "reset", &admin, ());
assert!(client.try_reset().is_ok());
}

#[test]
fn one_guess_in_ten_returns_true() {
let env = &Env::default();

let admin = Address::generate(env);

let client = generate_client(env, &admin);

// set the number
set_caller(&client, "reset", &admin, ());
client.reset();

let trues: std::vec::Vec<_> = (1u64..=10).filter(|number| client.guess(number)).collect();
assert_eq!(trues.len(), 1);
}

fn generate_client<'a>(env: &Env, admin: &Address) -> GuessTheNumberClient<'a> {
let contract_id = env.register(GuessTheNumber, (admin,));
GuessTheNumberClient::new(env, &contract_id)
}

fn set_caller<T>(client: &GuessTheNumberClient, method: &str, caller: &Address, args: T)
where
T: IntoVal<Env, Vec<Val>>,
{
// clear previous auth mocks
client.env.set_auths(&[]);

// mock auth as passed-in address
client.env.mock_auths(&[MockAuth {
address: caller,
invoke: &MockAuthInvoke {
contract: &client.address,
fn_name: method,
args: args.into_val(&client.env),
sub_invokes: &[],
},
}]);
}
14 changes: 0 additions & 14 deletions contracts/hello_world/src/lib.rs

This file was deleted.

21 changes: 0 additions & 21 deletions contracts/hello_world/src/test.rs

This file was deleted.

25 changes: 10 additions & 15 deletions environments.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ name = "me" # Required. Keys for this account will be saved to `./.stellar/ident
default = true # Optional. Whether to use this account as the `--source` for commands that need one.

[development.contracts]
fungible_token_interface_example = { client = true, constructor_args = "--owner me --initial_supply 1000000000000000000000000" }
nft_enumerable_example = { client = true, constructor_args = "--owner me" }

# Rather than in one list, TOML allows specifying contracts in their own "sections"
[development.contracts.guess_the_number]
# Generate a contract client (NPM package) for this contract. This means:
# - compile (build) the contract source to Wasm
# - deploy the contract to the `network` specified above
Expand All @@ -20,27 +25,17 @@ default = true # Optional. Whether to use this account as the `--source` for com
# You can only use `client = true` when:
# - the contract source must be part of the local Cargo workspace (in the
# PROJECT_ROOT/contracts folder)
# - The specified name here ("stellar_hello_world_contract") must match the
# - The specified name here ("guess_the_number") must match the
# underscored-version of the `name` in the contract's Cargo.toml.
# - The environment is `development` or `testing`
stellar_hello_world_contract = { client = true }

# Rather than in one list, TOML allows specifying contracts in their own "sections"
[development.contracts.fungible_token_interface_example]
client = true

# If your contract has a `__constructor`, specify your arguments to it here.
# These are the same arguments you could pass after the `--` in a call to
# `stellar contract deploy`
# Only available in `development` and `testing` environments
constructor_args = """
--owner me --initial_supply "1000000000000000000000000"
"""

[development.contracts.nft_enumerable_example]
client = true
constructor_args = """
--owner me
--admin me
"""

# Calls to the contract to make after it's deployed and initialized with
Expand All @@ -59,9 +54,9 @@ constructor_args = """
# `STELLAR_ACCOUNT=other-account`.
#
# Only supported in `development` and `testing` environments.
# after_deploy = """
# mint --amount 2000000 --to me"
# """
after_deploy = """
reset
"""

# Coming Soon: Specify live contracts to bind & import in this project using the given name.
# During initialization, these contracts will also be "spooned" into the development network,
Expand Down
Loading
Loading