The goal of this package is to enable bitmark account vault supporting Ethereum.
This package includes:
- An ethereum wallet
- A contract interface which defines how account vault interact with smart contracts
- A singleton for contract registration
With the contract ABI file, we can generate a contract module through abigen
. By creating a wrapper structure which implements the Call
and Deploy
function, a client can interact with all the different contract in the same interfaces.
The Call
function determines which method could be exposed and how a client is going to invoke it. Whereas the Deploy
function is obviously for deploying a new contract.
Here is a simple example of wrapping a contract:
type TestContract struct {
contractAddress string
}
// Deploy deploys the smart contract to ethereum blockchain
func (c *TestContract) Deploy(wallet *ethereum.Wallet, arguments json.RawMessage) (string, string, error) {
t, err := wallet.Transactor()
if err != nil {
return "", "", err
}
address, tx, _, err := DeployTestContract(t, wallet.RPCClient())
if err != nil {
return "", "", err
}
return address.String(), tx.Hash().String(), nil
}
// Call is the entry function for account vault to interact with a smart contract.
func (c *TestContract) Call(wallet *ethereum.Wallet, method, fund string, arguments json.RawMessage) (string, error) {
contract, err := NewTestContract(common.HexToAddress(c.contractAddress), wallet.RPCClient())
if err != nil {
return "", err
}
t, err := wallet.Transactor()
if err != nil {
return "", err
}
switch method {
case "set_tester":
var params struct {
Tester common.Address `json:"tester"`
}
if err := json.Unmarshal(arguments, ¶ms); err != nil {
return "", err
}
tx, err := contract.CreateArtwork(t, params.Tester)
if err != nil {
return "", err
}
return tx.Hash().String(), err
default:
return "", fmt.Errorf("unsupported method")
}
}
To simply the contract importing, the package creates a sigleton of registered contracts. Each wrapped contract needs to create a factory function which takes an address as parameter and returns the instance of it. For example,
func TestContractFactory(contractAddress string) ethereum.Contract {
return &TestContract{
contractAddress: contractAddress,
}
}
For each contract modules, it registers itself using the RegisterContract
call. For example,
func init() {
ethereum.RegisterContract("TestContract", TestContractFactory)
}
A client can easily query contracts by using GetContract
function.
truffle
jq
abigen
npm
make
make build