atto

package module
v1.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 17, 2024 License: MIT Imports: 13 Imported by: 0

README

GoDoc

atto is a tiny Nano wallet, which focuses on ease of use through simplicity. Included is a rudimentary Go library to interact with Nano nodes.

Disclaimer: I am no cryptographer and atto has not been audited. I cannot guarantee that atto is free of security compromising bugs. If you want to be extra cautious, I recommend offline signing, which is possible with the included atto-safesign.

Installation

You can download precompiled binaries from the releases page or build atto yourself like this; go 1.15 or higher is required:

git clone 'https://github.com/codesoap/atto.git'
cd atto
go build ./cmd/atto
# The atto binary is now available at ./atto. You could also install
# to ~/go/bin/ by executing "go install ./cmd/atto".

For Arch Linux @kseistrup also made atto available in the AUR.

Usage

$ # The new command generates a new seed.
$ atto new
D420296F5FEF486175FAA8F649DED00A5B0A096DB8D03972937542C51A7F296C
$ # Store it in your password manager:
$ pass insert nano
Enter password for nano: D420296F5FEF486175FAA8F649DED00A5B0A096DB8D03972937542C51A7F296C
Retype password for nano: D420296F5FEF486175FAA8F649DED00A5B0A096DB8D03972937542C51A7F296C

$ # The address command shows the address for an account.
$ pass nano | atto address
nano_3cyb3rwp5ba47t5jdzm5o7apeduppsgzw8ockn1dqt4xcqgapta6gh5htnnh

$ # With address and all following commands you can also provide an
$ # alternative account index (default is 0):
$ pass nano | atto -a 1 address
nano_1o3igdpf8c4msdgwcop71x4o16zzkhe4kyku4axdi8iwh8wh13e4fwgherik

$ # The balance command will receive receivable funds automatically.
$ pass nano | atto balance
Creating receive block for 1.025 from nano_34ymtnmhwseiex4eqf7nnf5wcyg44kknuuen5wwurm18ma91msf6e1pqo8hx... done
Creating receive block for 0.1 from nano_39nd8eksw1ia6aokn96z4uthocke47hfsx9gr31othm1nrfwnzmmaeehiccq... done
1.337 NANO

$ # Choosing a representative is important for keeping the network
$ # decentralized.
$ pass nano | atto representative nano_1jr699mk1fi6mxy1y76fmuyf3dgms8s5pzcsge5cyt1az93x4n18uxjenx93
Creating change block... done

$ # To avoid accidental loss of funds, the send command requires
$ # confirmation, unless the -y flag is given:
$ pass nano | atto send 0.1 nano_11zdqnjpisos53uighoaw95satm4ptdruck7xujbjcs44pbkkbw1h3zomns5
Send 0.1 NANO to nano_11zdqnjpisos53uighoaw95satm4ptdruck7xujbjcs44pbkkbw1h3zomns5? [y/N]: y
Creating send block... done

$ atto -h
Usage:
	atto -v
	atto n[ew]
	atto [-a ACCOUNT_INDEX] a[ddress]
	atto [-a ACCOUNT_INDEX] b[alance]
	atto [-a ACCOUNT_INDEX] r[epresentative] [NEW_REPRESENTATIVE]
	atto [-a ACCOUNT_INDEX] [-y] s[end] AMOUNT RECEIVER

If the -v flag is provided, atto will print its version number.

The new subcommand generates a new seed, which can later be used with
the other subcommands.

The address, balance, representative and send subcommands expect a seed
as the first line of their standard input. Showing the first address of
a newly generated key could work like this:
atto new | tee seed.txt | atto address

The send subcommand also expects manual confirmation of the transaction,
unless the -y flag is given.

The address subcommand displays addresses for a seed, the balance
subcommand receives receivable blocks and shows the balance of an
account, the representative subcommand shows the current representative
if NEW_REPRESENTATIVE is not given and changes the account's
representative if it is given and the send subcommand sends funds to an
address.

ACCOUNT_INDEX is an optional parameter, which must be a number between 0
and 4,294,967,295. It allows you to use multiple accounts derived from
the same seed. By default the account with index 0 is chosen.

Environment:
	ATTO_BASIC_AUTH_USERNAME  The username for HTTP Basic Authentication.
	                          If set, HTTP Basic Authentication will be
	                          used when making requests to the node.
	ATTO_BASIC_AUTH_PASSWORD  The password to use for HTTP Basic
	                          Authentication.

Technical details

atto is written with ca. 1000 lines of code and uses minimal external dependencies. This makes it easy to audit the code yourself and ensure, that it does nothing you wouldn't want it to do.

To change some defaults, like the node to use, take a look at cmd/atto/config.go.

Signatures are created without the help of a node, to avoid your seed or private keys being stolen by a node operator. The received account info is always validated using block signatures to ensure the node operator cannot manipulate atto by, for example, reporting wrong balances.

atto does not have any persistance and writes nothing to your file system. This makes atto very portable, but also means, that no history is stored locally. I recommend using a service like https://nanolooker.com/ to investigate transaction history.

Donations

If you want to show your appreciation for atto, you can donate to me at nano_1i7wsbehgwhxct91wpojr1j588ydikd64uc7p3kj54nofqioc6ydjopezf13.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrAccountManipulated = fmt.Errorf("the received account info has been manipulated")

ErrAccountManipulated is used when it seems like an account has been manipulated. This probably means someone is trying to steal funds.

View Source
var ErrAccountNotFound = fmt.Errorf("account has not yet been opened")

ErrAccountNotFound is used when an account could not be found by the queried node.

View Source
var ErrSignatureMissing = fmt.Errorf("signature is missing")

ErrSignatureMissing is used when the Signature of a Block is missing but required for the attempted operation.

View Source
var ErrWorkMissing = fmt.Errorf("work is missing")

ErrWorkMissing is used when the Work of a Block is missing but required for the attempted operation.

View Source
var RequestInterceptor func(request *http.Request) error

The RequestInterceptor is a function that is used to modify all HTTP requests that are sent to a node. If it is nil, requests are not modified.

May be used, for example, to authenticate requests.

Functions

func GenerateSeed

func GenerateSeed() (string, error)

GenerateSeed generates a new random seed.

func NewPrivateKey

func NewPrivateKey(seed string, index uint32) (*big.Int, error)

NewPrivateKey creates a private key from the given seed and index.

Types

type Account

type Account struct {
	PublicKey *big.Int
	Address   string
}

Account holds the public key and address of a Nano account.

func NewAccount

func NewAccount(privateKey *big.Int) (a Account, err error)

NewAccount creates a new Account and populates both its fields.

func NewAccountFromAddress

func NewAccountFromAddress(address string) (a Account, err error)

NewAccountFromAddress creates a new Account and populates both its fields.

func (Account) FetchAccountInfo

func (a Account) FetchAccountInfo(node string) (i AccountInfo, err error)

FetchAccountInfo fetches the AccountInfo of Account from the given node.

It is also verified, that the retreived AccountInfo is valid by doing a block_info RPC for the frontier, verifying the signature and ensuring that no fields have been changed in the account_info response.

May return ErrAccountNotFound or ErrAccountManipulated.

If ErrAccountNotFound is returned, FirstReceive can be used to create a first Block and AccountInfo and create the account by then submitting this Block.

func (Account) FetchReceivable added in v1.6.0

func (a Account) FetchReceivable(node string) ([]Receivable, error)

FetchReceivable fetches all unreceived blocks of Account from node.

func (Account) FirstReceive added in v1.4.0

func (a Account) FirstReceive(receivable Receivable, representative string) (AccountInfo, Block, error)

FirstReceive creates the first receive block of an account. The block will still be missing its signature and work. FirstReceive will also return AccountInfo, which can be used to create further blocks.

type AccountInfo

type AccountInfo struct {
	// Ignore this field. It only exists because of
	// https://github.com/nanocurrency/nano-node/issues/1782.
	Error string `json:"error"`

	Frontier       string `json:"frontier"`
	Representative string `json:"representative"`
	Balance        string `json:"balance"`

	PublicKey *big.Int `json:"-"`
	Address   string   `json:"-"`
}

AccountInfo holds the basic data needed for Block creation.

func (*AccountInfo) Change

func (i *AccountInfo) Change(representative string) (Block, error)

Change creates a change block, which will still be missing its signature and work. The Frontier and Representative of the AccountInfo will be updated.

func (*AccountInfo) Receive

func (i *AccountInfo) Receive(receivable Receivable) (Block, error)

Receive creates a receive block, which will still be missing its signature and work. The Frontier and Balance of the AccountInfo will be updated.

func (*AccountInfo) Send

func (i *AccountInfo) Send(amount, toAddr string) (Block, error)

Send creates a send block, which will still be missing its signature and work. The Frontier and Balance of the AccountInfo will be updated. The amount is interpreted as Nano, not raw!

type Block

type Block struct {
	Type           string `json:"type"`
	Account        string `json:"account"`
	Previous       string `json:"previous"`
	Representative string `json:"representative"`
	Balance        string `json:"balance"`
	Link           string `json:"link"`
	Signature      string `json:"signature"`
	Work           string `json:"work"`

	// This field is not part of the JSON but needed to improve the
	// performance of FetchWork and the security of Submit.
	SubType BlockSubType `json:"-"`
}

Block represents a block in the block chain of an account.

func (*Block) FetchWork

func (b *Block) FetchWork(node string) error

FetchWork uses the generate_work RPC on node to fetch and then set the Work of b.

func (*Block) GenerateWork added in v1.6.0

func (b *Block) GenerateWork() error

GenerateWork uses the CPU of the local computer to generate work and then sets it as b.Work.

func (Block) Hash

func (b Block) Hash() (string, error)

Hash calculates the block's hash and returns it's string representation.

func (*Block) Sign

func (b *Block) Sign(privateKey *big.Int) error

Sign computes and sets the Signature of b.

func (Block) Submit

func (b Block) Submit(node string) error

Submit submits the Block to the given node. Work and Signature of b must be populated beforehand.

May return ErrWorkMissing or ErrSignatureMissing.

type BlockSubType

type BlockSubType int64

BlockSubType represents the sub-type of a block.

const (
	// SubTypeReceive denotes blocks which raise the balance.
	SubTypeReceive BlockSubType = iota

	// SubTypeChange denotes blocks which change the representative.
	SubTypeChange

	// SubTypeSend denotes blocks which lower the balance.
	SubTypeSend
)

type Receivable added in v1.6.0

type Receivable struct {
	Hash   string
	Amount string
	Source string
}

Receivable represents a block that is waiting to be received.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL