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:
python3
Once 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_token
andtic_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_action
method 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.