diff --git a/CMakeLists.txt b/CMakeLists.txt index f01e929..7a541b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,8 +86,8 @@ target_link_libraries(sequence-demo PRIVATE sequence_c_sdk) # ---- CLI ---- -add_executable(sequence-cli cli.c) -target_link_libraries(sequence-cli PRIVATE sequence_c_sdk) +add_executable(sequence-wallet cli.c) +target_link_libraries(sequence-wallet PRIVATE sequence_c_sdk) # ---- Install ---- @@ -96,7 +96,7 @@ install(TARGETS sequence_c_sdk LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(TARGETS sequence-demo sequence-cli +install(TARGETS sequence-demo sequence-wallet RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(DIRECTORY lib/ diff --git a/Formula/wallet.rb b/Formula/wallet.rb index 51b1115..a7e6197 100644 --- a/Formula/wallet.rb +++ b/Formula/wallet.rb @@ -19,6 +19,6 @@ def install test do # Basic smoke test - assert_match "Usage", shell_output("#{bin}/sequence --help") + assert_match "Usage", shell_output("#{bin}/sequence-wallet --help") end end \ No newline at end of file diff --git a/README.md b/README.md index ca7cb25..07b2a63 100644 --- a/README.md +++ b/README.md @@ -45,28 +45,28 @@ cmake --build build ```shell # Init -./build/sequence-cli init --access_key AQAAAAAAAAK2JvvZhWqZ51riasWBftkrVXE +./build/sequence-wallet init --access-key AQAAAAAAAAK2JvvZhWqZ51riasWBftkrVXE # Get token balances -./build/sequence-cli get_token_balances --chain_id 137 --contract_address 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 --wallet_address 0x8e3E38fe7367dd3b52D1e281E4e8400447C8d8B9 --include_metadata +./build/sequence-wallet get-token-balances --chain-id 137 --contract-address 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 --wallet-address 0x8e3E38fe7367dd3b52D1e281E4e8400447C8d8B9 --include-metadata # Sign in with Email -./build/sequence-cli sign_in_with_email --email andygruening@gmail.com +./build/sequence-wallet sign-in-with-email --email andygruening@gmail.com # Confirm Email sign in -./build/sequence-cli confirm_email_sign_in --email andygruening@gmail.com --code 123456 +./build/sequence-wallet confirm-email-sign-in --email andygruening@gmail.com --code 123456 --wallet-type Ethereum_SequenceV3 # Use wallet -./build/sequence-cli use_wallet --wallet_type Ethereum_SequenceV3 +./build/sequence-wallet use-wallet --wallet-type Ethereum_SequenceV3 # Create wallet -./build/sequence-cli create_wallet +./build/sequence-wallet create-wallet # Sign message -./build/sequence-cli sign_message --chain_id 80002 --message test +./build/sequence-wallet sign-message --chain-id 80002 --message test # Send transaction -./build/sequence-cli send_transaction --chain_id 80002 --to 0xE5E8B483FfC05967FcFed58cc98D053265af6D99 --value 1000 +./build/sequence-wallet send-transaction --chain-id 80002 --to 0xE5E8B483FfC05967FcFed58cc98D053265af6D99 --value 1000 ``` #### Homebrew version release diff --git a/cli.c b/cli.c index 664a25d..f1587e8 100644 --- a/cli.c +++ b/cli.c @@ -2,6 +2,8 @@ #include #include #include +#include + #include "wallet/sequence_config.h" #include "wallet/sequence_wallet.h" #include "indexer/get_token_balances.h" @@ -30,14 +32,68 @@ void print_use_case(char *title, char *command) { void print_first_steps() { printf("\nLet's get things rolling!\n"); - print_use_case("Get Token Balances", "sequence-cli get_token_balances --chain_id --contract_address
--wallet_address
--include_metadata"); - print_use_case("Sign In with Email", "sequence-cli sign_in_with_email --email "); + print_use_case("Get Token Balances", "sequence-wallet get-token-balances --chain-id --contract-address
--wallet-address
--include-metadata"); + print_use_case("Sign In with Email", "sequence-wallet sign-in-with-email --email "); } void print_use_cases() { printf("\nLet’s try out some features!\n"); - print_use_case("Sign Message", "sequence-cli sign_message --chain_id --message "); - print_use_case("Send Transaction", "sequence-cli send_transaction --chain_id --to
--value "); + print_use_case("Sign Message", "sequence-wallet sign-message --chain-id --message "); + print_use_case("Send Transaction", "sequence-wallet send-transaction --chain-id --to
--value "); +} + +void print_help(const char *prog) { + printf( + "Sequence Wallet CLI\n" + "\n" + "Usage:\n" + " %s [options]\n" + "\n" + "Commands:\n" + " init\n" + " Initialize project\n" + " --access-key \n" + "\n" + " get-token-balances\n" + " Fetch token balances\n" + " --chain-id \n" + " --contract-address
\n" + " --wallet-address
\n" + " --include-metadata\n" + "\n" + " sign-in-with-email\n" + " Start email sign-in\n" + " --email \n" + "\n" + " confirm-email-sign-in\n" + " Confirm email sign-in\n" + " --email \n" + " --code \n" + " --wallet_type (optional)\n" + "\n" + " use-wallet\n" + " Select wallet type\n" + " --wallet-type \n" + "\n" + " create-wallet\n" + " Create a new wallet\n" + " --wallet-type (optional)\n" + "\n" + " sign-message\n" + " Sign a message\n" + " --chain-id \n" + " --message \n" + "\n" + " send-transaction\n" + " Send a transaction\n" + " --chain-id \n" + " --to
\n" + " --value \n" + "\n" + "Options:\n" + " -h, --help Show this help message\n", + prog + ); } int main(int argc, char **argv) { @@ -48,35 +104,40 @@ int main(int argc, char **argv) { const char *cmd = argv[1]; - if (strcmp(cmd, "init") != 0) { + if (strcmp(cmd, "init") != 0 && strcmp(argv[1], "--help") != 0 && strcmp(argv[1], "-h") != 0) { char *access_key = NULL; - secure_store_read_string("access_key", &access_key); + secure_store_read_string("access-key", &access_key); sequence_config_init(access_key); } - if (strcmp(cmd, "init") == 0) { + if (strcmp(argv[1], "--help") == 0 || + strcmp(argv[1], "-h") == 0) { + + print_help("sequence-wallet"); + + } else if (strcmp(cmd, "init") == 0) { print_header("Initialization"); const char *access_key = NULL; // Parse CLI args for (int i = 2; i < argc; i++) { - if (strcmp(argv[i], "--access_key") == 0 && i + 1 < argc) { + if (strcmp(argv[i], "--access-key") == 0 && i + 1 < argc) { access_key = argv[++i]; } } if (!access_key) { - fprintf(stderr, "Missing --access_key\n"); + fprintf(stderr, "Missing --access-key\n"); return 1; } - secure_store_write_string("access_key", access_key); + secure_store_write_string("access-key", access_key); printf("The access key has been successfully initialized.\n"); print_first_steps(); - } else if (strcmp(cmd, "get_token_balances") == 0) { + } else if (strcmp(cmd, "get-token-balances") == 0) { print_header("Get Token Balances"); const char *chain_id = NULL; @@ -85,119 +146,207 @@ int main(int argc, char **argv) { bool include_metadata = false; for (int i = 2; i < argc; i++) { - if (strcmp(argv[i], "--chain_id") == 0 && i + 1 < argc) chain_id = argv[++i]; - else if (strcmp(argv[i], "--contract_address") == 0 && i + 1 < argc) contract_address = argv[++i]; - else if (strcmp(argv[i], "--wallet_address") == 0 && i + 1 < argc) wallet_address = argv[++i]; - else if (strcmp(argv[i], "--include_metadata") == 0) include_metadata = true; + if (strcmp(argv[i], "--chain-id") == 0 && i + 1 < argc) chain_id = argv[++i]; + else if (strcmp(argv[i], "--contract-address") == 0 && i + 1 < argc) contract_address = argv[++i]; + else if (strcmp(argv[i], "--wallet-address") == 0 && i + 1 < argc) wallet_address = argv[++i]; + else if (strcmp(argv[i], "--include-metadata") == 0) include_metadata = true; } if (!chain_id || !contract_address || !wallet_address) { - fprintf(stderr, "Missing required args for get_token_balances\n"); + fprintf(stderr, "Missing required args for get-token-balances\n"); return 1; } SequenceGetTokenBalancesReturn *res = sequence_get_token_balances(chain_id, contract_address, wallet_address, include_metadata); + if (!res) { + fprintf(stderr, "sequence_get_token_balances failed\n"); + return 1; + } + log_sequence_get_token_balances_return(res); free_sequence_token_balances_return(res); - } else if (strcmp(cmd, "sign_in_with_email") == 0) { + } else if (strcmp(cmd, "sign-in-with-email") == 0) { print_header("Sign In with Email"); const char *email = NULL; for (int i = 2; i < argc; i++) { if (strcmp(argv[i], "--email") == 0 && i + 1 < argc) email = argv[++i]; } - if (!email) { fprintf(stderr, "Missing --email\n"); return 1; } + if (!email) { + fprintf(stderr, "Missing --email\n"); + return 1; + } if (sequence_sign_in_with_email(email)) { printf("Email sign-in has been successfully initialized. Please use the code sent to your email with the following command:\n"); - print_use_case("Confirm Email Sign In", "sequence-cli confirm_email_sign_in --email --code "); + print_use_case("Confirm Email Sign In", "sequence-wallet confirm_email_sign_in --email --code "); } - } else if (strcmp(cmd, "confirm_email_sign_in") == 0) { + } else if (strcmp(cmd, "confirm-email-sign-in") == 0) { print_header("Confirming Email Sign In"); const char *email = NULL; const char *code = NULL; + const char *wallet_type = NULL; + for (int i = 2; i < argc; i++) { if (strcmp(argv[i], "--email") == 0 && i + 1 < argc) email = argv[++i]; else if (strcmp(argv[i], "--code") == 0 && i + 1 < argc) code = argv[++i]; + else if (strcmp(argv[i], "--wallet-type") == 0) wallet_type = argv[++i]; + } + if (!email || !code) { + fprintf(stderr, "Missing --email or --code\n"); + return 1; } - if (!email || !code) { fprintf(stderr, "Missing --email or --code\n"); return 1; } sequence_restore_session(); sequence_complete_auth_return *res = sequence_confirm_email_sign_in(email, code); - if (res->wallet_count <= 0) { - printf("No wallets available, please create a new wallet."); - print_use_case("Create Wallet", "sequence-cli create_wallet"); + if (!res) { + fprintf(stderr, "sequence_confirm_email_sign_in failed\n"); + return 1; + } + + sequence_wallet *wallet = NULL; + + if (wallet_type) { + /* No wallets → create one */ + if (res->wallet_count == 0) { + wallet = sequence_create_wallet(wallet_type); + } + else if (res->wallets) { + + /* Prefer Ethereum_SequenceV3 if available */ + for (size_t i = 0; i < res->wallet_count; ++i) { + if (strcmp(res->wallets[i].type, wallet_type) == 0) { + wallet = sequence_use_wallet(wallet_type); + break; + } + } + } + + /* If no wallet was selected, fallback to create the specified wallet type */ + if (!wallet) { + wallet = sequence_create_wallet(wallet_type); + } + + if (wallet) { + printf("Sequence Wallet Address: %s\n", wallet->address); + print_use_cases(); + } else { + fprintf(stderr, "Failed to initialize wallet\n"); + } + } else { + + if (res->wallet_count == 0) { + printf("No wallets available, please create a new wallet.\n"); + print_use_case("Create Wallet", "sequence-wallet create-wallet"); + + sequence_complete_auth_return_free(res); + return 0; + } + printf("Please select one of the existing wallet types:\n"); - } - if (res->wallets) { - for (size_t i = 0; i < res->wallet_count; i++) { - printf("Wallet Type %ld: %s\n", i, res->wallets[i].type); + if (res->wallets) { + for (size_t i = 0; i < res->wallet_count; ++i) { + printf("Wallet Type %zu: %s\n", i, res->wallets[i].type); + } } + + printf("\nUse the following command to select it:\n"); + print_use_case( + "Use Wallet", + "sequence-wallet use-wallet --wallet-type " + ); } sequence_complete_auth_return_free(res); - printf("\nUse the following command to select it:\n"); - print_use_case("Use Wallet", "sequence-cli use_wallet --wallet_type "); - - } else if (strcmp(cmd, "create_wallet") == 0) { + } else if (strcmp(cmd, "create-wallet") == 0) { print_header("Create Wallet"); sequence_restore_session(); - const sequence_wallet *wallet = sequence_create_wallet(); + + const char *walletType = NULL; + for (int i = 2; i < argc; i++) { + if (strcmp(argv[i], "--wallet-type") == 0 && i + 1 < argc) walletType = argv[++i]; + } + + // Use sequence v3 wallet type by default + if (!walletType) { + walletType = "Ethereum_SequenceV3"; + } + + const sequence_wallet *wallet = sequence_create_wallet(walletType); + + if (!wallet) { + fprintf(stderr, "Failed to create wallet of type '%s'\n", walletType); + return 1; + } + printf("Sequence Wallet Address: %s\n", wallet->address); print_use_cases(); - } else if (strcmp(cmd, "use_wallet") == 0) { + } else if (strcmp(cmd, "use-wallet") == 0) { print_header("Use Wallet"); const char *walletType = NULL; for (int i = 2; i < argc; i++) { - if (strcmp(argv[i], "--wallet_type") == 0 && i + 1 < argc) walletType = argv[++i]; + if (strcmp(argv[i], "--wallet-type") == 0 && i + 1 < argc) walletType = argv[++i]; } - if (!walletType) { fprintf(stderr, "Missing --wallet_type\n"); return 1; } + if (!walletType) { fprintf(stderr, "Missing --wallet-type\n"); return 1; } sequence_restore_session(); const sequence_wallet *wallet = sequence_use_wallet(walletType); + + if (!wallet) { + fprintf(stderr, "Failed to use wallet of type '%s'\n", walletType); + return 1; + } + printf("Sequence Wallet Address: %s\n", wallet->address); print_use_cases(); - } else if (strcmp(cmd, "sign_message") == 0) { + } else if (strcmp(cmd, "sign-message") == 0) { print_header("Sign Message"); const char *chain_id = NULL; const char *message = NULL; for (int i = 2; i < argc; i++) { - if (strcmp(argv[i], "--chain_id") == 0 && i + 1 < argc) chain_id = argv[++i]; + if (strcmp(argv[i], "--chain-id") == 0 && i + 1 < argc) chain_id = argv[++i]; else if (strcmp(argv[i], "--message") == 0 && i + 1 < argc) message = argv[++i]; } - if (!chain_id || !message) { fprintf(stderr, "Missing --chain_id or --message\n"); return 1; } + + if (!chain_id || !message) { + fprintf(stderr, "Missing --chain-id or --message\n"); + return 1; + } sequence_restore_session(); char *signature = sequence_sign_message(chain_id, message); printf("Signature: %s\n", signature); - } else if (strcmp(cmd, "send_transaction") == 0) { + } else if (strcmp(cmd, "send-transaction") == 0) { print_header("Send Transaction"); const char *chain_id = NULL; const char *to = NULL; const char *value = NULL; for (int i = 2; i < argc; i++) { - if (strcmp(argv[i], "--chain_id") == 0 && i + 1 < argc) chain_id = argv[++i]; + if (strcmp(argv[i], "--chain-id") == 0 && i + 1 < argc) chain_id = argv[++i]; else if (strcmp(argv[i], "--to") == 0 && i + 1 < argc) to = argv[++i]; else if (strcmp(argv[i], "--value") == 0 && i + 1 < argc) value = argv[++i]; } - if (!chain_id || !to || !value) { fprintf(stderr, "Missing --chain_id, --to or --value\n"); return 1; } + if (!chain_id || !to || !value) { + fprintf(stderr, "Missing --chain-id, --to or --value\n"); + return 1; + } sequence_restore_session(); char *txHash = sequence_send_transaction(chain_id, to, value); diff --git a/demo.c b/demo.c index e3d36c8..39506d3 100644 --- a/demo.c +++ b/demo.c @@ -73,7 +73,7 @@ int main(void) { sequence_wallet *wallet; if (response->wallet_count == 0) { - wallet = sequence_create_wallet(); + wallet = sequence_create_wallet("Ethereum_SequenceV3"); } else { diff --git a/lib/wallet/sequence_connector.c b/lib/wallet/sequence_connector.c index b17cc5a..b37354f 100644 --- a/lib/wallet/sequence_connector.c +++ b/lib/wallet/sequence_connector.c @@ -64,7 +64,7 @@ static char* sign_and_send(const char* endpoint, const char* payload) http_client_add_header(c, "Accept: application/json"); http_client_add_header(c, auth_header); - printf(">> %s (with header: %s)\n", payload, auth_header); + printf(">> Request\n%s\n%s\n\n", payload, auth_header); HttpResponse r = http_client_post_json(c, endpoint, payload, 10000); @@ -78,11 +78,11 @@ static char* sign_and_send(const char* endpoint, const char* payload) return NULL; } - char* body = r.body; + char* body = strdup(r.body); - printf("Response: %s\n", body); + printf("<< Response\n%s\n\n", body); - //http_response_free(&r); + http_response_free(&r); http_client_destroy(c); return body; @@ -166,7 +166,7 @@ sequence_complete_auth_return* sequence_confirm_email_sign_in(const char* email, return response; } -sequence_wallet* sequence_use_wallet(const char* walletType) +sequence_wallet* sequence_use_wallet(const char* wallet_type) { if (!cur_signer || !cur_signer->ctx) { @@ -174,7 +174,7 @@ sequence_wallet* sequence_use_wallet(const char* walletType) return NULL; } - const char* use_wallet_json = sequence_build_use_wallet_json(walletType); + const char* use_wallet_json = sequence_build_use_wallet_json(wallet_type); const char* body = sign_and_send("/UseWallet", use_wallet_json); sequence_wallet_response* response = sequence_build_wallet_return(body); @@ -190,7 +190,7 @@ sequence_wallet* sequence_use_wallet(const char* walletType) return sequence_wallet; } -sequence_wallet* sequence_create_wallet() +sequence_wallet* sequence_create_wallet(const char *wallet_type) { if (!cur_signer || !cur_signer->ctx) { @@ -198,7 +198,7 @@ sequence_wallet* sequence_create_wallet() return NULL; } - const char* create_wallet_json = sequence_build_create_wallet_json("Ethereum_SequenceV3"); + const char* create_wallet_json = sequence_build_create_wallet_json(wallet_type); const char* body = sign_and_send("/CreateWallet", create_wallet_json); sequence_wallet_response* response = sequence_build_wallet_return(body); diff --git a/lib/wallet/sequence_connector.h b/lib/wallet/sequence_connector.h index df979cc..4dee08a 100644 --- a/lib/wallet/sequence_connector.h +++ b/lib/wallet/sequence_connector.h @@ -7,9 +7,9 @@ int sequence_sign_in_with_email(const char *email); sequence_complete_auth_return *sequence_confirm_email_sign_in(const char *email, const char *code); -sequence_wallet *sequence_use_wallet(const char *walletType); +sequence_wallet *sequence_use_wallet(const char *wallet_type); -sequence_wallet *sequence_create_wallet(); +sequence_wallet *sequence_create_wallet(const char *wallet_type); char *sequence_sign_message(const char *chain_id, const char *message);