The purpose of this tutorial is to demonstrate how you can use EOSFactory to execute the simplest development cycle: create a new contract, edit the code, build the contract, deploy it and interact with it.
- This tutorial assumes that you have successfully installed EOSFactory. If it's not the case, please refer to Installing EOSFactory.
- We also assume that you are familiar with the material covered in Interacting with EOS Contracts in EOSFactory.
- Finally, we assume that you are familiar with the official EOS Hello World tutorial.
Open a bash terminal and run Python CLI:
python3Once in the Python shell, import the EOSFactory library:
from eosfactory.eosf import *To create a new contract from a pre-defined template all you need is a name for the contract and the name of the template, for example:
project_path = project_from_template("foo", template="hello_world", remove_existing=True)NOTE: Do not use spaces in contract names. What is allowed are letters, numbers, underscores
_, dots.and dashes-. Regarding the second parameter, as of now there are three templates to choose from (i.e.hello_world,eosio_tokenandtic_tac_toe), with more coming in the future. This parameter is optional, the default value ishello_world.
The above command creates a new folder and inside it a new smart-contract file is placed. However, if you want to access an existing smart-contract, use the following syntax and specifying the entire path, for example:
contract_builder_foo = ContractBuilder(project_path)Or use just the folder name, if the contract is located in the workspace you explicitly defined when installing EOSFactory:
contract_builder_foo = ContractBuilder("foo")In a similar way, you can access demo contracts shipped with EOSFactory, for example:
contract_builder_hello = ContractBuilder("hello_world")To check the directory where the contract's files are located:
print(contract_builder_foo.path())Locate the folder containing the new contract (if you're not sure where it is, use the output produced by the contract_builder_foo.path method) and edit the foo.cpp file in your favorite text editor by commenting out line 18, i.e. require_auth( user ) :
#include <eosio/eosio.hpp>
#include <eosio/print.hpp>
#include "hello.world.hpp"
using namespace eosio;
class hello : public eosio::contract {
public:
using contract::contract;
[[eosio::action]]
void hi( account_name user ) {
//require_auth( user );
print( "Hello, ", name{user} );
}
};
EOSIO_ABI( hello, (hi) )contract_builder_foo.build()First, start the testnet and initialize the workspace:
reset()
create_master_account("master")Then create an account which will be holding the contract:
create_account("host", master)Next, let's redefine the contract, so that it's associated with the above account and thus becomes deployable. You can use the entire path to the contract's folder:
contract_foo = Contract(host, contract_builder_foo.path())Or you can use the name of the contract's folder (provided it's located in your smart-contract workspace):
contract_foo = Contract(host, "foo")Next, we can deploy the contract:
contract_foo.deploy()NOTE: In a similar way you could deploy a demo contract supplied by EOSFactory, for example:
contract_hello = Contract(host, "hello_world")
contract_hello.build()
contract_hello.deploy()First, let's create a couple of testing accounts:
create_account("alice", master)
create_account("carol", master)You can play with the contract by sending it actions with different arguments:
contract_foo.push_action("hi", {"user":alice}, permission=alice)contract_foo.push_action("hi", {"user":carol}, permission=carol)contract_foo.push_action("hi", {"user":alice}, permission=carol)contract_foo.push_action("hi", {"user":carol}, permission=alice)NOTE: The
push_actionmethod takes three parameters:
- the name of the action, e.g.
"hi",- the data required by the action, e.g.
{"user":alice},- the permissions required by the action, e.g.
alice.
Regarding permissions, EOSFactory offers several options:
contract_foo.push_action("hi", {"user":alice}, alice)contract_foo.push_action("hi", {"user":alice}, permission=alice)contract_foo.push_action("hi", {"user":alice}, permission=(alice, Permission.ACTIVE))contract_foo.push_action("hi", {"user":alice}, permission=[(alice, Permission.ACTIVE), (carol, Permission.OWNER)])All the above variations should work, as the contract allows anyone to authorize the hi action.
And now let's modify the hi method by uncommenting line 18, so that that contract authenticates the user before further execution:
void hi( account_name user ) {
require_auth( user );
print( "Hello, ", name{user} );
}Re-compile the contract:
contract_foo.build()And re-deploy the contract:
contract_foo.deploy()Now, if we attempt to mismatch the user and the authority, the contract will throw an error:
contract_foo.push_action("hi", {"user":alice}, permission=carol)Error 3090004: Missing required authority
Ensure that you have the related authority inside your transaction!But if we use the appropriate authority, there should no error:
contract_foo.push_action("hi", {"user":alice}, permission=alice)When your are done your contract, you might want to delete it from your workspace:
contract_foo.delete()NOTE: The above command removes the entire folder.
To stop the testnet:
stop()To exit Python CLI:
exit()Alternatively, use the ctrl-D shortcut.