From 6ca8679887594962ede37f8d4b575db8f6b04a54 Mon Sep 17 00:00:00 2001 From: gh-actions Date: Thu, 11 Apr 2024 21:08:14 +0000 Subject: [PATCH] Deploy website - based on b01817612aba20eae5bd017b2c75bddbf632af0b --- 404.html | 4 ++-- RFCs/document-syncing.html | 4 ++-- RFCs/fula-sec.html | 4 ++-- RFCs/fula-sec/did.html | 4 ++-- RFCs/fula-sec/encryption.html | 4 ++-- RFCs/personal-data-reserve.html | 4 ++-- RFCs/private-network.html | 4 ++-- RFCs/replication.html | 4 ++-- RFCs/rfc-process.html | 4 ++-- api-intro.html | 4 ++-- api/client-instance.html | 4 ++-- api/file-api.html | 4 ++-- api/graph-api.html | 4 ++-- assets/js/799a1b22.ced56f76.js | 1 + assets/js/799a1b22.eb0d0dcf.js | 1 - .../{runtime~main.ab4bb7c6.js => runtime~main.b41761a5.js} | 2 +- blockchain/Recipes/Account.html | 4 ++-- blockchain/Recipes/Asset.html | 4 ++-- blockchain/Recipes/Bag.html | 4 ++-- blockchain/Recipes/Bundle.html | 4 ++-- blockchain/Recipes/Challenges.html | 4 ++-- blockchain/Recipes/Claims.html | 4 ++-- blockchain/Recipes/Manifest.html | 4 ++-- blockchain/Recipes/Market.html | 4 ++-- blockchain/Recipes/Pool.html | 4 ++-- blockchain/Services/BuildNode.html | 4 ++-- blockchain/Services/Explorer.html | 4 ++-- blockchain/Services/FulaContractAPI.html | 4 ++-- blockchain/Services/Node.html | 4 ++-- blockchain/Services/NodeAPI.html | 4 ++-- blockchain/Services/ProofEngine.html | 4 ++-- blockchain/Services/RunNode.html | 4 ++-- blockchain/Services/Status.html | 4 ++-- blockchain/blockchain-intro.html | 4 ++-- blockchain/recipes.html | 4 ++-- blockchain/services.html | 4 ++-- blog/archive.html | 4 ++-- components/WorkInProgress.html | 4 ++-- design/encryption.html | 4 ++-- design/test.html | 4 ++-- functionyard.html | 4 ++-- functionyard/add-storage.html | 4 ++-- functionyard/dapps.html | 4 ++-- functionyard/fxblox-app.html | 6 +++--- functionyard/fxfotos.html | 4 ++-- functionyard/hardware/fxblox-hardware-rk1.html | 4 ++-- functionyard/hardware/fxblox-hardware-rpi-reimage.html | 4 ++-- functionyard/hardware/fxblox-hardware-rpi.html | 4 ++-- functionyard/hardware/fxblox-hardware.html | 4 ++-- functionyard/join.html | 4 ++-- functionyard/metamask.html | 4 ++-- functionyard/support.html | 4 ++-- getting-started.html | 4 ++-- getting-started/box-setup.html | 4 ++-- getting-started/fula-client.html | 4 ++-- getting-started/rpi-setup.html | 4 ++-- getting-started/using-samples.html | 4 ++-- index.html | 4 ++-- introduction/bas.html | 4 ++-- introduction/blox.html | 4 ++-- introduction/contribute.html | 4 ++-- introduction/contribute/contribution-tutorial.html | 4 ++-- introduction/contribute/styling.html | 4 ++-- introduction/contribute/writing.html | 4 ++-- introduction/fula.html | 4 ++-- mvp.html | 4 ++-- mvp/admin-reporting.html | 4 ++-- mvp/box-admin.html | 4 ++-- mvp/forgot-password.html | 4 ++-- mvp/fotos.html | 4 ++-- mvp/fotos/availability.html | 4 ++-- mvp/fotos/backup.html | 4 ++-- mvp/fotos/setup.html | 4 ++-- mvp/fotos/sharing.html | 4 ++-- mvp/my-account.html | 4 ++-- mvp/pools.html | 4 ++-- mvp/pools/storage-provide.html | 4 ++-- mvp/privacy-dashboard.html | 4 ++-- mvp/questions.html | 4 ++-- mvp/technical-questions.html | 4 ++-- mvp/unboxing.html | 4 ++-- reference-api.html | 4 ++-- release/testnet-alpha.html | 4 ++-- whitepaper.html | 4 ++-- work_in_progress.html | 4 ++-- 85 files changed, 167 insertions(+), 167 deletions(-) create mode 100644 assets/js/799a1b22.ced56f76.js delete mode 100644 assets/js/799a1b22.eb0d0dcf.js rename assets/js/{runtime~main.ab4bb7c6.js => runtime~main.b41761a5.js} (99%) diff --git a/404.html b/404.html index 76b80472..9ace55ba 100644 --- a/404.html +++ b/404.html @@ -5,13 +5,13 @@ Page Not Found | Functionland - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/RFCs/document-syncing.html b/RFCs/document-syncing.html index 0d1a90de..798f5e65 100644 --- a/RFCs/document-syncing.html +++ b/RFCs/document-syncing.html @@ -5,13 +5,13 @@ Document Syncing | Functionland - +
Skip to main content

Document Syncing

Summary​

This RFC proposes usage of IPFS-Cluster in conjunction with a Correspondant and Newsroom component to sync files and folders across several devices.

Use Case​

A Box owner would like to sync the meeting notes on their desktop with other meeting participants in real time.

They run a command and provide instructions for other participants to download the document.

Each participant is able to download and edit the meeting notes and see updates from others in real time.

Out of Scope​

  • high-frequency updates to documents which might be encountered with multi-tenancy or recording streaming video

  • data persisted by orbit db or any other dbs

Pre-conditions​

  • each participant's device in the meeting is accessible from the others

    EITHER

    * they have a public static IP

    OR

    * NAT hole punching works AND there are relays available to help establish connectivity

Design Considerations​

IPFS-Cluster​

A properly configured ipfs-cluster provides most of the properties required to implement this use case including.

  • a private network of trusted peers

  • conflict resolution

  • notifying peers of changes

  • efficient transmission of data

  • providing peer pinning status

Conflict Resolution​

IPFS Cluster provides two choices for conflict resolution.

CRDT will be used because:

  • it utilizes 'GossipSub' which will probably be useful for future use cases related to replication.

  • it does not require > 50% of peers to be online in order to operate

  • 'follower' peers might be used in the future to provide 'read-only' access

  • 'trusted peers' might be used in the future to provide access control

  • peers will probably come and go frequently (ie/ someone needs to drop from the meeting)

  • since we have full control over the document store, we can ensure the DAG is shallow (based on limitations of number of files in a directory)

  • less stable / tested conflict resolution can be tolerated for this use case

Design​

Box System Architecture​

The following diagram illustrates how various components on the Box will work together to implement data syncing.

There are two new components introduced:

  • correspondant

  • newsroom

Box System Architecture

Box System Architecture

System Properties​

  • peers should not enter a recursive loop with each other by notifying authors of updates that originated from them

  • each program should be reentrant in the sense that they can be aborted at any point during execution then restarted

    • the shared state will be updated to reflect the latest changes to the file system

Correspondant​

The role of the correspondant is to ensure IPFS-Cluster is pinning the latest files created and updated on the author's file system.

When the root CID of the file system changes it should also unpin the old one so that the garbage collector can remove deleted files.

A watch (with debounce) of the filesystem is used instead of an interval timer for the event loop since it will enable changes to be corresponded immediately without consuming resources unnecessarily.

Correspondant Flow State​

Correspondant Flow Chart Implementation

Correspondant Flow Chart Implementation

Newsroom Flow State​

Newsroom FLow Chart Implementation

Newsroom FLow Chart Implementation

Docker-Compose​

In order to access ipfs-cluster-ctl and ipfs from the command line, the correspondant and newsroom will be bundled in the same image as ipfs-cluster-ctl and IPFS.

A separate service will be defined for:

  • newsroom

  • correspondant

  • IPFS

  • ipfs-cluster-ctl

  • ipfs-cluster-service

The docker setup for the IPFS components can be followed from the IPFS-Cluster documentation.

The IPFS components should be listed as a dependency of the correspondant and newsroom.

Future​

Performance Optimizations​

  • a scheduler might be used to prioritize fula-api latency over syncing

  • since the correspondant knows what file/folder changed, it might rebuild the DAG bottom up instead of top down

  • further research needs to be put into how ipfs get works to see if entire contents of the DAG are copied to /fx or only the parts that change

    • if the former is true, since we know the old DAG, we could walk them both ourselves skipping the CIDs that are the same

    • this may be necessary for handling removal of files anyway

Connectivity Research​

The main goal is to remove the connectivity pre-condition from this use case so it will work from any device over the vast majority of network topologies.

The following issues are related to this:

Possibilities​

Data types​

Although this use case is focused on syncing plaintext (eg/ UTF-8 encoded) files it could also cover other documents that IPFS and IPFS-Cluster handles well out of the box such as photos and video.

Person-person Collaboration​

With the addition of an authentication and ACL layer:

  • two different Box owners could share a document with each other and perform real-time edits on it. They might add a third person as reviewer with read-only access

  • a group of people might create a shared album where certain members have the ability to upload photos and others are only allowed to view them (or vice versa)

- + \ No newline at end of file diff --git a/RFCs/fula-sec.html b/RFCs/fula-sec.html index dcab9943..c18b99f1 100644 --- a/RFCs/fula-sec.html +++ b/RFCs/fula-sec.html @@ -5,13 +5,13 @@ FULA Security Layer | Functionland - +
Skip to main content

FULA Security Layer

Overview​

Authentication and encrypted data storage are the main structural elements for decentralized networks and Web3 applications. By default, IPFS does not encrypt the data persisted to it. This means that if someone has a CID, they can access the data without the author's permission. The fula-sec layer aims to solve this, so that data owners can have full control over how their data is accessed.

The fula-sec layer is broken down into the following fundamental building blocks:

What Security Protocols Implemented​

We aim not only to encrypt the data, but also to verify its valid data and use a key exchange mechanism. The key exchange mechanism remains the DID (Decentrilized Identity) mechanism. In the table below, you can see which algorithm was used for what purpose.

KeywordObjectiveDescription
Ed25519Used to obtain user IdentityEdwards-curve Digital Signature Algorithm(EdDSA)
AESUsed by the client side to encrypt each content. The keys are shared only by authorized audience. The keys are not given to audience in a straightforward manner, of course.Advanced Encryption Standard Algorithm (AES)
JWSJWS includes the Signing option. It has two method sign the payload and verify a signed data. A JSON Web Signature (abbreviated JWS) is an IETF-proposed standard (RFC 7515) for signing arbitrary data.
JWEAn encrypted JWE object for one or multiple DIDs.JSON Web Encryption (JWE) is an IETF standard providing a standardised syntax for the exchange of encrypted data, based on JSON and Base64.
RSARSA involves a public key and a private key. The public key can be known by everyone and is used for encrypting messages. The intention is that messages encrypted with the public key can only be decrypted by using the private key.Rivest–Shamir–Adleman.

Unresolved questions​

  • Content Access Revoke
  • Storing DID document in L3 blockchain

Future possibilities​

  • A box owner can associate multiple peer addresses with a DID.
- + \ No newline at end of file diff --git a/RFCs/fula-sec/did.html b/RFCs/fula-sec/did.html index 435593f4..0174a27b 100644 --- a/RFCs/fula-sec/did.html +++ b/RFCs/fula-sec/did.html @@ -5,14 +5,14 @@ Decentralized Identity (DID) | Functionland - +
Skip to main content

Decentralized Identity (DID)

Why DID in FULA?​

DID enables agents to assert their identity so that they can establish trust, privacy and security with other agents in the network without a centralized authority.

What is Required?​

Setting up decentralized identity with providers(blockchain/distributed ledger) usually consists of the following elements:

  1. Identity owner: The user who creates their decentralized identity using the identity wallet.
  2. Issuer/Verifier: An entity that issues and verifies identification information. They sign the transaction with their private key.
  3. Blockchain/Distributed Ledger: A decentralized and distributed ledger that provides the mechanism and functions for DID and operation.
  4. DID (Decentralized Identifier): A unique identifier that contains details such as public key, verification information, documents.

Can we achieve creating DID without any providers?​

Yes, but with some flaws. As long as we do not store all operations with DID on a ledger verified by an acceptable number of other nodes, security of the data will be lost. Moreover, data storage in blockchain/distributed ledger mechanism is immutable and permanent, and hence, modification and deletion are not possible. The decentralized identity systems use this mechanism so that no external entity can tamper or modify the data.

How does it work?​

  1. Create DID identity - With Create DID, we will have a DID identity and two secret keys options for backup.

create-did

Create DID identity flow


  1. Recover DID identity - We need a mnemonic or private key to restore identity.

recover-did

Recover DID identity flow

See here for DID reference implementation.

- + \ No newline at end of file diff --git a/RFCs/fula-sec/encryption.html b/RFCs/fula-sec/encryption.html index 424f0d89..ccc71bdc 100644 --- a/RFCs/fula-sec/encryption.html +++ b/RFCs/fula-sec/encryption.html @@ -5,13 +5,13 @@ Two-way Encryption Mechanism | Functionland - +
Skip to main content

Two-way Encryption Mechanism

Summary​

There are two scenarios that require encryption

  1. Tagged DID encryption
  2. Asymmetric Encryption - Encrypt the subscriber/audience's public key.

Tagged Encryption​

Encrypt data by adding a DID.

Tagged encryption works according to the following steps:

  1. Each agent must have a generated DID address.

  2. Alice uses a unique symmetric key (sKn) for encrypting each piece of content and each file while streaming to the Box.

  3. After the file has been successfully stored to the IPFS node, it returns the CID for each encrypted file to Alice.

  4. Alice now gives Bob access to the file by issuing him a JWE Doc with BOB`s DID address, symmetric key (sK1) and CID

  5. Bob decrypts the document using his own DID address and then obtains the symmetric key (sK1) to get the file that belongs to Alice. As a result, BOB gets the CID and sends a request to the Box.

  6. Bob decrypts the data with sK1 while streaming it from the Box.

tagged-encryption

Tagged Encryption Sequence Diagram

See here for tagged encryption sample code.

Asymmetric Encryption​

With assymetric encryption, no one needs to share DID identity with others, they just need to know a PubKey.

Asymmetric Encryption works according to the following steps:

  1. First, each application must have a generated DID address and PublicKey.

  2. Alice uses a unique symmetric key (sKn) for encrypting each piece of content and each file while streaming to the Box.

  3. After the file has been successfully stored to the IPFS node, it returns the CID for each encrypted file to Alice.

  4. Alice now gives Bob access to the file by issuing him a JWE Doc with BOB`s PubKey, symmetric key (sK1) and CID.

  5. Bob decrypts the document using his own PrivateKey and then obtains the symmetric key (sK1) to get the file that belongs to Alice. As a result, BOB gets the CID and sends a request to the Box.

  6. Bob decrypts data with sK1 while streaming it from the Box.

Assymetric Encryption Sequence Diagram

Tagged Encryption Sequence Diagram

See here for assymetric encryption sample code.

References​

- + \ No newline at end of file diff --git a/RFCs/personal-data-reserve.html b/RFCs/personal-data-reserve.html index ee4cca03..91a54d33 100644 --- a/RFCs/personal-data-reserve.html +++ b/RFCs/personal-data-reserve.html @@ -5,13 +5,13 @@ Personal Data Reserve | Functionland - +
Skip to main content

Personal Data Reserve

Summary​

This RFC covers how a Box customer's data can be replicated across a group of Boxes physically separated from each other to help prevent unwanted loss.

Use Case​

A person owns 3-5 Boxes (eg/ one in their home, one at their office and one at a friend's house).

Their basement floods bricking the one located in their home.

They are still able to access all of the data that was uploaded to their bricked home Box from one of their other Boxes or a brand new Box provisioned with factory settings.

The following scenarios are handled:

  • adding a new Box to the reserve

  • removing a Box from the reserve

  • data becomes corrupted on a Box

Terminology​

NameDefinition
reservea group of keepers collaboratively working together to back up a snapshot
snapshota collection of data that represents the entire file system being backed up at a given moment in time
chunka portion of a data set
keepera Box process responsible for backing up a file system to the reserve
retrievera Box process given the task of rebuilding a usable file system from a snapshot
authorthe Box where the backed up data set was created
peera member of the reserve
replication factorhow many keepers a chunk of data is stored on; a greater replication factor means greater resilience
data seta file, directory, or data from a database
warning time windowhow much time should be given to send an alert before an imminent limitation is encountered and a system failure occurs

Pre-conditions​

  • the owner has already authenticated themselves with each Box

  • the fula-api is persisting data to a disk accessible by the keeper

  • each Box is already provisioned with the necessary configuration info required to operate a reserve

Assumptions​

  • each keeper in a reserve can be trusted to not operate maliciously by performing unwanted delete operations

  • the data being backed up is:

    • multimedia files such as photos and video
    • orbit db metadata
    • plain text files for shared configuration data

Out of Scope​

  • high-frequency updates to data sets which might be encountered with multi-tenancy or recording streaming video

  • syncing of data between Boxes so that it is usable on each Box (eg/ CRUD operations on them in real time)

  • conflicts arising from concurrent updates initiated by a user on several different Boxes

  • heuristics used to minimize bandwidth and improve availability

Limitations​

The following limitations may be encountered while operating a reserve:

  • file size
  • number of files in a directory
  • snapshot size
  • number of keepers in a reserve

Configuration​

Configuration data for each peer can be split into local and shared.

Local Configuration​

  • local Box address

  • local public/private key

Shared Configuration​

  • remote Box addresses of other peers in the reserve

  • shared secret

  • minimum acceptable replication factor

  • 'normal' event dispatching frequency

  • warning time window

    • has a global default as well as an override for each limitation

Conflict Resolution​

Although it can be assumed the snapshot is already free from conflicts caused by concurrent updates initiated from a user, conflicts may still arise from disk corruption or other unforseen keeper errors.

The disputing keepers will take the appropriate steps to resolve the conflict. If an appropriate resolution can not be achieved, an event is raised.

Events​

The following events are dispatched for an administrative UI.

  • limitation imminent

  • limitation encountered

  • keeper health

    • memory
    • disk I/O
    • CPU usage
    • disk corruption
  • unresolved conflict

  • unacceptable replication factor

  • keeper added / removed

  • network disruption

Event Types​

  • normal
  • warning
  • failure

Warnings​

Events dispatched before a failure occurs based on a forecasting heuristic to determine how quickly a limit will be reached.

Event Frequency​

Normal events are dispatched periodically (based on a config param) for historical reporting and warnings|failures are dispatched immediately.

Implementation​

Components​

The components that are needed for this use case are:

  • data set keeper

  • data set retriever

  • event dispatcher

  • file integrity monitor

Event Dispatcher​

A mechanism for dispatching events and queueing them to prevent loss if a peer goes down.

File Integrity Monitoring​

For detecting / handling disk corruption.

A full sweep of the file system is periodically done comparing the contents of chunks on disk with a source of truth.

Network Architecture​

A peer-peer architecture is used over master/slave so that if a single Box goes down the rest of the reserve will still be able to operate normally.

  • any shared config data is stored on each Box

  • any shared state required for the retrieval of a data set is stored on each Box

  • no central servers are used for networking

Drawbacks​

Putting the responsibility of data reliability on Box owners means there is potential for a Box owner to make a mistake and permanently lose their data.

Rationale and alternatives​

An alternative could be to use paid services (cloud storage providers) with their own SLAs to take on the responsibility of data reliability.

If participating in a decentralized storage network (DSN), the Box owner could also purchase a mining component to offset their cost.

There are currently a few drawbacks with this:

  • becoming a storage miner requires a significant upfront investment to cover hardware and staking costs

  • a private reserve will always be more efficient since keepers will not have to worry about the overhead of trusting each other

These options are not mutually exclusive. Offering both options (free and paid) could provide the greatest freedom/flexibility for Box owners.

Dependencies​

  • IPFS Cluster

  • private connections

  • authentication

  • retriever

  • keeper

@TODO - provide links to relevant docs

Unresolved questions​

What is an ideal replication factor?

How can resilience be measured? Markov models?

How can contents of an entire filesystem be efficiently compared with a source of truth?

How can system resources and their limits be calculated?

How can NAT hole punching work in a pnet without any relays?

Should data compression be taken into account?

Future Possibilities​

History​

Storing a history snapshots so an owner can go back in time and recover a data set from a previous state. This could help with data loss due to user errors.

Regions​

A person or group of people may have a large number of Boxes and want to set up geographically grouped regions such that if there is a severe network outage, each region will still be able to recover the entire contents of a snapshot.

- + \ No newline at end of file diff --git a/RFCs/private-network.html b/RFCs/private-network.html index db5841d0..31344094 100644 --- a/RFCs/private-network.html +++ b/RFCs/private-network.html @@ -5,7 +5,7 @@ Private Network | Functionland - + @@ -18,7 +18,7 @@ In the Config we should add to support to load config.json in this format:

{
"nodes": [
"/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
"/dnsaddr/bootstrap.libp2p.io/ipfs/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
"/dnsaddr/bootstrap.libp2p.io/ipfs/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa"
]
}

Which will be used for creating js-libp2p-bootstrap config.

FULA-client​

In fula-client We have to change pkey to fulaSecret so:

createClient(config?: Partial<Libp2pOptions & constructorOptions>, pKey = undefined): Promise<Fula>

to

createClient(config?: Partial<Libp2pOptions & constructorOptions>, fulaSecret = undefined): Promise<Fula>

and change connect interface to get a list of peerId`s from:

connect: (peerId: string) => Connection

to

 connect: (peerId: [string]) => Connection

We need to change Connection in the way that:

Case Study​

For dogfooding of new changes we can use a copy of react-gallery and change the BoxConfig to get list of comma seperated peerIds and App should change to pass the list of peerId's to fula-client.

Note: if example repo would be outside mono-repo we can just use branch for describing every functionality.

Alternative approaches​

VPN​

Using VPN for creating the private network.

Disadvantage:

- + \ No newline at end of file diff --git a/RFCs/replication.html b/RFCs/replication.html index 060ce39e..bed2dd96 100644 --- a/RFCs/replication.html +++ b/RFCs/replication.html @@ -5,14 +5,14 @@ Replication | Functionland - +
Skip to main content

Replication

Summary

When user set up his box he should join/create a public/private pool. in every pool user will pin their data for High availability and replication. and get fula token for keeping the pinset alive.

Motivation

  • user can mine fula and use app's and other futuers.
  • user can have HA on his/her data.

Guide-level explanation

  • there is node call validator that run's on the box and try to keep the pinset alive.
  • the validator use fula-file-protocol to stream pinned data to functionland/box container which keeping the pools data.
  • the validator can get the proof that the data stored and get to consensus of cluster pinset state.
  • joining to the pool most be base on geolocation.

Reference-level explanation

Drawbacks

Rationale and alternatives

Prior art

Unresolved questions

Future possibilities

- + \ No newline at end of file diff --git a/RFCs/rfc-process.html b/RFCs/rfc-process.html index 00746a61..8870bc9d 100644 --- a/RFCs/rfc-process.html +++ b/RFCs/rfc-process.html @@ -5,13 +5,13 @@ Requests for comments (RFCs) | Functionland - +
Skip to main content

Request for comments

What is the RFC process?​

Many changes, including bug fixes and documentation improvements, can be implemented and reviewed via the normal GitHub pull request workflow.

However, some changes though are "substantial", and we ask that these be put through a bit of design process and produce a consensus among community members.

The "RFC" (Request For Comments) process is intended to provide a consistent, controlled path for new features to enter the project, so that all stakeholders and contributors can be confident about the direction the project is evolving in.

When to follow this process​

You should consider using this process if you intend to make "substantial" changes in any Functionland project or the documentation. Here are some examples of things that would benefit from an RFC:

  • A new feature that requires rethinking of something that has already been developed and shipped.
  • A change in the documentation structure in order to enhance readers experience.
  • The introduction of a new idea, concept or convention that is currently not present in Functionland.

The RFC process will help you attract more attention to your proposal, as well as make sure that everybody gets a chance to participate in shaping and polishing your new idea.

About the process​

In short, to get a major feature added to any of Functionland's projects, you would first get the RFC merged into the RFC repo of that project as a markdown file. At that point the RFC is β€˜active’ and may be implemented with the goal of eventual inclusion.

  • Fork the project repository
  • Copy rfcs/template.md to rfcs/0000-my-feature/README.md (where my-feature is descriptive, don't ask for an RFC number yet)
  • Put any accompanying resources (pictures, etc.) in rfcs/0000-my-feature/. You can refer to these in the text.
  • Fill in the RFC. Details matter! Remember: RFCs that lack convincing motivation, fail to demonstrate understanding of the impact of the design, or are disingenuous about the drawbacks or alternatives tend to be poorly received.
  • Submit a pull request. As a pull request, the RFC will receive design feedback from the broader community. The author should be prepared to revise it in response to their feedback.
  • Build consensus and integrate feedback. RFCs that have broad support are much more likely to make progress than those that don't receive any comments.
  • The community will discuss the RFC pull request in the comment thread of the pull request itself as much as possible. Offline discussion will be summarized on the pull request comment thread.
  • RFCs rarely go through this process unchanged, especially as members of the broader community identify alternatives and drawbacks. You can make edits, big and small, to the RFC to clarify or change the design, but make changes as new commits to the pull request, and leave a comment on the pull request explaining your changes. Specifically, do not squash or rebase commits after they are visible on the pull request.
  • At some point, a member will propose a "motion for final comment period" (FCP), along with a disposition for the RFC (merge, close, or postpone).
    • For RFCs with lengthy discussion, the motion to FCP is usually preceded by a summary comment that attempts to map the current state of the discussion including major tradeoffs and/or points of disagreement.
  • The FCP lasts ten (10) calendar days, guaranteeing it remains open for at least five (5) business days. This allows stakeholders the opportunity to submit any final objections before a decision is reached.
  • In most cases the FCP period is quiet, and the RFC is either merged or closed. However, sometimes substantial new arguments or ideas are raised, the FCP is canceled, and the RFC returns to development mode.
- + \ No newline at end of file diff --git a/api-intro.html b/api-intro.html index 9b05dbf4..433eeccf 100644 --- a/api-intro.html +++ b/api-intro.html @@ -5,13 +5,13 @@ Fula API | Functionland - +
Skip to main content

Fula API

We designed Fula API to help you (a third-party, open-source developer) build other rich and compelling user experiences.

Want to get your hands dirty right away? Head over to getting started.

If you're the kind of person who likes to read the entire manual before starting the engine, then visit the Fula Reference API.

- + \ No newline at end of file diff --git a/api/client-instance.html b/api/client-instance.html index 91c39da5..2b0cc85d 100644 --- a/api/client-instance.html +++ b/api/client-instance.html @@ -5,13 +5,13 @@ Client Instance | Functionland - +
Skip to main content

Client Instance

Fula client package provides a method createClient that returns client instance. You can use this object to call File and Data APIs.

The client instance is basically a wrapper around a libp2p node. It abstracts away the protocol layer and makes it easier to communicate over libp2p with Fula's File and Graph protocols.

In addition to File and Data APIs, the client instance provides access to the underlying libp2p node. It also maintains the connection between client and the Box and provides a reconnecting mechanism.

You can find below basic methods for working with the client instance.

Create a new client instance​

You can use the createClient method to create a new client instance.

async createClient(config?, pKey=undefined)

Arguments are:

  • config?: The configuration object that gets passed directly to the underlying libp2p node. See here for more information
  • pkey: The private key used for securing the connection. Fula client is currently using NOISE as the connection encryptor, if you want to change that in config, make sure you provide appropriate arguments.

The method resolves to a Fula instance.

Example:

import {createClient} from '@functionland/fula'
const client = await createClient()

Connect to Box​

In order to use the different APIs provided by the Fula client, you must connect a client instance to a Box app using the connect method.

async connect(serverId)

Arguments are:

  • serverId: The base58 PeerID string provided by Box app or any other libp2p node supporting File and Graph protocols.

Example:

const serverId = '12D3KooWBFCDpMyEmyAAAAY6PiQw2vaM35ChTZ8ZmVUe8GFRMUrt' // copied from box app
await client.connect(serverId)

Close a connection​

You can disconnect an already connected client instance using the close method. This will close the connection and stops the libp2p node.

async close()

Example:

await client.close()

Access to Libp2p node​

As mentioned earlier, the Fula client is a wrapper around a libp2p node abstracting away the protocol layer and providing APIs to communicate over File and Graph protocols. If you want to do more specific configurations, access the libp2p cache, or access other interfaces, you can use the getNode method.

getNode()

This method returns a Libp2p node.

Example:

const libp2pNode = client.getNode()
console.log(libp2pNode.multiaddrs)
// [ <Multiaddr 047f00000106f9ba - /ip4/127.0.0.1/tcp/63930> ]
WIP Alert

Please note: these instructions remain a work in progress as we continue to evolve, refine and perfect the Fula API. Make sure to check back soon for more details!

- + \ No newline at end of file diff --git a/api/file-api.html b/api/file-api.html index 22ca6db6..8eb65259 100644 --- a/api/file-api.html +++ b/api/file-api.html @@ -5,7 +5,7 @@ File API | Functionland - + @@ -13,7 +13,7 @@
Skip to main content

File API (Object Store)

File API provides an interface-like object store for you to upload files and streams (eg. photos, videos or any type of document) and efficiently retrieve them for use in your web/mobile DApp.

File protocol is based on object stores. When you upload something, a CID is created and returned to you and the file gets stored in an IPFS compatible datastore.

Upload​

SendFile​

sendFile(File) => Promise<FileId>

sendFile will take a File as an argument and return a Promise. If the upload completes successfully, a Promise will return a FileId that is a string representing the CID of uploaded content.

Example​

import {Fula, createClient} from '@functionland/fula';

const fulaClient = await createClient();
await fulaClient.connect(serverId);
...
const selectedFile = document.getElementById('input').files[0];
const id = await fulaClient.sendFile(selectedFile);

sendStreamFile​

sendStreamFile(source, meta) => Promise<FileId>

sendStreamFile will take a source and meta as argument and return a Promise. If upload is done successfully, a Promise will return a FileId that is a string representing the CID of uploaded content. (This is useful when you're working with stream or outside the browser.)

  • source: AsyncIterable<Uint8Array>
  • meta: {name,type,lastModified,size}

Example​

import {Fula, createClient} from '@functionland/fula';

const fulaClient = await createClient();
await fulaClient.connect(serverId);
...
export async function* fileToAsyncItrable(file:File) {
const reader = (file.stream()).getReader();
while (true) {
const {value, done} = await reader.read();
if (done) {
break;
}
yield value;
}
}
const selectedFile = document.getElementById('input').files[0];
const id = await fulaClient.sendStreamFile(fileToAsyncItrable(selectedFile),
{
name: selectedFile.name,
type: selectedFile.type,
size: selectedFile.size,
lastModified: selectedFile.lastModified
});

Download​

receiveFile​

(fileId: FileId) => Promise<File>

receiveFile will take FileId and return Promise. if file retrieved successfully Promise return a File

  • fileId: FileId

Example​

import {Fula, createClient} from '@functionland/fula';

const fulaClient = await createClient();
await fulaClient.connect(serverId);
...
const data = await fulaClient.receiveFile(fileId);

receiveMeta​

(fileId: FileId) => Promise<Meta>

receiveMeta will take FileId and return Promise. if meta for the file retrieved successfully Promise return a Meta

  • fileId: FileId

Example​

import {Fula, createClient} from '@functionland/fula';

const fulaClient = await createClient();
await fulaClient.connect(serverId);
...
const {name, type, size, lastModified} = await fulaClient.receiveMeta(fileId);

receiveStreamFile​

(fileId: FileId) => Promise<{ source: AsyncIterable<Uint8Array>, meta: Meta }>

receiveStreamFile will take FileId and return a Promise. If the FileId exists, a Promise will return a { source: AsyncIterable<Uint8Array>, meta: Meta }

That source is a stream of content of the file and Meta is the Meta. (This is useful when you're working with a stream or outside of the browser.)

  • fileId: FileId

Example​

import {Fula, createClient} from '@functionland/fula';

const fulaClient = await createClient();
await fulaClient.connect(serverId);
...
const {source, meta} = await fulaClient.receiveStreamFile(fileId);
const {name, type, size, lastModified} = meta;
const content: Array<Uint8Array> = [];
for await (const chunk of source) {
content.push(Uint8Array.from(chunk));
}
const blob = new Blob(content, {type})


WIP Alert

Please note: these instructions remain a work in progress as we continue to evolve, refine and perfect the Fula API. Make sure to check back soon for more details!

- + \ No newline at end of file diff --git a/api/graph-api.html b/api/graph-api.html index 5c05c9d5..a048a326 100644 --- a/api/graph-api.html +++ b/api/graph-api.html @@ -5,7 +5,7 @@ Graph API | Functionland - + @@ -27,7 +27,7 @@ takes an array of filters.

Example​

This example demonstrates the filter use:

filter: {
and: [
{name: {nin: ["keyvan", "mahdi"]}},
{
or: [
{age: {gt: 45}},
{age: {lt: 15}}
]
}
]
}

Subscription​

Fula client's Graph API provides subscription for queries. You can subscribe to a query's result and get the new result on each change using the graphqlSubscription method.

async function* graphqlSubscribe(query: string, variableValues?: never, operationName?: string)

The interface is almost identical to the graphql method, except that graphqlSubscribe returns an AsyncIterable.

Arguments are:

The method returns an AsyncIterable that generates a new result based on query filters every time the collection is changed.

Example​

const readQuery = `
query {
read(input:{
collection:"profile",
filter:{
age: {gt: 50}
}
}){
id
name
age
}
}
`;

const resultIterator = client.graphqlSubscribe(readQuery)

for await (const res of resultIterator){
console.log(res)
}

WIP Alert

Please note: these instructions remain a work in progress as we continue to evolve, refine and perfect the Fula API. Make sure to check back soon for more details!

- + \ No newline at end of file diff --git a/assets/js/799a1b22.ced56f76.js b/assets/js/799a1b22.ced56f76.js new file mode 100644 index 00000000..f07398a9 --- /dev/null +++ b/assets/js/799a1b22.ced56f76.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7878],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>u});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,p=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=s(n),u=o,h=c["".concat(p,".").concat(u)]||c[u]||m[u]||i;return n?a.createElement(h,r(r({ref:t},d),{},{components:n})):a.createElement(h,r({ref:t},d))}));function u(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=c;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l.mdxType="string"==typeof e?e:o,r[1]=l;for(var s=2;s{n.r(t),n.d(t,{contentTitle:()=>r,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(7462),o=(n(7294),n(3905));const i={title:"FxBlox App Setup",id:"fxblox-app"},r=void 0,l={unversionedId:"functionyard/fxblox-app",id:"functionyard/fxblox-app",title:"FxBlox App Setup",description:"Installing the FxBlox App",source:"@site/docs/functionyard/fxblox-app.md",sourceDirName:"functionyard",slug:"/functionyard/fxblox-app",permalink:"/functionyard/fxblox-app",tags:[],version:"current",frontMatter:{title:"FxBlox App Setup",id:"fxblox-app"},sidebar:"tutorialSidebar",previous:{title:"Add Storage",permalink:"/functionyard/add-storage"},next:{title:"Joining Testnet",permalink:"/functionyard/join"}},p=[{value:"Installing the FxBlox App",id:"installing-the-fxblox-app",children:[{value:"Initial Setup",id:"initial-setup",children:[],level:3},{value:"App Configuration Steps",id:"app-configuration-steps",children:[],level:3},{value:"Troubleshoot",id:"troubleshoot",children:[],level:3}],level:2},{value:"Add Multiple FxBloxes",id:"add-multiple-fxbloxes",children:[],level:2},{value:"Format Drive",id:"format-drive",children:[],level:2},{value:"App features",id:"app-features",children:[],level:2}],s={toc:p};function d(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,a.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"installing-the-fxblox-app"},"Installing the FxBlox App"),(0,o.kt)("h3",{id:"initial-setup"},"Initial Setup"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Download the App"),": ",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"For Android: ",(0,o.kt)("a",{parentName:"li",href:"https://play.google.com/store/apps/details?id=land.fx.blox"},"FxBlox on Google Play (v1.6.14+)"),"."),(0,o.kt)("li",{parentName:"ul"},"For iOS: ",(0,o.kt)("a",{parentName:"li",href:"https://apps.apple.com/ca/app/fxblox/id6444862171"},"FxBlox on AppStore (v1.6.14+)"),"."))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Metamask Wallet"),": Ensure you have a ",(0,o.kt)("a",{parentName:"li",href:"https://play.google.com/store/apps/details?id=io.metamask"},"Metamask wallet")," for setting up your identity.")),(0,o.kt)("h3",{id:"app-configuration-steps"},"App Configuration Steps"),(0,o.kt)("div",{className:"admonition admonition-info alert alert--info"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},"If adding more than one FxBlox to your app, get familiar with ",(0,o.kt)("a",{parentName:"p",href:"#add-multiple-fxbloxs"},"these instructions first.")))),(0,o.kt)("div",{className:"admonition admonition-info alert alert--info"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},"For a successful setup you should either have the Blox with internal storage, or attach an external storage to it."))),(0,o.kt)("div",{className:"admonition admonition-warning alert alert--danger"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"12",height:"16",viewBox:"0 0 12 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))),"warning")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},"Please make sure to first uninstall (not update) any previous version of FxBlox on your phone and then re-install the latest version"))),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},'Open Metamask Wallet. We recommend having the opening network set to "Ethereum Mainnet" for a smoother setup process.'),(0,o.kt)("li",{parentName:"ol"},"Minimize Metamask (not close) and open the FxBlox app."),(0,o.kt)("li",{parentName:"ol"},"Read the ",(0,o.kt)("a",{parentName:"li",href:"https://fx.land/terms"},"Terms and Condition")," and if you agree, then select ",(0,o.kt)("inlineCode",{parentName:"li"},"Agree and Setup Blox")," in the app."),(0,o.kt)("li",{parentName:"ol"},"Enter a memorable password for data encryption and click ",(0,o.kt)("inlineCode",{parentName:"li"},"Sign")," (Note: This is not your Metamask password)."),(0,o.kt)("li",{parentName:"ol"},"Complete the connection in the Metamask app, then return to the FxBlox app.",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"You may need to click back to manually return to the app if it does not open Blox automatically after you sign in Metamask"),(0,o.kt)("li",{parentName:"ul"},"It does not matter which chain (Ethereum, Mumbai, etc) you are on in your Metamask wallet."))),(0,o.kt)("li",{parentName:"ol"},"Tap ",(0,o.kt)("inlineCode",{parentName:"li"},"Connect to new blox"),"."),(0,o.kt)("li",{parentName:"ol"},'Manually connect your phone to the "FxBlox" WiFi/Hotspot, and turn off "mobile data", then continue in the app.')),(0,o.kt)("div",{className:"admonition admonition-warning alert alert--danger"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"12",height:"16",viewBox:"0 0 12 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))),"warning")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},'Everyone should format their storage in step 8. If you have Blox with internal storage, disconnect any external disk. If you have Blox with no internal storage, attach your external storage. At the "set Authorizer" page, wait for 10 seconds and a green button named "Format Disk" appears. click on it and blox turns ',(0,o.kt)("font",{color:"purple"}," purple")," and reboots after a few minutes. You should wait for the light to turn flashing ",(0,o.kt)("font",{color:"cyan"}," light blue")," again and then reconnect your phone to FxBlox again to continue the process"))),(0,o.kt)("ol",{start:8},(0,o.kt)("li",{parentName:"ol"},"Make sure you have attached at least 300GB of external storage to your FxBlox. Proceed by clicking ",(0,o.kt)("inlineCode",{parentName:"li"},"Next")," once the app recognizes the storage.",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"If the storage is not recognized ensure that is it correctly formatted by clicking on the ",(0,o.kt)("inlineCode",{parentName:"li"},"Format")," button.",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"The light will turn ",(0,o.kt)("font",{color:"purple"}," purple"),", to indicate it is formatting. ",(0,o.kt)("strong",{parentName:"li"},"Formatting times depend on storage medium and capacity"),", so be patient during this time. Device will reboot automatically and eventually start flashing ",(0,o.kt)("font",{color:"cyan"}," light blue")," again when it is ready to proceed."))),(0,o.kt)("li",{parentName:"ul"},"If you have an FxBlox version with internal storage, there is no need to attach external storage."))),(0,o.kt)("li",{parentName:"ol"},"Select your desired WiFi network for the FxBlox and enter the password.",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"If you entered the wrong password, double check you're connected to FxBlox Wifi and just go back to the wifi selection screen to choose and re-enter your password."))),(0,o.kt)("li",{parentName:"ol"},"Finally, on the last screen reconnect your mobile device to your home WiFi and you can turn on the mobile data again if you want to. The app will confirm the successful setup. Please note the app does not continue if you do not have an active internet connection. When Blox is connected to the internet, the LEDs turn ",(0,o.kt)("inlineCode",{parentName:"li"},"green")," for 30 seconds and then turn off."),(0,o.kt)("li",{parentName:"ol"},"We recommend unplugging and replugging the Blox after the initial setup once for a hard reboot and ensuring that everything is set. After you re-plug the power and it boots, it may reboot automatically once as well.")),(0,o.kt)("h3",{id:"troubleshoot"},"Troubleshoot"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Final step connection issues"),": Connect to mobile or home wifi, restart the FxBlox app, select ",(0,o.kt)("inlineCode",{parentName:"li"},"Connect to Existing Blox"),". If that doesn't work, restart the FxBlox device. Close app and reopen to proceed with ",(0,o.kt)("inlineCode",{parentName:"li"},"Connect to new Blox"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"If Metamask doesn't redirect after signing transaction"),": Manually go back to the FxBlox app."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"App issues with Metamask"),': On some phones, if you cannot get the "Connect" and "sign" prompts in Metamask, you may need to put both the Metamask app and Blox app in Unrestricted mode from the "Battery Optimization". Go to: ',(0,o.kt)("inlineCode",{parentName:"li"},"Settings")," > ",(0,o.kt)("inlineCode",{parentName:"li"},"Apps")," > ",(0,o.kt)("inlineCode",{parentName:"li"},"FxBlox")," > ",(0,o.kt)("inlineCode",{parentName:"li"},"Battery")," / ",(0,o.kt)("inlineCode",{parentName:"li"},"App Battery")," > Choose ",(0,o.kt)("inlineCode",{parentName:"li"},"Unrestricted"),". Do the same for the Metamask app. After the setup, you can return it back to the default of ",(0,o.kt)("inlineCode",{parentName:"li"},"Optimized"))),(0,o.kt)("h2",{id:"add-multiple-fxbloxes"},"Add Multiple FxBloxes"),(0,o.kt)("p",null,"As of Android/iOS app version 1.6.7, there is not an easy way to add more than one blox to your account. Follow these additional steps if you would like to connect more than one blox:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"If not already done, complete setup of your first Blox."),(0,o.kt)("li",{parentName:"ol"},"Verify Blox is listed as ",(0,o.kt)("inlineCode",{parentName:"li"},"Authorized")," under ",(0,o.kt)("inlineCode",{parentName:"li"},"Settings"),"->",(0,o.kt)("inlineCode",{parentName:"li"},"Blox Discovery"),". If not, restart your Blox by unplug/plug-ing it back in."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"Log Out")," of your account by going to ",(0,o.kt)("inlineCode",{parentName:"li"},"Settings")," -> ",(0,o.kt)("inlineCode",{parentName:"li"},"Log Out"),"."),(0,o.kt)("li",{parentName:"ol"},"Proceed and complete set-up of your next FxBlox."),(0,o.kt)("li",{parentName:"ol"},"Repeat steps 2-4 for all the FxBloxes you have, except for the last one.",(0,o.kt)("div",{parentName:"li",className:"admonition admonition-info alert alert--info"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},"If you're using the default naming scheme ",(0,o.kt)("inlineCode",{parentName:"p"},"Blox unit #X"),", then name your last Blox ",(0,o.kt)("inlineCode",{parentName:"p"},"Blox unit #1"),". The reason for this is because the app will auto-number the rest of your Bloxes when you add them back in.")))),(0,o.kt)("li",{parentName:"ol"},"When you've finally added the last FxBlox, go to ",(0,o.kt)("inlineCode",{parentName:"li"},"Settings")," -> ",(0,o.kt)("inlineCode",{parentName:"li"},"Blox Discovery"),"."),(0,o.kt)("li",{parentName:"ol"},"All FxBloxes should say ",(0,o.kt)("inlineCode",{parentName:"li"},"Authorized"),", so select them and click ",(0,o.kt)("inlineCode",{parentName:"li"},"Add selected blox(s)"),"."),(0,o.kt)("li",{parentName:"ol"},"Verify you can see all of them by going to ",(0,o.kt)("inlineCode",{parentName:"li"},"Blox")," tab and swiping left/right between them.")),(0,o.kt)("div",{className:"admonition admonition-info alert alert--info"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},"As you can see the functionality is there, but prioritization of an easier way to add them is scheduled for after testnet launch."),(0,o.kt)("p",{parentName:"div"},(0,o.kt)("strong",{parentName:"p"},"Our apps are open-source and built in React Native for cross-platform support. So if you would like to ",(0,o.kt)("a",{parentName:"strong",href:"https://github.com/functionland/fx-components"},"contribute to the project"),", that would be greatly appreciated!")))),(0,o.kt)("h2",{id:"format-drive"},"Format Drive"),(0,o.kt)("p",null,"If you were eager to test out nightly releases on your own, you may have trouble joining the official launch of the testnet. This is because the blocks from the temporary chains are incompatible with the official testnet blocks. To fix this, you need to erase all previous blocks, easiest way is to format the drive."),(0,o.kt)("p",null,"To format your drive: "),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Tap on the ",(0,o.kt)("inlineCode",{parentName:"li"},"Blox")," tab to see this screen",(0,o.kt)("center",null,(0,o.kt)("img",{src:"/img/fxyard-network/blox-page.png",style:{width:450}}))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Tap and hold")," the ",(0,o.kt)("inlineCode",{parentName:"li"},"Hard Disk")," you want to format"),(0,o.kt)("li",{parentName:"ol"},"When the pop-up shows, click the ",(0,o.kt)("inlineCode",{parentName:"li"},"Format")," button",(0,o.kt)("center",null,(0,o.kt)("img",{src:"/img/fxyard-network/format-button.png",style:{width:400}}))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Now wait!")," The light will turn purple. This process may take more or less than 5 minutes, dependent on the speed of your drive."),(0,o.kt)("li",{parentName:"ol"},"The FxBlox will auto-reboot, after it is done the lights will turn off.")),(0,o.kt)("p",null,"FxBlox will automatically connect to testnet and save chain history. You should be able to join testnet now."),(0,o.kt)("h2",{id:"app-features"},"App features"),(0,o.kt)("p",null,"1- You can transfer your earned tokens to your wallet by holding your finger on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Earnings")," section in the Home Page and paste the address of you wallet by clicking the icon (Please note manually entering is not allowed)"),(0,o.kt)("p",null,"2- You can format the storage by holding your finger on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Hard Disks")," section of the Home Page"),(0,o.kt)("p",null,"3- You can check blox details by clicking on the blox icon in Home page and some other details by clicking on the profile icon on top right"),(0,o.kt)("p",null,"4- You can see added or existing Bloxes in the network, when you are connected to the same wifi as blox and choose ",(0,o.kt)("inlineCode",{parentName:"p"},"Blox Discovery")," from Settings tab"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/799a1b22.eb0d0dcf.js b/assets/js/799a1b22.eb0d0dcf.js deleted file mode 100644 index 18236162..00000000 --- a/assets/js/799a1b22.eb0d0dcf.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[7878],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>u});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,p=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=s(n),u=o,h=c["".concat(p,".").concat(u)]||c[u]||m[u]||i;return n?a.createElement(h,r(r({ref:t},d),{},{components:n})):a.createElement(h,r({ref:t},d))}));function u(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,r=new Array(i);r[0]=c;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l.mdxType="string"==typeof e?e:o,r[1]=l;for(var s=2;s{n.r(t),n.d(t,{contentTitle:()=>r,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(7462),o=(n(7294),n(3905));const i={title:"FxBlox App Setup",id:"fxblox-app"},r=void 0,l={unversionedId:"functionyard/fxblox-app",id:"functionyard/fxblox-app",title:"FxBlox App Setup",description:"Installing the FxBlox App",source:"@site/docs/functionyard/fxblox-app.md",sourceDirName:"functionyard",slug:"/functionyard/fxblox-app",permalink:"/functionyard/fxblox-app",tags:[],version:"current",frontMatter:{title:"FxBlox App Setup",id:"fxblox-app"},sidebar:"tutorialSidebar",previous:{title:"Add Storage",permalink:"/functionyard/add-storage"},next:{title:"Joining Testnet",permalink:"/functionyard/join"}},p=[{value:"Installing the FxBlox App",id:"installing-the-fxblox-app",children:[{value:"Initial Setup",id:"initial-setup",children:[],level:3},{value:"App Configuration Steps",id:"app-configuration-steps",children:[],level:3},{value:"Troubleshoot",id:"troubleshoot",children:[],level:3}],level:2},{value:"Add Multiple FxBloxes",id:"add-multiple-fxbloxes",children:[],level:2},{value:"Format Drive",id:"format-drive",children:[],level:2},{value:"App features",id:"app-features",children:[],level:2}],s={toc:p};function d(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,a.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"installing-the-fxblox-app"},"Installing the FxBlox App"),(0,o.kt)("h3",{id:"initial-setup"},"Initial Setup"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Download the App"),": ",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"For Android: ",(0,o.kt)("a",{parentName:"li",href:"https://play.google.com/store/apps/details?id=land.fx.blox"},"FxBlox on Google Play (v1.6.14+)"),"."),(0,o.kt)("li",{parentName:"ul"},"For iOS: ",(0,o.kt)("a",{parentName:"li",href:"https://apps.apple.com/ca/app/fxblox/id6444862171"},"FxBlox on AppStore (v1.6.14+)"),"."))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Metamask Wallet"),": Ensure you have a ",(0,o.kt)("a",{parentName:"li",href:"https://play.google.com/store/apps/details?id=io.metamask"},"Metamask wallet")," for setting up your identity.")),(0,o.kt)("h3",{id:"app-configuration-steps"},"App Configuration Steps"),(0,o.kt)("div",{className:"admonition admonition-info alert alert--info"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},"If adding more than one FxBlox to your app, get familiar with ",(0,o.kt)("a",{parentName:"p",href:"#add-multiple-fxbloxs"},"these instructions first.")))),(0,o.kt)("div",{className:"admonition admonition-info alert alert--info"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},"For a successful setup you should either have the Blox with internal storage, or attach an external storage to it."))),(0,o.kt)("div",{className:"admonition admonition-info alert alert--info"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},"Please make sure you first uninstall (not update) any previous version of FxBlox on your phone and then re-install the latest version"))),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},'Open Metamask Wallet. We recommend having the opening network set to "Ethereum Mainnet" for a smoother setup process.'),(0,o.kt)("li",{parentName:"ol"},"Minimize Metamask (not close) and open the FxBlox app."),(0,o.kt)("li",{parentName:"ol"},"Read the ",(0,o.kt)("a",{parentName:"li",href:"https://fx.land/terms"},"Terms and Condition")," and if you agree, then select ",(0,o.kt)("inlineCode",{parentName:"li"},"Agree and Setup Blox")," in the app."),(0,o.kt)("li",{parentName:"ol"},"Enter a memorable password for data encryption and click ",(0,o.kt)("inlineCode",{parentName:"li"},"Sign")," (Note: This is not your Metamask password)."),(0,o.kt)("li",{parentName:"ol"},"Complete the connection in the Metamask app, then return to the FxBlox app.",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"You may need to click back to manually return to the app if it does not open Blox automatically after you sign in Metamask"),(0,o.kt)("li",{parentName:"ul"},"It does not matter which chain (Ethereum, Mumbai, etc) you are on in your Metamask wallet."))),(0,o.kt)("li",{parentName:"ol"},"Tap ",(0,o.kt)("inlineCode",{parentName:"li"},"Connect to new blox"),"."),(0,o.kt)("li",{parentName:"ol"},'Manually connect your phone to the "FxBlox" WiFi/Hotspot, and turn off "mobile data", then continue in the app.')),(0,o.kt)("div",{className:"admonition admonition-warning alert alert--danger"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"12",height:"16",viewBox:"0 0 12 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"}))),"warning")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},'Everyone should format their storage in step 8. If you have Blox with internal storage, disconnect any external disk. If you have Blox with no internal storage, attach your external storage. At the "set Authorizer" page, wait for 10 seconds and a green button named "Format Disk" appears. click on it and blox turns ',(0,o.kt)("font",{color:"purple"}," purple")," and reboots after a few minutes. You should wait for the light to turn flashing ",(0,o.kt)("font",{color:"cyan"}," light blue")," again and then reconnect your phone to FxBlox again to continue the process"))),(0,o.kt)("ol",{start:8},(0,o.kt)("li",{parentName:"ol"},"Make sure you have attached at least 300GB of external storage to your FxBlox. Proceed by clicking ",(0,o.kt)("inlineCode",{parentName:"li"},"Next")," once the app recognizes the storage.",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"If the storage is not recognized ensure that is it correctly formatted by clicking on the ",(0,o.kt)("inlineCode",{parentName:"li"},"Format")," button.",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"The light will turn ",(0,o.kt)("font",{color:"purple"}," purple"),", to indicate it is formatting. ",(0,o.kt)("strong",{parentName:"li"},"Formatting times depend on storage medium and capacity"),", so be patient during this time. Device will reboot automatically and eventually start flashing ",(0,o.kt)("font",{color:"cyan"}," light blue")," again when it is ready to proceed."))),(0,o.kt)("li",{parentName:"ul"},"If you have an FxBlox version with internal storage, there is no need to attach external storage."))),(0,o.kt)("li",{parentName:"ol"},"Select your desired WiFi network for the FxBlox and enter the password.",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"If you entered the wrong password, double check you're connected to FxBlox Wifi and just go back to the wifi selection screen to choose and re-enter your password."))),(0,o.kt)("li",{parentName:"ol"},"Finally, on the last screen reconnect your mobile device to your home WiFi and you can turn on the mobile data again if you want to. The app will confirm the successful setup. Please note the app does not continue if you do not have an active internet connection. When Blox is connected to the internet, the LEDs turn ",(0,o.kt)("inlineCode",{parentName:"li"},"green")," for 30 seconds and then turn off."),(0,o.kt)("li",{parentName:"ol"},"We recommend unplugging and replugging the Blox after the initial setup once for a hard reboot and ensuring that everything is set. After you re-plug the power and it boots, it may reboot automatically once as well.")),(0,o.kt)("h3",{id:"troubleshoot"},"Troubleshoot"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Final step connection issues"),": Connect to mobile or home wifi, restart the FxBlox app, select ",(0,o.kt)("inlineCode",{parentName:"li"},"Connect to Existing Blox"),". If that doesn't work, restart the FxBlox device. Close app and reopen to proceed with ",(0,o.kt)("inlineCode",{parentName:"li"},"Connect to new Blox"),"."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"If Metamask doesn't redirect after signing transaction"),": Manually go back to the FxBlox app."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"App issues with Metamask"),': On some phones, if you cannot get the "Connect" and "sign" prompts in Metamask, you may need to put both the Metamask app and Blox app in Unrestricted mode from the "Battery Optimization". Go to: ',(0,o.kt)("inlineCode",{parentName:"li"},"Settings")," > ",(0,o.kt)("inlineCode",{parentName:"li"},"Apps")," > ",(0,o.kt)("inlineCode",{parentName:"li"},"FxBlox")," > ",(0,o.kt)("inlineCode",{parentName:"li"},"Battery")," / ",(0,o.kt)("inlineCode",{parentName:"li"},"App Battery")," > Choose ",(0,o.kt)("inlineCode",{parentName:"li"},"Unrestricted"),". Do the same for the Metamask app. After the setup, you can return it back to the default of ",(0,o.kt)("inlineCode",{parentName:"li"},"Optimized"))),(0,o.kt)("h2",{id:"add-multiple-fxbloxes"},"Add Multiple FxBloxes"),(0,o.kt)("p",null,"As of Android/iOS app version 1.6.7, there is not an easy way to add more than one blox to your account. Follow these additional steps if you would like to connect more than one blox:"),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"If not already done, complete setup of your first Blox."),(0,o.kt)("li",{parentName:"ol"},"Verify Blox is listed as ",(0,o.kt)("inlineCode",{parentName:"li"},"Authorized")," under ",(0,o.kt)("inlineCode",{parentName:"li"},"Settings"),"->",(0,o.kt)("inlineCode",{parentName:"li"},"Blox Discovery"),". If not, restart your Blox by unplug/plug-ing it back in."),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("inlineCode",{parentName:"li"},"Log Out")," of your account by going to ",(0,o.kt)("inlineCode",{parentName:"li"},"Settings")," -> ",(0,o.kt)("inlineCode",{parentName:"li"},"Log Out"),"."),(0,o.kt)("li",{parentName:"ol"},"Proceed and complete set-up of your next FxBlox."),(0,o.kt)("li",{parentName:"ol"},"Repeat steps 2-4 for all the FxBloxes you have, except for the last one.",(0,o.kt)("div",{parentName:"li",className:"admonition admonition-info alert alert--info"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},"If you're using the default naming scheme ",(0,o.kt)("inlineCode",{parentName:"p"},"Blox unit #X"),", then name your last Blox ",(0,o.kt)("inlineCode",{parentName:"p"},"Blox unit #1"),". The reason for this is because the app will auto-number the rest of your Bloxes when you add them back in.")))),(0,o.kt)("li",{parentName:"ol"},"When you've finally added the last FxBlox, go to ",(0,o.kt)("inlineCode",{parentName:"li"},"Settings")," -> ",(0,o.kt)("inlineCode",{parentName:"li"},"Blox Discovery"),"."),(0,o.kt)("li",{parentName:"ol"},"All FxBloxes should say ",(0,o.kt)("inlineCode",{parentName:"li"},"Authorized"),", so select them and click ",(0,o.kt)("inlineCode",{parentName:"li"},"Add selected blox(s)"),"."),(0,o.kt)("li",{parentName:"ol"},"Verify you can see all of them by going to ",(0,o.kt)("inlineCode",{parentName:"li"},"Blox")," tab and swiping left/right between them.")),(0,o.kt)("div",{className:"admonition admonition-info alert alert--info"},(0,o.kt)("div",{parentName:"div",className:"admonition-heading"},(0,o.kt)("h5",{parentName:"div"},(0,o.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,o.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,o.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,o.kt)("div",{parentName:"div",className:"admonition-content"},(0,o.kt)("p",{parentName:"div"},"As you can see the functionality is there, but prioritization of an easier way to add them is scheduled for after testnet launch."),(0,o.kt)("p",{parentName:"div"},(0,o.kt)("strong",{parentName:"p"},"Our apps are open-source and built in React Native for cross-platform support. So if you would like to ",(0,o.kt)("a",{parentName:"strong",href:"https://github.com/functionland/fx-components"},"contribute to the project"),", that would be greatly appreciated!")))),(0,o.kt)("h2",{id:"format-drive"},"Format Drive"),(0,o.kt)("p",null,"If you were eager to test out nightly releases on your own, you may have trouble joining the official launch of the testnet. This is because the blocks from the temporary chains are incompatible with the official testnet blocks. To fix this, you need to erase all previous blocks, easiest way is to format the drive."),(0,o.kt)("p",null,"To format your drive: "),(0,o.kt)("ol",null,(0,o.kt)("li",{parentName:"ol"},"Tap on the ",(0,o.kt)("inlineCode",{parentName:"li"},"Blox")," tab to see this screen",(0,o.kt)("center",null,(0,o.kt)("img",{src:"/img/fxyard-network/blox-page.png",style:{width:450}}))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Tap and hold")," the ",(0,o.kt)("inlineCode",{parentName:"li"},"Hard Disk")," you want to format"),(0,o.kt)("li",{parentName:"ol"},"When the pop-up shows, click the ",(0,o.kt)("inlineCode",{parentName:"li"},"Format")," button",(0,o.kt)("center",null,(0,o.kt)("img",{src:"/img/fxyard-network/format-button.png",style:{width:400}}))),(0,o.kt)("li",{parentName:"ol"},(0,o.kt)("strong",{parentName:"li"},"Now wait!")," The light will turn purple. This process may take more or less than 5 minutes, dependent on the speed of your drive."),(0,o.kt)("li",{parentName:"ol"},"The FxBlox will auto-reboot, after it is done the lights will turn off.")),(0,o.kt)("p",null,"FxBlox will automatically connect to testnet and save chain history. You should be able to join testnet now."),(0,o.kt)("h2",{id:"app-features"},"App features"),(0,o.kt)("p",null,"1- You can transfer your earned tokens to your wallet by holding your finger on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Earnings")," section in the Home Page and paste the address of you wallet by clicking the icon (Please note manually entering is not allowed)"),(0,o.kt)("p",null,"2- You can format the storage by holding your finger on the ",(0,o.kt)("inlineCode",{parentName:"p"},"Hard Disks")," section of the Home Page"),(0,o.kt)("p",null,"3- You can check blox details by clicking on the blox icon in Home page and some other details by clicking on the profile icon on top right"),(0,o.kt)("p",null,"4- You can see added or existing Bloxes in the network, when you are connected to the same wifi as blox and choose ",(0,o.kt)("inlineCode",{parentName:"p"},"Blox Discovery")," from Settings tab"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.ab4bb7c6.js b/assets/js/runtime~main.b41761a5.js similarity index 99% rename from assets/js/runtime~main.ab4bb7c6.js rename to assets/js/runtime~main.b41761a5.js index 7eeb4fef..e03c5d0b 100644 --- a/assets/js/runtime~main.ab4bb7c6.js +++ b/assets/js/runtime~main.b41761a5.js @@ -1 +1 @@ -(()=>{"use strict";var e,a,c,f,r,d={},b={};function t(e){var a=b[e];if(void 0!==a)return a.exports;var c=b[e]={id:e,loaded:!1,exports:{}};return d[e].call(c.exports,c,c.exports,t),c.loaded=!0,c.exports}t.m=d,t.c=b,e=[],t.O=(a,c,f,r)=>{if(!c){var d=1/0;for(n=0;n=r)&&Object.keys(t.O).every((e=>t.O[e](c[o])))?c.splice(o--,1):(b=!1,r0&&e[n-1][2]>r;n--)e[n]=e[n-1];e[n]=[c,f,r]},t.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return t.d(a,{a:a}),a},c=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,t.t=function(e,f){if(1&f&&(e=this(e)),8&f)return e;if("object"==typeof e&&e){if(4&f&&e.__esModule)return e;if(16&f&&"function"==typeof e.then)return e}var r=Object.create(null);t.r(r);var d={};a=a||[null,c({}),c([]),c(c)];for(var b=2&f&&e;"object"==typeof b&&!~a.indexOf(b);b=c(b))Object.getOwnPropertyNames(b).forEach((a=>d[a]=()=>e[a]));return d.default=()=>e,t.d(r,d),r},t.d=(e,a)=>{for(var c in a)t.o(a,c)&&!t.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:a[c]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((a,c)=>(t.f[c](e,a),a)),[])),t.u=e=>"assets/js/"+({53:"935f2afb",261:"reactPlayerKaltura",553:"39968117",710:"4321c919",771:"f19b4864",815:"a98adb27",1e3:"dbaeb152",1082:"665bb1c2",1142:"27873332",1413:"b7a78bd3",1477:"b2f554cd",1564:"c9e48236",1565:"eb64892a",1646:"f9ddae1b",1648:"72fa51da",1752:"01430d47",1915:"0fd2f69e",1919:"1cc0488f",1969:"395b74f0",1973:"ec9cc4dd",1989:"ffb0c1a3",2027:"da49a82e",2121:"reactPlayerFacebook",2217:"1299eea8",2356:"a2977611",2369:"e58963f1",2523:"be614d59",2546:"reactPlayerStreamable",2672:"2e7550da",2686:"96034ec1",2696:"63c3a5f4",2746:"68453654",2794:"2b0a0def",3009:"6c7613ed",3300:"17e75398",3334:"48a74962",3557:"b0d6fa48",3608:"9e4087bc",3616:"f7d1f36e",3649:"748a29f1",3693:"1c5b444a",3743:"reactPlayerVimeo",3772:"bc2ced7b",3780:"313672b0",3854:"8a24b94f",4004:"f277957b",4100:"c7806b8e",4205:"952b5e81",4258:"reactPlayerMux",4439:"reactPlayerYouTube",4492:"5a04bf5c",4566:"c4cee058",4667:"reactPlayerMixcloud",5006:"8ef82ac0",5065:"0ab2a066",5153:"6f0e7e6f",5192:"74636f36",5194:"37866fe0",5213:"32415a15",5326:"831e3b29",5389:"79f59562",5490:"736647ea",5507:"ef6fc643",6011:"reactPlayerFilePlayer",6125:"reactPlayerSoundCloud",6208:"7dbfe80c",6216:"reactPlayerTwitch",6235:"ec73ac1d",6358:"7e50ec22",6502:"aa32ca26",6936:"18f5500a",6938:"f9725412",6950:"e9a5100a",6971:"c377a04b",7118:"f0ae19a0",7162:"d589d3a7",7170:"ca2fca4c",7596:"reactPlayerDailyMotion",7648:"0f3c4d9e",7664:"reactPlayerPreview",7738:"2a6dab62",7823:"00e8b4a4",7868:"7ad88a01",7877:"649c7e91",7878:"799a1b22",7918:"17896441",8010:"b48a96ee",8055:"reactPlayerWistia",8265:"f2d4d1e7",8358:"f3ebba76",8432:"256e3dd8",8489:"b80db04d",8839:"bd78fdc3",8888:"reactPlayerVidyard",8899:"7e4aa304",8930:"eb9f70f2",9104:"07401f6a",9124:"533b8a8b",9514:"1be78505"}[e]||e)+"."+{53:"6ad5e475",261:"7579c0d7",553:"2fc350e4",710:"fa9bf934",771:"550109ad",815:"34495ab3",1e3:"b49b8aa8",1068:"a87e72e3",1082:"8715b56d",1142:"5aaceec2",1413:"4ab1d864",1477:"c8d67205",1564:"41f33c51",1565:"47fc0fd2",1646:"38b30559",1648:"9929271a",1752:"a9f034fa",1915:"b16d5aff",1919:"26666b79",1969:"b9af20b7",1973:"7f8a44a2",1989:"6046128c",2027:"40c9df2e",2121:"714a5363",2217:"f3cc2b87",2356:"b184da56",2369:"0bc6ff47",2523:"76ec7f64",2546:"7c035560",2672:"b11d26a3",2686:"64b3fcc3",2696:"853d0290",2746:"cccdd557",2794:"14c267da",3009:"81eb0cb7",3300:"a64b1917",3334:"fdee2724",3557:"b94fe364",3608:"afe79f3d",3616:"399b5b88",3649:"400bac3a",3693:"cf42c8aa",3743:"48dad143",3772:"8ce58896",3780:"7d871103",3854:"3cf62e6c",4004:"abee8faa",4100:"5d5783da",4205:"8ed02872",4258:"31068986",4439:"13ef0796",4492:"1b65df73",4566:"e5b16854",4608:"edbf3a69",4667:"2c7196c7",5006:"e5bc3ab0",5065:"fcd18960",5153:"02549f34",5192:"d67b68ca",5194:"80e497bc",5213:"b9978fbe",5326:"e6b73445",5389:"b0fa8dc6",5490:"0fd8e11e",5507:"4ac00692",6011:"021ba2b0",6125:"1f91fbb4",6208:"e58569e6",6216:"edb984e3",6235:"5cb354d3",6358:"8a08ab64",6502:"2bfb4cb1",6936:"5767e142",6938:"b47c2931",6950:"694634ee",6971:"6857c96a",7118:"de4a295b",7162:"e46a01e0",7170:"b93b8167",7596:"907aed8a",7648:"51a8acc9",7664:"bcf5d5e6",7738:"cb2608c8",7823:"732cc844",7868:"f87a36a9",7877:"3b4ed3a0",7878:"eb0d0dcf",7918:"4e7c453d",8010:"fcce28aa",8055:"08670365",8265:"32ec1ac2",8358:"b166dc93",8432:"97248456",8489:"c9da7313",8839:"e440c154",8888:"9e555253",8899:"e425a080",8930:"353aa1bf",9104:"a7df8159",9124:"e70ae8bc",9514:"1d073e0b"}[e]+".js",t.miniCssF=e=>"assets/css/styles.550d40eb.css",t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),f={},r="docs:",t.l=(e,a,c,d)=>{if(f[e])f[e].push(a);else{var b,o;if(void 0!==c)for(var l=document.getElementsByTagName("script"),n=0;n{b.onerror=b.onload=null,clearTimeout(s);var r=f[e];if(delete f[e],b.parentNode&&b.parentNode.removeChild(b),r&&r.forEach((e=>e(c))),a)return a(c)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=u.bind(null,b.onerror),b.onload=u.bind(null,b.onload),o&&document.head.appendChild(b)}},t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.p="/",t.gca=function(e){return e={17896441:"7918",27873332:"1142",39968117:"553",68453654:"2746","935f2afb":"53",reactPlayerKaltura:"261","4321c919":"710",f19b4864:"771",a98adb27:"815",dbaeb152:"1000","665bb1c2":"1082",b7a78bd3:"1413",b2f554cd:"1477",c9e48236:"1564",eb64892a:"1565",f9ddae1b:"1646","72fa51da":"1648","01430d47":"1752","0fd2f69e":"1915","1cc0488f":"1919","395b74f0":"1969",ec9cc4dd:"1973",ffb0c1a3:"1989",da49a82e:"2027",reactPlayerFacebook:"2121","1299eea8":"2217",a2977611:"2356",e58963f1:"2369",be614d59:"2523",reactPlayerStreamable:"2546","2e7550da":"2672","96034ec1":"2686","63c3a5f4":"2696","2b0a0def":"2794","6c7613ed":"3009","17e75398":"3300","48a74962":"3334",b0d6fa48:"3557","9e4087bc":"3608",f7d1f36e:"3616","748a29f1":"3649","1c5b444a":"3693",reactPlayerVimeo:"3743",bc2ced7b:"3772","313672b0":"3780","8a24b94f":"3854",f277957b:"4004",c7806b8e:"4100","952b5e81":"4205",reactPlayerMux:"4258",reactPlayerYouTube:"4439","5a04bf5c":"4492",c4cee058:"4566",reactPlayerMixcloud:"4667","8ef82ac0":"5006","0ab2a066":"5065","6f0e7e6f":"5153","74636f36":"5192","37866fe0":"5194","32415a15":"5213","831e3b29":"5326","79f59562":"5389","736647ea":"5490",ef6fc643:"5507",reactPlayerFilePlayer:"6011",reactPlayerSoundCloud:"6125","7dbfe80c":"6208",reactPlayerTwitch:"6216",ec73ac1d:"6235","7e50ec22":"6358",aa32ca26:"6502","18f5500a":"6936",f9725412:"6938",e9a5100a:"6950",c377a04b:"6971",f0ae19a0:"7118",d589d3a7:"7162",ca2fca4c:"7170",reactPlayerDailyMotion:"7596","0f3c4d9e":"7648",reactPlayerPreview:"7664","2a6dab62":"7738","00e8b4a4":"7823","7ad88a01":"7868","649c7e91":"7877","799a1b22":"7878",b48a96ee:"8010",reactPlayerWistia:"8055",f2d4d1e7:"8265",f3ebba76:"8358","256e3dd8":"8432",b80db04d:"8489",bd78fdc3:"8839",reactPlayerVidyard:"8888","7e4aa304":"8899",eb9f70f2:"8930","07401f6a":"9104","533b8a8b":"9124","1be78505":"9514"}[e]||e,t.p+t.u(e)},(()=>{var e={1303:0,532:0};t.f.j=(a,c)=>{var f=t.o(e,a)?e[a]:void 0;if(0!==f)if(f)c.push(f[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var r=new Promise(((c,r)=>f=e[a]=[c,r]));c.push(f[2]=r);var d=t.p+t.u(a),b=new Error;t.l(d,(c=>{if(t.o(e,a)&&(0!==(f=e[a])&&(e[a]=void 0),f)){var r=c&&("load"===c.type?"missing":c.type),d=c&&c.target&&c.target.src;b.message="Loading chunk "+a+" failed.\n("+r+": "+d+")",b.name="ChunkLoadError",b.type=r,b.request=d,f[1](b)}}),"chunk-"+a,a)}},t.O.j=a=>0===e[a];var a=(a,c)=>{var f,r,d=c[0],b=c[1],o=c[2],l=0;if(d.some((a=>0!==e[a]))){for(f in b)t.o(b,f)&&(t.m[f]=b[f]);if(o)var n=o(t)}for(a&&a(c);l{"use strict";var e,a,c,f,r,d={},b={};function t(e){var a=b[e];if(void 0!==a)return a.exports;var c=b[e]={id:e,loaded:!1,exports:{}};return d[e].call(c.exports,c,c.exports,t),c.loaded=!0,c.exports}t.m=d,t.c=b,e=[],t.O=(a,c,f,r)=>{if(!c){var d=1/0;for(n=0;n=r)&&Object.keys(t.O).every((e=>t.O[e](c[o])))?c.splice(o--,1):(b=!1,r0&&e[n-1][2]>r;n--)e[n]=e[n-1];e[n]=[c,f,r]},t.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return t.d(a,{a:a}),a},c=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,t.t=function(e,f){if(1&f&&(e=this(e)),8&f)return e;if("object"==typeof e&&e){if(4&f&&e.__esModule)return e;if(16&f&&"function"==typeof e.then)return e}var r=Object.create(null);t.r(r);var d={};a=a||[null,c({}),c([]),c(c)];for(var b=2&f&&e;"object"==typeof b&&!~a.indexOf(b);b=c(b))Object.getOwnPropertyNames(b).forEach((a=>d[a]=()=>e[a]));return d.default=()=>e,t.d(r,d),r},t.d=(e,a)=>{for(var c in a)t.o(a,c)&&!t.o(e,c)&&Object.defineProperty(e,c,{enumerable:!0,get:a[c]})},t.f={},t.e=e=>Promise.all(Object.keys(t.f).reduce(((a,c)=>(t.f[c](e,a),a)),[])),t.u=e=>"assets/js/"+({53:"935f2afb",261:"reactPlayerKaltura",553:"39968117",710:"4321c919",771:"f19b4864",815:"a98adb27",1e3:"dbaeb152",1082:"665bb1c2",1142:"27873332",1413:"b7a78bd3",1477:"b2f554cd",1564:"c9e48236",1565:"eb64892a",1646:"f9ddae1b",1648:"72fa51da",1752:"01430d47",1915:"0fd2f69e",1919:"1cc0488f",1969:"395b74f0",1973:"ec9cc4dd",1989:"ffb0c1a3",2027:"da49a82e",2121:"reactPlayerFacebook",2217:"1299eea8",2356:"a2977611",2369:"e58963f1",2523:"be614d59",2546:"reactPlayerStreamable",2672:"2e7550da",2686:"96034ec1",2696:"63c3a5f4",2746:"68453654",2794:"2b0a0def",3009:"6c7613ed",3300:"17e75398",3334:"48a74962",3557:"b0d6fa48",3608:"9e4087bc",3616:"f7d1f36e",3649:"748a29f1",3693:"1c5b444a",3743:"reactPlayerVimeo",3772:"bc2ced7b",3780:"313672b0",3854:"8a24b94f",4004:"f277957b",4100:"c7806b8e",4205:"952b5e81",4258:"reactPlayerMux",4439:"reactPlayerYouTube",4492:"5a04bf5c",4566:"c4cee058",4667:"reactPlayerMixcloud",5006:"8ef82ac0",5065:"0ab2a066",5153:"6f0e7e6f",5192:"74636f36",5194:"37866fe0",5213:"32415a15",5326:"831e3b29",5389:"79f59562",5490:"736647ea",5507:"ef6fc643",6011:"reactPlayerFilePlayer",6125:"reactPlayerSoundCloud",6208:"7dbfe80c",6216:"reactPlayerTwitch",6235:"ec73ac1d",6358:"7e50ec22",6502:"aa32ca26",6936:"18f5500a",6938:"f9725412",6950:"e9a5100a",6971:"c377a04b",7118:"f0ae19a0",7162:"d589d3a7",7170:"ca2fca4c",7596:"reactPlayerDailyMotion",7648:"0f3c4d9e",7664:"reactPlayerPreview",7738:"2a6dab62",7823:"00e8b4a4",7868:"7ad88a01",7877:"649c7e91",7878:"799a1b22",7918:"17896441",8010:"b48a96ee",8055:"reactPlayerWistia",8265:"f2d4d1e7",8358:"f3ebba76",8432:"256e3dd8",8489:"b80db04d",8839:"bd78fdc3",8888:"reactPlayerVidyard",8899:"7e4aa304",8930:"eb9f70f2",9104:"07401f6a",9124:"533b8a8b",9514:"1be78505"}[e]||e)+"."+{53:"6ad5e475",261:"7579c0d7",553:"2fc350e4",710:"fa9bf934",771:"550109ad",815:"34495ab3",1e3:"b49b8aa8",1068:"a87e72e3",1082:"8715b56d",1142:"5aaceec2",1413:"4ab1d864",1477:"c8d67205",1564:"41f33c51",1565:"47fc0fd2",1646:"38b30559",1648:"9929271a",1752:"a9f034fa",1915:"b16d5aff",1919:"26666b79",1969:"b9af20b7",1973:"7f8a44a2",1989:"6046128c",2027:"40c9df2e",2121:"714a5363",2217:"f3cc2b87",2356:"b184da56",2369:"0bc6ff47",2523:"76ec7f64",2546:"7c035560",2672:"b11d26a3",2686:"64b3fcc3",2696:"853d0290",2746:"cccdd557",2794:"14c267da",3009:"81eb0cb7",3300:"a64b1917",3334:"fdee2724",3557:"b94fe364",3608:"afe79f3d",3616:"399b5b88",3649:"400bac3a",3693:"cf42c8aa",3743:"48dad143",3772:"8ce58896",3780:"7d871103",3854:"3cf62e6c",4004:"abee8faa",4100:"5d5783da",4205:"8ed02872",4258:"31068986",4439:"13ef0796",4492:"1b65df73",4566:"e5b16854",4608:"edbf3a69",4667:"2c7196c7",5006:"e5bc3ab0",5065:"fcd18960",5153:"02549f34",5192:"d67b68ca",5194:"80e497bc",5213:"b9978fbe",5326:"e6b73445",5389:"b0fa8dc6",5490:"0fd8e11e",5507:"4ac00692",6011:"021ba2b0",6125:"1f91fbb4",6208:"e58569e6",6216:"edb984e3",6235:"5cb354d3",6358:"8a08ab64",6502:"2bfb4cb1",6936:"5767e142",6938:"b47c2931",6950:"694634ee",6971:"6857c96a",7118:"de4a295b",7162:"e46a01e0",7170:"b93b8167",7596:"907aed8a",7648:"51a8acc9",7664:"bcf5d5e6",7738:"cb2608c8",7823:"732cc844",7868:"f87a36a9",7877:"3b4ed3a0",7878:"ced56f76",7918:"4e7c453d",8010:"fcce28aa",8055:"08670365",8265:"32ec1ac2",8358:"b166dc93",8432:"97248456",8489:"c9da7313",8839:"e440c154",8888:"9e555253",8899:"e425a080",8930:"353aa1bf",9104:"a7df8159",9124:"e70ae8bc",9514:"1d073e0b"}[e]+".js",t.miniCssF=e=>"assets/css/styles.550d40eb.css",t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),f={},r="docs:",t.l=(e,a,c,d)=>{if(f[e])f[e].push(a);else{var b,o;if(void 0!==c)for(var l=document.getElementsByTagName("script"),n=0;n{b.onerror=b.onload=null,clearTimeout(s);var r=f[e];if(delete f[e],b.parentNode&&b.parentNode.removeChild(b),r&&r.forEach((e=>e(c))),a)return a(c)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:b}),12e4);b.onerror=u.bind(null,b.onerror),b.onload=u.bind(null,b.onload),o&&document.head.appendChild(b)}},t.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.p="/",t.gca=function(e){return e={17896441:"7918",27873332:"1142",39968117:"553",68453654:"2746","935f2afb":"53",reactPlayerKaltura:"261","4321c919":"710",f19b4864:"771",a98adb27:"815",dbaeb152:"1000","665bb1c2":"1082",b7a78bd3:"1413",b2f554cd:"1477",c9e48236:"1564",eb64892a:"1565",f9ddae1b:"1646","72fa51da":"1648","01430d47":"1752","0fd2f69e":"1915","1cc0488f":"1919","395b74f0":"1969",ec9cc4dd:"1973",ffb0c1a3:"1989",da49a82e:"2027",reactPlayerFacebook:"2121","1299eea8":"2217",a2977611:"2356",e58963f1:"2369",be614d59:"2523",reactPlayerStreamable:"2546","2e7550da":"2672","96034ec1":"2686","63c3a5f4":"2696","2b0a0def":"2794","6c7613ed":"3009","17e75398":"3300","48a74962":"3334",b0d6fa48:"3557","9e4087bc":"3608",f7d1f36e:"3616","748a29f1":"3649","1c5b444a":"3693",reactPlayerVimeo:"3743",bc2ced7b:"3772","313672b0":"3780","8a24b94f":"3854",f277957b:"4004",c7806b8e:"4100","952b5e81":"4205",reactPlayerMux:"4258",reactPlayerYouTube:"4439","5a04bf5c":"4492",c4cee058:"4566",reactPlayerMixcloud:"4667","8ef82ac0":"5006","0ab2a066":"5065","6f0e7e6f":"5153","74636f36":"5192","37866fe0":"5194","32415a15":"5213","831e3b29":"5326","79f59562":"5389","736647ea":"5490",ef6fc643:"5507",reactPlayerFilePlayer:"6011",reactPlayerSoundCloud:"6125","7dbfe80c":"6208",reactPlayerTwitch:"6216",ec73ac1d:"6235","7e50ec22":"6358",aa32ca26:"6502","18f5500a":"6936",f9725412:"6938",e9a5100a:"6950",c377a04b:"6971",f0ae19a0:"7118",d589d3a7:"7162",ca2fca4c:"7170",reactPlayerDailyMotion:"7596","0f3c4d9e":"7648",reactPlayerPreview:"7664","2a6dab62":"7738","00e8b4a4":"7823","7ad88a01":"7868","649c7e91":"7877","799a1b22":"7878",b48a96ee:"8010",reactPlayerWistia:"8055",f2d4d1e7:"8265",f3ebba76:"8358","256e3dd8":"8432",b80db04d:"8489",bd78fdc3:"8839",reactPlayerVidyard:"8888","7e4aa304":"8899",eb9f70f2:"8930","07401f6a":"9104","533b8a8b":"9124","1be78505":"9514"}[e]||e,t.p+t.u(e)},(()=>{var e={1303:0,532:0};t.f.j=(a,c)=>{var f=t.o(e,a)?e[a]:void 0;if(0!==f)if(f)c.push(f[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var r=new Promise(((c,r)=>f=e[a]=[c,r]));c.push(f[2]=r);var d=t.p+t.u(a),b=new Error;t.l(d,(c=>{if(t.o(e,a)&&(0!==(f=e[a])&&(e[a]=void 0),f)){var r=c&&("load"===c.type?"missing":c.type),d=c&&c.target&&c.target.src;b.message="Loading chunk "+a+" failed.\n("+r+": "+d+")",b.name="ChunkLoadError",b.type=r,b.request=d,f[1](b)}}),"chunk-"+a,a)}},t.O.j=a=>0===e[a];var a=(a,c)=>{var f,r,d=c[0],b=c[1],o=c[2],l=0;if(d.some((a=>0!==e[a]))){for(f in b)t.o(b,f)&&(t.m[f]=b[f]);if(o)var n=o(t)}for(a&&a(c);l Account | Functionland - +

Account

Create​

Description:​

This function generates a new SugarFunge key pair to interact with the node.

Steps:​

  1. Call the account/create endpoint.

Expected Output:​

{
"seed": "//074a488cc87418a474b5ac30dbcf979caf2099110af805fa208b1a0c53097fc2",
"account": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b"
}
  • seed: represents the private key of the new account.
  • account: represents the public key of the new account.

Fund​

Description:​

This function funds an account to be able to carry out different operations on the node. By funding an account, that key pair its inserted in the node's keystore.

Previous Steps:​

  1. Create an account

Steps:​

  1. Call the account/fund endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"amount": 750000000000,
"to": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b"
}
  • seed: the seed of the account that would be doing the funding.
  • to: the account address that will be funded.
  • amount: the specific amount to be added to the account.

Expected Output:​

{
"from": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"to": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b",
"amount": 750000000000
}
  • from: the account address that did the funding.
  • to: the account address that was funded.
  • amount: the specific amount that was added to the account.

Exists​

**Description:​

This function checks if the account exists and is active.

Note: This function will return false if the account has not been funded yet

Previous Steps:​

  1. Create an account
  2. Fund an account

Steps:​

  1. Call the account/exists endpoint with the following request body:

Example Input:​

{
"account": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
}
  • account: the account address that will be checked.

Expected Output:​

{
"account": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"exists": true
}
  • account: the checked account address.
  • exists: the account current status.

Seeded​

**Description:**​

This function computes the account from seed.

Previous Steps:​

  1. Create an account

Steps:​

  1. Call the account/seeded endpoint with the following request body:

Example Input:​

{
"seed": "//Alice"
}
  • seed: the seed of the account to be computed.

Expected Output:​

{
"seed": "//Alice",
"account": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
}
  • seed: the seed of the account.
  • account: the account address that was computed.

Balance​

Description:​

This function checks the balance of sugar in an account.

Previous Steps:​

  1. Create an account

Steps:​

  1. Call the account/balance endpoint with the following request body:

Example Input:​

{
"account": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b"
}
  • account: the account address that will be checked.

Expected Output:​

{
"amount": 750000000000
}
  • amount: the amount of sugar in that given account.
- + \ No newline at end of file diff --git a/blockchain/Recipes/Asset.html b/blockchain/Recipes/Asset.html index 13ce0c87..3fe46960 100644 --- a/blockchain/Recipes/Asset.html +++ b/blockchain/Recipes/Asset.html @@ -5,13 +5,13 @@ Asset | Functionland - +

Asset

Create Class​

Description:​

This function creates a new class of assets. Classes being a set that includes related assets that have common characteristics.

Previous Steps:​

  1. Create an account
  2. Fund an account

Steps:​

  1. Call the assets/create_class endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"metadata": {
"userdata": "Type 1"
},
"class_id": 1,
"owner": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b"
}
  • seed: the seed of the account that will pay for the transaction.
  • class_id: the class identifier (must be unique).
  • owner: the account address that will have ownership of the class.
  • metadata: additional information about the class.

Expected Output:​

{
"class_id": 1,
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
}
  • class_id: the class identifier.
  • who: the account address of the class owner.

Class Info​

Description:​

This function returns information about a class.

Previous Steps:​

  1. Create an account
  2. Fund an account
  3. Create a class

Steps:​

  1. Call the assets/class_info endpoint with the following request body:

Example Input:​

{
"class_id": 1
}
  • class_id: the class identifier.

Expected Output:​

{
"info": {
"class_id": 1,
"owner": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"metadata": {
"userdata": "data"
}
}
}
  • class_id: the class identifier.
  • owner: the account address of the class owner.
  • metadata: additional information about the asset.

Create​

Description:​

This function creates an asset.

Previous Steps:​

  1. Create an account
  2. Fund an account
  3. Create a class

Steps:​

  1. Call the assets/create endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"account": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b",
"class_id": 1,
"asset_id": 1,
"metadata": {
"userdata": "Type 1"
}
}
  • seed: the seed of the account that will pay for the transaction.
  • class_id: the class identifier
  • asset_id: the asset identifier (must be unique).
  • account: the account address that will have ownership of the asset.
  • metadata: additional information about the asset.

Expected Output:​

{
"class_id": 1,
"asset_id": 1,
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
}
  • class_id: the class identifier.
  • asset_id: the asset identifier.
  • who: the account address of the asset owner.

Info​

Description:​

This function returns information about an asset.

Previous Steps:​

  1. Create an account
  2. Fund an account
  3. Create a class
  4. Create an asset

Steps:​

  1. Call the assets/info endpoint with the following request body:

Example Input:​

{
"class_id": 1,
"asset_id": 1
}
  • class_id: the class identifier.
  • asset_id: the asset identifier.

Expected Output:​

{
"info": {
"class_id": 1,
"asset_id": 1,
"owner": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"metadata": {
"userdata": "data"
}
}
}
  • class_id: the class identifier.
  • asset_id: the asset identifier.
  • owner: the account address of the asset owner.
  • metadata: additional information about the asset.

Update Metadata​

Description:​

This function updates the asset class metadata.

Previous Steps:​

  1. Create an account
  2. Fund an account
  3. Create a class
  4. Create an asset

Steps:​

  1. Call the assets/update_metadata endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"metadata": {
"userdata": "some new data"
},
"class_id": 1,
"asset_id": 1
}
  • seed: the seed of the account that will pay for the transaction.
  • metadata: the new metadata to be set by this function.
  • class_id: the class identifier.
  • asset_id: the asset identifier.

Expected Output:​

{
"class_id": 1,
"asset_id": 1,
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"metadata": {
"userdata": "some new data"
}
}
  • class_id: the class identifier.
  • asset_id: the asset identifier.
  • who: the account address that paid for the transaction.
  • metadata: the information updated by the function.

Mint​

Description:​

This function mints an asset by a given amount.

Previous Steps:​

  1. Create an account
  2. Fund an account
  3. Create a class
  4. Create an asset

Steps:​

  1. Call the assets/mint endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"to": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b",
"class_id": 1
"asset_id": 1,
"amount": 500000
}
  • seed: the seed of the account that will pay for the transaction.
  • class_id: the class identifier
  • asset_id: the asset identifier
  • to: the account address that will have ownership of the assets.
  • amount: the specific amount of assets to be minted.

Expected Output:​

{
"to": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b",
"class_id": 1,
"asset_id": 1,
"amount": 500000,
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
}
  • who: the account address that paid for the transaction.
  • class_id: the class identifier
  • asset_id: the asset identifier
  • to: the account address that has the ownership of the assets.
  • amount: the specific amount of assets minted.

Burn​

Description:​

This function burns an asset by a given amount.

Previous Steps:​

  1. Create an account
  2. Fund an account
  3. Create a class
  4. Create an asset

Steps:​

  1. Call the assets/burn endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"from": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b",
"class_id": 1,
"asset_id": 1,
"amount": 4000
}
  • seed: the seed of the account that will pay for the transaction.
  • class_id: the class identifier
  • asset_id: the asset identifier
  • from: the account address that will burn the assets.
  • amount: the specific amount of assets to be burned.

Expected Output:​

{
"from": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b",
"class_id": 1,
"asset_id": 1,
"amount": 4000,
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
}
  • who: the account address that paid for the transaction.
  • class_id: the class identifier
  • asset_id: the asset identifier
  • from: the account address that burned the assets.
  • amount: the specific amount of assets burned.

Balance​

Description:​

This function checks the balance of an asset in the given account.

Previous Steps:​

  1. Create an account
  2. Fund an account
  3. Create a class
  4. Create an asset

Steps:​

  1. Call the assets/balance endpoint with the following request body:

Example Input:​

{
"account": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b",
"class_id": 1,
"asset_id": 1
}
  • class_id: the class identifier
  • asset_id: the asset identifier
  • account: the account address that will be checked.

Expected Output:​

{
"amount": 500000
}
  • amount: the specific amount of assets in the given account.

Transfer​

Description:​

This function transfers a given amount of assets from one account to another.

Previous Steps:​

  1. Create an account
  2. Fund an account
  3. Create a class
  4. Create an asset
  5. Mint an asset

Steps:​

  1. Call the assets/transfer_from endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"from": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b",
"to": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"class_id": 1,
"asset_id": 1,
"amount": 50000
}
  • seed: the seed of the account that will pay for the transaction.
  • class_id: the class identifier
  • asset_id: the asset identifier
  • from: the account address that will send the assets.
  • to: the account address that will receive the assets
  • amount: the specific amount of assets to be sent.

Expected Output:​

{
"from": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b",
"to": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"class_id": 1,
"asset_id": 1,
"amount": 50000,
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
}
  • who: the account address that paid for the transaction.
  • class_id: the class identifier
  • asset_id: the asset identifier
  • from: the account address that sent the assets.
  • to: the account address that received the assets
  • amount: the specific amount of assets sent.
- + \ No newline at end of file diff --git a/blockchain/Recipes/Bag.html b/blockchain/Recipes/Bag.html index 3e8bd8a6..74c586a7 100644 --- a/blockchain/Recipes/Bag.html +++ b/blockchain/Recipes/Bag.html @@ -5,13 +5,13 @@ Bag | Functionland - +

Bag

Register​

Description:​

This function register a bag transaction.

Steps:​

  1. Call the bag/register endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"class_id": 100000,
"metadata": {
"userdata": "somedata"
}
}
  • seed: the seed of the account that will pay for the transaction.
  • class_id: the new class identifier that the bag will manage.
  • metadata: additional information about the bag.

Expected Output:​

{
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"class_id": 100000
}
  • who: the account address that paid for the transaction.
  • class_id: the class identifier managed by the bag.

Create​

Description:​

This function creates a bag transaction.

Previous Steps:​

  1. Create an account.
  2. Fund an account.
  3. Register bag.

Steps:​

  1. Call the bag/create endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"class_id": 100000,
"owners": ["5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"],
"shares": [1]
}
  • seed: the seed of the account that will pay for the transaction.
  • class_id: the class identifier that the bag manages.
  • owners: array of account addresses that will be associated with the bag.
  • shares: the amount of share held by the corresponding owners.

Expected Output:​

{
"bag": "5EYCAe5jLQkbmk7kHzj7VNqTGExAEDCjwnnzSh1UEC9N9PgP",
"class_id": 100000,
"asset_id": 0,
"owners": [
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
]
}
  • owners: array of account addresses associated with the bag.
  • bag: the bag account.
  • class_id: the class identifier that the bag manages.
  • asset_id: the asset identifier that the bag manages.

Deposit​

Description:​

This function creates a new deposit to the bag account.

Previous Steps:​

  1. Create an account.
  2. Fund an account.
  3. Create a class.
  4. Create an asset.
  5. Mint an asset.
  6. Register bag.
  7. Create a bag.

Steps:​

  1. Call the bag/deposit endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"bag": "5EYCAe5jLQkbmk7kHzj7VNqTGExAEDCjwnnzSh1UEC9N9PgP",
"class_ids": [1],
"asset_ids": [[0,1]],
"amounts": [[100,200]]
}
  • seed: the seed of the account that will pay for the transaction.
  • bag: the bag account where the deposit will be made.
  • class_ids: an array of the class identifiers that will be part of the transaction.
  • asset_ids: an array of asset_ids arrays that will be related to each class_id.
  • amounts: an array of amount arrays that will be related to each asset_id.

Expected Output:​

{
"bag": "5EYCAe5jLQkbmk7kHzj7VNqTGExAEDCjwnnzSh1UEC9N9PgP",
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
}
  • who: the account address that paid for the transaction.
  • bag: the bag account.

Sweep​

Description:​

This function sweep the deposits made on an bag account to a given account.

Previous Steps:​

  1. Create an account.
  2. Fund an account.
  3. Create a class.
  4. Create an asset.
  5. Mint an asset.
  6. Register bag.
  7. Create a bag.
  8. Bag deposit.

Steps:​

  1. Call the bag/sweep endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"to": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"bag": "5EYCAe5jLQkbmk7kHzj7VNqTGExAEDCjwnnzSh1UEC9N9PgP"
}
  • seed: the seed of the account that will pay for the transaction.
  • bag: the bag account where the deposit were made.
  • to: the receiver account address.

Expected Output:​

{
"bag": "5EYCAe5jLQkbmk7kHzj7VNqTGExAEDCjwnnzSh1UEC9N9PgP",
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"to": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
}
  • who: the account address that paid for the transaction.
  • bag: the bag account.
  • to: the receiver account address.
- + \ No newline at end of file diff --git a/blockchain/Recipes/Bundle.html b/blockchain/Recipes/Bundle.html index b6412712..54a01529 100644 --- a/blockchain/Recipes/Bundle.html +++ b/blockchain/Recipes/Bundle.html @@ -5,13 +5,13 @@ Bundle | Functionland - +

Bundle

Register​

Description:​

This function registers a new bundle schema.

Previous Steps:​

  1. Create a class.
  2. Create an asset.
  3. Mint an asset.

Steps:​

  1. Call the bundle/register endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"class_id": 3,
"asset_id": 0,
"schema": {
"class_ids": [1],
"asset_ids": [
[1]
],
"amounts": [
[5]
]
},
"metadata": {
"userdata": ""
}
}
  • seed: the seed of the account that will pay for the transaction.
  • class_id: the new class identifier that the bundle will manage.
  • asset_id: the new asset identifier that the bundle will manage.
  • schema: this will represent all the classes and assets that need to be present in order to fulfill the other transactions
    • class_ids: an array of the class identifiers that will be part of the schema.
    • asset_ids: an array of asset_ids arrays that will be related to each class_id.
    • amounts: an array of amount arrays that will be related to each asset_id.
  • metadata: additional information about the bundle.

Expected Output:​

{
"bundle_id": "460bf8be553867922d58c434b3e672ffee40d163d4e744d28c1f67f93d0b3a3c",
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"class_id": 3,
"asset_id": 0
}
  • who: the account address associated with the bundle.
  • bundle_id: the bundle identifier.
  • class_id: the class identifier managed by the bundle.
  • asset_id: the asset identifier managed by the bundle.

Mint​

Description:​

This function mints a bundle.

Previous Steps:​

  1. Create an account.
  2. Register a bundle schema.

Steps:​

  1. Call the bundle/mint endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"from": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"to": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"bundle_id": "460bf8be553867922d58c434b3e672ffee40d163d4e744d28c1f67f93d0b3a3c",
"amount": 10
}
  • seed: the seed of the account that will pay for the transaction.
  • from: the account address of the sender.
  • to: the account address of the receiver.
  • bundle_id: the bundle identifier.
  • amount: the amount to be minted.

Expected Output:​

{
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"from": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"to": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"bundle_id": "460bf8be553867922d58c434b3e672ffee40d163d4e744d28c1f67f93d0b3a3c",
"amount": 10
}
  • who: the account address that paid for the transaction.
  • from: the account address of the sender.
  • to: the account address of the receiver.
  • bundle_id: the bundle identifier.
  • amount: the amount minted.

Get​

Description:​

Fetches the bundles registered

Previous Steps:​

  1. Create an account.
  2. Register a bundle schema.

Steps:​

  1. Call the bundle endpoint with the following request body:

Example Input:​

{}

Expected Output:​

{
"bundles": [
{
"bundle_id": "460bf8be553867922d58c434b3e672ffee40d163d4e744d28c1f67f93d0b3a3c",
"class_id": 5,
"asset_id": 1
}
]
}
  • bundle: an array with all the bundle registered.

Get Data​

Description:​

Fetches the data of the bundles registered

Previous Steps:​

  1. Create an account.
  2. Register a bundle schema.

Steps:​

  1. Call the bundle/data endpoint with the following request body:

Example Input:​

{}

Expected Output:​

{
"bundles": [
{
"bundle_id": "460bf8be553867922d58c434b3e672ffee40d163d4e744d28c1f67f93d0b3a3c",
"creator": "5EcFZ4EkYFMYcpJWyjgDde4zG8tVvmdanXeSyNTyD42r552b",
"class_id": 5,
"asset_id": 1
"schema": {
"class_ids": [1],
"asset_ids": [
[1]
],
"amounts": [
[5]
]
},
"metadata": {
"userdata": "info"
}
}
]
}
  • bundle: an array with all the bundle registered and its respective data.
- + \ No newline at end of file diff --git a/blockchain/Recipes/Challenges.html b/blockchain/Recipes/Challenges.html index 2fdec25d..0b71a968 100644 --- a/blockchain/Recipes/Challenges.html +++ b/blockchain/Recipes/Challenges.html @@ -5,13 +5,13 @@ Challenges | Functionland - +

Challenges

The Challenges were implemented to improve the security of the proof-engine and the claim of the Fula Tokens. The challenges consist of a series of random proof of storage of a manifest and they are made each cycle in the proof-engine, here:

  • The challenger doesn’t select the file to be challenged, it’s selected randomly between all the CIDs stored on the chain.
  • The challenged users have to send their current stored CIDs since they don’t know which CID is being challenged: These cids are checked with the IPFS information and the values stored on the chain. This promotes the challenged always to have their corresponding CIDs stored, since if it’s not stored in IPFS the challenge tokens for that CID could be lost.

The purpose of the Challenges is to collect Challenge Tokens that depends on the size of the file being challenged, these tokens are differentΒ from the Labor Tokens. The labor tokens are minted by each user in their proof-engine, while the challenge tokens need you to receive a challenge first from another user. In each cycle of the proof-engine the following actions are performed

  • Generate a random challenge to a CID of the chain.
  • Checks if a challenge against him is currently active
    • If thats the case, the challenge is verified and on a successful result the challenge tokens are minted for the challenged account, if failed no challenge tokens are gained this way.

The challenge tokens are going to be used with the labor tokens to transform them into claimed tokens:

  • In a regular case 1 Claimed token = 1 Labor token + 1 Challenge token.
  • In cases where the values minted by the labor tokens differ from the expected amounts each cycle (In case some error or attack is being made to get more tokens than they are supposed), a correction to the proportion will be made.

Generate Challenge​

Description:​

Starts a new random challenge of a CID.

Previous Steps:​

  1. Upload a manifest.
  2. Store a manifest.

Steps:​

  1. Call the fula/challenge/generate endpoint with the following request body:

Example Input:​

{
"seed": "//Alice"
}
  • seed: the seed of the account challenger.

Example Output:​

{
"challenger": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"challenged": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"cid": "CIDTest1",
"state": "Open"
}
  • challenger: the account of the challenger that made the request.
  • challenged: the selected account of the random challenge.
  • cid: the content identifier associated to the challenge.
  • state: the current state of this challenge (Open as its just been created)

Verify Challenge​

Description:​

Verifies the challenges made to an account and returns the successful and failed ones

Previous Steps:​

  1. Upload a manifest.
  2. Store a manifest.
  3. Generate a challenge.

Steps:​

  1. Call the fula/challenge/verify endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"pool_id": 1,
"cids": ["CIDTest1","CIDTest2"],
"class_id": 2000,
"asset_id": 3000
}
  • seed: the seed of the account to verify.
  • cid: an array of the content identifiers.
  • pool_id: the pool identifier.
  • class_id: the class identifier of labor token.
  • asset_id: the asset identifier of labor token.

Example Output:​

{
"challenged": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"successful": ["CIDTest1"],
"failed": ["CIDTest2"]
}
  • challenged: the account of the account being verified.
  • successful: and array of the contend identifiers thats were successful.
  • failed: and array of the contend identifiers thats were failed.

Mint Labor Tokens​

Description:​

This function mint labor tokens

Previous Steps:​

  1. Upload a manifest.
  2. Store a manifest.
  3. Generate a challenge.
  4. Verify a challenge

Steps:​

  1. Call the fula/mint_labor_tokens endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"pool_id": 1
"class_id": 2000,
"asset_id": 3000
}
  • seed: the seed of the account to verify.
  • pool_id: the pool identifier.
  • class_id: the class identifier of labor token.
  • asset_id: the asset identifier of labor token.

Example Output:​

{
"account": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"amount": 12345,
"class_id": 2000,
"asset_id": 3000
}
  • account: the account minting the labor tokens.
  • amount: the amount of labor tokens that were minted.
  • class_id: the class identifier of labor token.
  • asset_id: the asset identifier of labor token.

Verify Pending Challenge​

Description:​

Verifies if the given account has open challenges

Previous Steps:​

  1. Upload a manifest.
  2. Store a manifest.
  3. Generate a challenge.

Steps:​

  1. Call the fula/challenge/pending endpoint with the following request body:

Example Input:​

{
"seed": "//Alice"
}
  • seed: the seed of the account thats verifying if its got challenges.

Example Output:​

{
"account": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"pending": true
}
  • account: the account being verified.
  • pending: indicates if the account has some challenges open

Verify File Size​

Description:​

Cheks that the cids associate with an account are correct

Previous Steps:​

  1. Upload a manifest.
  2. Store a manifest.

Steps:​

  1. Call the fula/file/verify endpoint with the following request body:

Example Input:​

{
"seed": "//Alice"
}
  • seed: the seed of the account associated with the CIDs.

Example Output:​

{
"account": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"cids": ["CIDTest1","CIDTest2"]
}
  • account: the account being verified.
  • pending: an array of content identifiers

Provide Files Sizes​

Description:​

Updates the file of the sized for each cid provided.

Previous Steps:​

  1. Upload a manifest.
  2. Store a manifest.

Steps:​

  1. Call the fula/file/provide endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"pool_id": 1,
"cids": ["CIDTest1","CIDTest2"],
"sizes": [88359,23456],
}
  • seed: the seed of the account associated with the CIDs.
  • cid: an array of the content identifiers.
  • pool_id: the pool identifier.
  • sizes: an array of the file sized corresponding to the array of CIDs.

Example Output:​

{
"account": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"pool_id": 1,
"cids": ["CIDTest1","CIDTest2"],
"sizes": [88359,23456],
}
  • account: the account associated with the given CIDs.
  • cid: an array of the content identifiers.
  • pool_id: the pool identifier.
  • sizes: an array of the file sized corresponding to the array of CIDs.
- + \ No newline at end of file diff --git a/blockchain/Recipes/Claims.html b/blockchain/Recipes/Claims.html index 82b3d82a..39c78763 100644 --- a/blockchain/Recipes/Claims.html +++ b/blockchain/Recipes/Claims.html @@ -5,13 +5,13 @@ Claims | Functionland - +

Claims

Claim tokens​

Description:​

Its retrives all the claims done by the clients.

Steps:​

  1. Call the fula/claims endpoint with the following request body:

Expected Input:​

{}

Example Output:​

{
"claims": [
{
"account": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"minted_labor_tokens": 10,
"expected_labor_tokens": 0,
"minted_challenge_tokens": 1000
}
}
  • account: the account associated with the claims tokens.
  • minted_labor_tokens: the amount of labor tokens minted.
  • expected_labor_tokens: the amount of labor tokens expected.
  • minted_challenge_tokens: the amount of challenge tokens minted.
- + \ No newline at end of file diff --git a/blockchain/Recipes/Manifest.html b/blockchain/Recipes/Manifest.html index c41f1de0..6f97da42 100644 --- a/blockchain/Recipes/Manifest.html +++ b/blockchain/Recipes/Manifest.html @@ -5,13 +5,13 @@ Manifest | Functionland - +

Manifest

Upload Manifest​

Description:​

Allows the user to upload a manifest to the chain so it's available to be stored.

Previous Steps:​

  1. Upload the file on IPFS and copy the file CID.

Steps:​

  1. Call the manifest/upload endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"pool_id": 1,
"cid": "CIDTest1",
"replication_factor":2,
"manifest_metadata": {
"job": {
"work": "Storage",
"engine": "IPFS",
"uri": "CIDTest1"
}
}
}
  • seed: the seed of the account uploader.
  • replication_factor: the amount of times that file can be replicated.
  • pool_id: the pool identifier where the file its going to be uploaded.
  • manifest_metadata: the corresponding metadata of the manifest being uploaded.

Example Output:​

{
"uploader": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"storage": [],
"manifest_metadata": {
"job": {
"engine": "IPFS",
"uri": "CIDTest1",
"work": "Storage"
}
},
"pool_id": 1
}
  • uploader: the account of the file uploader.
  • storage: the accounts that are storing the file currently (initialized as empty).
  • manifest_metadata: the corresponding metadata of the manifest uploaded.
  • pool_id: the pool identifier where the file its going to be uploaded.

Batch Upload Manifest​

Description:​

Allows the user to upload multiple manifest to the chain so they’re available to be stored.

Previous Steps:​

  1. Upload the files on IPFS and copy the file CIDs.

Steps:​

  1. Call the manifest/batch_upload endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"pool_id": [1,1],
"cid":["CIDTest2", "CIDTest3"],
"replication_factor": [2,3],
"manifest_metadata": [{
"job": {
"work": "Storage",
"engine": "IPFS",
"uri": "CIDTest1"
}
},{
"job": {
"work": "Storage",
"engine": "IPFS",
"uri": "CIDTest2"
}
}]
}
  • seed: the seed of the account uploader.
  • replication_factor: the amount of times that file can be replicated.
  • pool_id: the pool identifier where the file its going to be uploaded.
  • manifest_metadata: the corresponding metadata of the manifest being uploaded.

Example Output:​

{
"uploader": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"pool_id": [1,1],
"manifest_metadata": [
{
"job": {
"engine": "IPFS",
"uri": "CIDTest1",
"work": "Storage"
}
},
{
"job": {
"engine": "IPFS",
"uri": "CIDTest2",
"work": "Storage"
}
}
]
}
  • uploader: the account of the file uploader.
  • manifest_metadata: the corresponding array of metadata of the manifests uploaded.
  • pool_id: the array of pool identifiers where the file its going to be uploaded.

Store Manifest​

Description:​

Allows the user to store a specific manifest through the cid of a manifest.

Previous Steps:​

  1. Upload a manifest.

Steps:​

  1. Call the manifest/storage endpoint with the following request body:

Example Input:​

{
"seed": "//Bob"
"cid": "CIDTest1",
"pool_id": 1
}
  • seed: the seed of the storage account.
  • cid: the content identifier associated with the file uploaded.
  • pool_id: the pool identifier where the file is uploaded.

Example Output:​

{
"storage": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"cid": "CIDTest1",
"pool_id": 1
}
  • storage: the account that's storing the file.
  • cid: the content identifier of the manifest being stored.
  • pool_id: the pool identifier where the file is uploaded.

Batch Store Manifest​

Description:​

Allows the user to store all the manifest he wants through the cids of those manifest.

Previous Steps:​

  1. Upload a manifest.

Steps:​

  1. Call the manifest/batch_storage endpoint with the following request body:

Example Input:​

{
"seed": "//Bob",
"pool_id": 1,
"cid": ["CIDTest1","CIDTest2"]
}
  • seed: the seed of the storage account.
  • cid: an array of the content identifiers associated with the files uploaded.
  • pool_id: the pool identifier where the file is uploaded.

Example Output:​

{
"storer": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"cid": ["CIDTest1","CIDTest2"]
"pool_id": 1
}
  • storer: the account that's storing the file.
  • cid: an array of the content identifiers associated with the files uploaded.
  • pool_id: the pool identifier where the file is uploaded.

Get Available​

Description:​

Fetches all the available manifests to be stored.

Previous Steps:​

  1. Upload a manifest.

Steps:​

  1. Call the manifest/available endpoint with the following request body:

Example Input:​

{
"pool_id": 1
}
  • pool_id: the pool identifier where the file is uploaded.

Example Output:​

{
"manifests": [
{
"pool_id": 1,
"manifest_data": {
"manifest_metadata": {
"job": {
"engine": "IPFS",
"uri": "CIDTest1",
"work": "Storage"
}
}
},
"replication_available": 1
}
]
}
  • manifests: an array of all the manifest that are available to be stored in that pool.

Get All​

Description:​

Fetches all the manifest there are or those related to the parameters given as filter.

Previous Steps:​

  1. Upload a manifest.

Steps:​

  1. Call the manifest endpoint with the following request body:

Note: If you call the function with empty parameters: { }. This will bring all the manifest there are.

Example Input:​

{
"pool_id": 1,
"account":"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
}
  • pool_id: the pool identifier where the files are uploaded.
  • account: the account that uploaded the files.

Example Output:​

{
"manifests": [
{
"pool_id": 1,
"uploaders": [
{
"uploader": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"storers": [],
"replication_available": 2
}
],
"manifest_metadata": {
"job": {
"engine": "IPFS",
"uri": "CIDTest1",
"work": "Storage"
}
}
}
]
}
  • manifests: an array of all the manifest that were fetch according to the parameters given.

Remove​

Description:​

The uploader or admin can remove a manifest from the pool.

Previous Steps:​

  1. Upload a manifest.

Steps:​

  1. Call the manifest/remove endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"cid": "CIDTest1",
"pool_id": 1
}
  • seed: the seed of the account uploader.
  • cid: the content identifier of the manifest being removed.
  • pool_id: the pool identifier where the file is being removed.

Example Output:​

{
"uploader": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"cid": "CIDTest1",
"pool_id": 1
}
  • uploader: the account of the file uploader.
  • cid: the content identifier of the manifest removed.
  • pool_id: the pool identifier where the file was removed.

Batch Remove​

Description:​

The uploader or admin can remove a manifest from the pool.

Previous Steps:​

  1. Upload a manifest.

Steps:​

  1. Call the manifest/batch_remove endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"pool_id": [1,1],
"cid": ["CIDTest1","CIDTest2"]
}
  • seed: the seed of the storage account.
  • cid: an array of the content identifiers associated with manifest being removed.
  • pool_id: the pool identifier where the file is being removed.

Example Output:​

{
"uploader": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"cid": ["CIDTest1","CIDTest2"],
"pool_id": [1,1],
}
  • uploader: the account of the file uploader.
  • cid: the array of content identifiers of the manifest removed.
  • pool_id: the pool identifier where the file was removed.

Remove Stored Manifest​

Description:​

The storer can stop storing a given manifest

Previous Steps:​

  1. Upload a manifest.
  2. Store a manifest.

Steps:​

  1. Call the manifest/remove_storing_manifest endpoint with the following request body:

Example Input:​

{
"seed": "//Bob",
"cid": "CIDTest1",
"pool_id": 1
}
  • seed: the seed of the account storer.
  • cid: the content identifier of the manifest to no longer be stored.
  • pool_id: the pool identifier.

Example Output:​

{
"storer": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"cid": "CIDTest1",
"pool_id": 1
}
  • storer: the account of the file storer.
  • cid: the content identifier of the manifest no longer being stored.
  • pool_id: the pool identifier.

Batch Remove Stored Manifest​

Description:​

The storer can stop storing the given manifests

Previous Steps:​

  1. Upload a manifest.
  2. Store a manifest.

Steps:​

  1. Call the manifest/batch_remove_storing_manifest endpoint with the following request body:

Example Input:​

{
"seed": "//Bob",
"cid": ["CIDTest1","CIDTest2"]
"pool_id": 1
}
  • seed: the seed of the account storer.
  • cid: the array of content identifiers of the manifests to no longer be stored.
  • pool_id: the pool identifier.

Example Output:​

{
"storer": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"cid": ["CIDTest1","CIDTest2"]
"pool_id": 1
}
  • storer: the account of the file storer.
  • cid: the array of content identifiers of the manifests no longer being stored.
  • pool_id: the pool identifier.
- + \ No newline at end of file diff --git a/blockchain/Recipes/Market.html b/blockchain/Recipes/Market.html index e8406368..7eaf1a12 100644 --- a/blockchain/Recipes/Market.html +++ b/blockchain/Recipes/Market.html @@ -5,13 +5,13 @@ Market | Functionland - +

Market

Create​

Description:​

This function creates a new market.

Previous Steps:​

  1. Create an account.
  2. Fund an account.

Steps:​

  1. Call the market/create_market endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"market_id": 1
}
  • seed: the seed of the account that will pay for the transaction.
  • market_id: the market identifier.

Expected Output:​

{
"market_id": 1,
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
}
  • who: the account address associated with the market.
  • market_id: the market identifier.

Create Market Rate​

Description:​

This function creates a new market rate.

Previous Steps:​

  1. Create an account.
  2. Fund an account.
  3. Create a class.
  4. Create an asset.
  5. Mint an asset.
  6. Create a market.

Steps:​

  1. Call the market/create_market_rate endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"market_id": 1,
"market_rate_id": 1,
"rates": {
"rates": [
{
"class_id": 2000,
"asset_id": 1,
"action": {
"Transfer": 1
},
"from": "Market",
"to": "Buyer"
},
{
"class_id": 2000,
"asset_id": 2,
"action": {
"Mint": 1
},
"from": "Market",
"to": "Buyer"
},
{
"class_id": 3000,
"asset_id": 1,
"action": {
"Has": [
"GreaterEqualThan",
5000
]
},
"from": "Buyer",
"to": "Market"
},
{
"class_id": 3000,
"asset_id": 2,
"action": {
"Transfer": 5
},
"from": "Buyer",
"to": "Market"
},
{
"class_id": 3000,
"asset_id": 3,
"action": {
"Burn": 50
},
"from": "Buyer",
"to": "Market"
},
{
"class_id": 4000,
"asset_id": 1,
"action": {
"Transfer": 2
},
"from": "Market",
"to": {
"Account": "//Alice"
}
},
{
"class_id": 4000,
"asset_id": 2,
"action": {
"Transfer": 1
},
"from": "Buyer",
"to": {
"Account": "//Alice"
}
}
],
"metadata": []
}
}
  • seed: the seed of the account that will pay for the transaction.
  • market_id: the market identifier
  • market_rate_id: the market rate identifier
  • rates:
    • rates: an array of the requirements that the transaction needs to fulfilled.
    • metadata: additional information about the rates.

Expected Output:​

{
"market_id": 1,
"market_rate_id": 1,
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
}
  • who: the account address associated with the market.
  • market_id: the market identifier.
  • market_rate_id: the market rate identifier.

Deposit Assets​

Description:​

This function deposits a given amount of assets in the market.

Previous Steps:​

  1. Create an account.
  2. Fund an account.
  3. Create a class.
  4. Create an asset.
  5. Mint an asset.
  6. Create a market.
  7. Create a market rate.

Steps:​

  1. Call the market/deposit_assets endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"market_id": 1,
"market_rate_id": 1,
"amount": 1000
}
  • seed: the seed of the account that will pay for the transaction.
  • market_id: the market identifier
  • market_rate_id: the market rate identifier
  • amount: the specific amount of assets to be deposited.

Expected Output:​

{
"who": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"market_id": 1,
"market_rate_id": 1,
"amount": 1000,
"balances": [],
"success": true
}
  • who: the account address associated with the market.
  • market_id: the market identifier.
  • market_rate_id: the market rate identifier.
  • amount: the specific amount of assets deposited.
  • balances: an array of the results of each operation after the deposit
  • success: an indicator to see if the deposited was successful

Exchange Assets​

Description:​

This function deposits a given amount of assets in the market.

Previous Steps:​

  1. Create an account.
  2. Fund an account.
  3. Create a class.
  4. Create an asset.
  5. Mint an asset.
  6. Create a market.
  7. Create a market rate.
  8. Deposit assets.

Steps:​

  1. Call the market/exchange_assets endpoint with the following request body:

Example Input:​

{
"seed": "//Bob",
"market_id": 1,
"market_rate_id": 1,
"amount": 1000
}
  • seed: the seed of the account that will pay for the transaction.
  • market_id: the market identifier
  • market_rate_id: the market rate identifier
  • amount: the specific amount of assets to be exchanged.

Expected Output:​

{
"buyer": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"market_id": 1,
"market_rate_id": 1,
"amount": 1000,
"balances": [
{
"rate": {
"class_id": 1,
"asset_id": 1,
"action": "Mint",
"amount": 1000,
"from": "Market",
"to": "Buyer"
},
"balance": 1000000
}
],
"success": true
}
  • who: the account address associated with the market.
  • market_id: the market identifier.
  • market_rate_id: the market rate identifier.
  • amount: the specific amount of assets exchanged.
  • balances: an array of the results of each operation after the exchange
  • success: an indicator to see if the deposited was successful
- + \ No newline at end of file diff --git a/blockchain/Recipes/Pool.html b/blockchain/Recipes/Pool.html index 409037bb..80e636a1 100644 --- a/blockchain/Recipes/Pool.html +++ b/blockchain/Recipes/Pool.html @@ -5,13 +5,13 @@ Pool | Functionland - +

Pool

Create​

Description:​

Allows the user to create a pool and is set as the owner of the pool

Previous Steps:​

  1. Create an account.
  2. Fund an account.

Steps:​

  1. Call the fula/pool/create endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"pool_name":"PoolNro1",
"peer_id": "PeerIdTest1",
"region": "Ontario"
}
  • seed: the seed of the account that will pay for the transaction.
  • pool_name: the name of the pool.
  • peer_id: the peer identifier

Expected Output:​

{
"owner": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"pool_id": 1
}
  • owner: the account address associated with the pool.
  • pool_id: the pool identifier.

Join​

Description:​

Sends a request to join a pool to its members, that will vote to decide if the user is Accepted or Denied

Previous Steps:​

  1. Create an account.
  2. Fund an account.
  3. Create a pool.

Steps:​

  1. Call the fula/pool/join endpoint with the following request body:

Example Input:​

{
"seed": "//Bob",
"pool_id": 1,
"peer_id": "PeerIdBob"
}
  • seed: the seed of the account that wants to join and will pay for the transaction.
  • pool_id: the pool identifier.
  • peer_id: the peer identifier

Expected Output:​

{
"pool_id": 1,
"account": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
}
  • account: the account address that requested to join the pool.
  • pool_id: the pool identifier.

Cancel Join​

Description:​

Withdraw the latest pool request sent to the given pool by that user.

Previous Steps:​

  1. Create an account.
  2. Fund an account.
  3. Create a pool.
  4. Request to join the pool.

Steps:​

  1. Call the fula/pool/cancel_join endpoint with the following request body:

Example Input:​

{
"seed": "//Bob",
"pool_id": 1
}
  • seed: the seed of the account that no longer wants to join the pool.
  • pool_id: the pool identifier.

Expected Output:​

{
"pool_id": 1,
"account": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
}
  • account: the account address that no longer wants to join the pool.
  • pool_id: the pool identifier.

Pool Requests​

Description:​

Allows the user to get all the current pool requests (can be filtered by pool_id and account of the requester)

Previous Steps:​

  1. Create an account.
  2. Fund an account.
  3. Create a pool.
  4. Request to join the pool.

Steps:​

  1. Call the fula/pool/poolrequests endpoint with the following request body:

Note: If you call the function with empty parameters: { }. This will bring all the pool requests there are.

Example Input:​

{
"pool_id": 1
}
  • pool_id: the pool identifier.

Expected Output:​

{
"poolrequests": [
{
"pool_id": 1,
"account": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"voted": [],
"positive_votes": 0,
"peer_id": "PeerIdBob"
}
]
}
  • poolrequests: an array of all the pool requests associated with the queried parameters

Pools​

Description:​

Fetches all the pools that exist in the chain

Previous Steps:​

  1. Create an account.
  2. Fund an account.
  3. Create a pool.

Steps:​

  1. Call the fula/pool/all endpoint

Expected Output:​

{
"pools": [
{
"pool_id": 1,
"creator": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"pool_name": "PoolTest1",
"region": "Ontario",
"parent": null,
"participants": [
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
]
}
]
}
  • pools: an array of all the pools and their respective information.

Users​

Description:​

Get all the accounts that are/were members of a pool or are requesting to be in one

Previous Steps:​

  1. Create an account.
  2. Fund an account.
  3. Create a pool.
  4. Join a pool.

Steps:​

  1. Call the fula/pool/users endpoint with the following request body:

Note: If you call the function with empty parameters: { }. This will bring all users.

Example Input:​

{
"pool_id": 1
}
  • pool_id: the pool identifier.

Expected Output:​

{
"users": [
{
"account": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"pool_id": null,
"request_pool_id": 1,
"peer_id": ""
},
{
"account": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
"pool_id": 1,
"request_pool_id": null,
"peer_id": "PeerIdTest1"
}
]
}
  • users: an array of all the users and their respective information.

Vote​

Description:​

Allows the members of a pool to vote to accept or denied a new given member into the pool

Previous Steps:​

  1. Create an account.
  2. Fund an account.
  3. Create a pool.
  4. Join a pool.
  5. Get pool requests.

Steps:​

  1. Call the fula/pool/vote endpoint with the following request body:

Example Input:​

{
"seed": "//Alice",
"pool_id": 1,
"account": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty",
"vote_value": true,
"peer_id": "PeerIdTest"
}
  • seed: the seed of the user voting.
  • pool_id: the pool identifier.
  • account: the account address of the user requesting to join.
  • vote_value: the vote of the user.

Expected Output:​

{
"pool_id": 1,
"account": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
}
  • pool_id: the pool identifier.
  • account: the account address of the user requesting to join.

Leave​

Description:​

The user leaves their pool and this will also remove the storing manifests that from their latest pool if they had any

Previous Steps:​

  1. Create an account.
  2. Fund an account.
  3. Create a pool.
  4. Join a pool.

Steps:​

  1. Call the fula/pool/leave endpoint with the following request body:

Example Input:​

{
"seed": "//Bob",
"pool_id": 1
}
  • seed: the seed of the user that wants to leave the pool.
  • pool_id: the pool identifier.

Expected Output:​

{
"pool_id": 1,
"account": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty"
}
  • pool_id: the pool identifier.
  • account: the account address of the user that left the pool.
- + \ No newline at end of file diff --git a/blockchain/Services/BuildNode.html b/blockchain/Services/BuildNode.html index 89d43f8f..4ba7e4b3 100644 --- a/blockchain/Services/BuildNode.html +++ b/blockchain/Services/BuildNode.html @@ -5,13 +5,13 @@ Build Node | Functionland - +

Build Node

1- Install Rust

curl https://sh.rustup.rs -sSf | sh

source ~/.bashrc

2- Install dependencies:

sudo apt-get install protobuf-compiler libclang-dev build-essential

3- Clone node repo

git clone https://github.com/functionland/sugarfunge-node.git

4- Enter the folder

cd ./sugarfunge-node

5- Install wasm32

rustup target add wasm32-unknown-unknown

6- Build

cargo build --release

Now a folder named "./target/release" is create where it contains all the compiled codes. If any error occured, your system might still be missing some dependancies. Please follow the full guide below and run step 6 again afterwards:

Install OS dependencies and Rust​

- + \ No newline at end of file diff --git a/blockchain/Services/Explorer.html b/blockchain/Services/Explorer.html index b4bb3ad7..2d9a2754 100644 --- a/blockchain/Services/Explorer.html +++ b/blockchain/Services/Explorer.html @@ -5,13 +5,13 @@ Explorer | Functionland - +

Explorer

Compile from Source

Install NodeJS​

Install Yarn​

Clone the Explorer​

git clone https://github.com/functionland/sugarfunge-explorer.git

Run the Explorer​

Requires a Node running.

yarn
WS_URL=ws://127.0.0.1:9944 yarn start

Using Docker

Install Docker​

Build the image​

docker build -t sugarfunge-explorer:local -f docker/Dockerfile .

Run the Explorer​

Requires a Node running.

docker run --rm -d --network host --env WS_URL=ws://127.0.0.1:9944 sugarfunge-explorer:local

Functionyard Network

If you want to run an explorer for functionyard network:

docker run --rm --name Explorer --network host --env WS_URL=wss://node.functionyard.fx.land --env WSS_URL=wss://node.functionyard.fx.land sugarfunge-explorer:local

Or set it as a service:

sudo nano /etc/systemd/system/docker-sugarfunge-explorer.service

And fill it with:

[Unit]
Description=Docker Sugarfunge Explorer
After=docker.service
Requires=docker.service

[Service]
TimeoutStartSec=0
Type=simple
ExecStart=/usr/bin/docker run --rm --name Explorer --network host --env WS_URL=wss://node.functionyard.fx.land --env WSS_URL=wss://node.functionyard.fx.land sugarfunge-explorer:local
ExecStop=/usr/bin/docker stop Explorer
Restart=always
StandardOutput=file:/var/log/Explorer.log
StandardError=file:/var/log/Explorer.err

[Install]
WantedBy=multi-user.target
- + \ No newline at end of file diff --git a/blockchain/Services/FulaContractAPI.html b/blockchain/Services/FulaContractAPI.html index 558d8cd3..ee526c83 100644 --- a/blockchain/Services/FulaContractAPI.html +++ b/blockchain/Services/FulaContractAPI.html @@ -5,13 +5,13 @@ Fula Contract API | Functionland - +

Fula Contract API

This is the end point that interacts with Fula blockchain contract

Run the Node API​

Requires a Node running.

Install dependencies​

sudo apt-get install build-essential

Set up the .env file​

Using the .env.example create the .env file and fill the needed values

LAUNCH THE FULA CONTRACT API​

Run the following command

cargo run --release -- --node-server=wss://node3.functionyard.fx.land

Alternatively, if you want to set it up as a service:

cargo build --release

then:

sudo nano /etc/systemd/system/fula-contract-api.service

And enter hte below in the file:

[Unit]
Description=Fula Contract API

[Service]
TimeoutStartSec=0
Type=simple
ExecStart=/home/user/fula-contract-api/target/release/functionland-contract-api --node-server=wss://node3.functionyard.fula.network
Restart=always
StandardOutput=file:/var/log/fula-contract-api.log
StandardError=file:/var/log/fula-contract-api.err

[Install]
WantedBy=multi-user.target

Then enable the service and start it. You can test the end points like below:

curl -X POST http://127.0.0.1:4001/health

Available endpoints​

Health: Verifies that the API is running

path: "health"

Read endpoints​

Supply: Consult the total supply of the token

paths: "goerli/supply", "mumbai/supply"

Allowance: Consult the current allowance of the given accounts

paths: "goerli/allowance", "mumbai/allowance"

Write endpoints​

Mint: Mint tokens to the given account

paths: "goerli/mint", "mumbai/mint"

Burn: Burn tokens from the given account if the necessary allowance

paths: "goerli/burn", "mumbai/burn"

Transfer: Transfer the tokens from the given account if the necessary allowance

paths: "goerli/transfer", "mumbai/transfer"

Increase_allowance: Increase the amount of tokens to be able to burn or transfer

paths: "goerli/increase_allowance", "mumbai/increase_allowance"

Decrease_allowance: Decrease the amount of tokens to be able to burn or transfer

paths: "goerli/decrease_allowance", "mumbai/decrease_allowance"
- + \ No newline at end of file diff --git a/blockchain/Services/Node.html b/blockchain/Services/Node.html index baa7e480..293ce960 100644 --- a/blockchain/Services/Node.html +++ b/blockchain/Services/Node.html @@ -5,13 +5,13 @@ Test Node | Functionland - +

Test Node

This document explains how to run sample nodes. However, for an actual node with custom keys please refer to Run Node

Compile from Source

Install OS dependencies and Rust​

Clone the Node​

git clone https://github.com/functionland/sugarfunge-node.git

Run a Local Testnet​

alice node:​

cargo run --release -- --chain=local --enable-offchain-indexing true --alice --base-path=.tmp/a --port=30334 --ws-port 9944 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external

bob node:​

cargo run --release -- --chain=local --enable-offchain-indexing true --bob --base-path=.tmp/b --port=30335 --ws-port 9945 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external --bootnodes /ip4/127.0.0.1/tcp/30334/p2p/12D3KooWNxmYfzomt7EXfMSLuoaK68JzXnZkNjXyAYAwNrQTDx7Y

charlie node:​

cargo run --release -- --chain=local --enable-offchain-indexing true --charlie --base-path=.tmp/c --port=30336 --ws-port 9946 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external --bootnodes /ip4/127.0.0.1/tcp/30334/p2p/12D3KooWNxmYfzomt7EXfMSLuoaK68JzXnZkNjXyAYAwNrQTDx7Y

Using Docker

Install Docker​

Build the image​

docker build -t sugarfunge-node:local -f docker/Dockerfile .

Run a Local Testnet​

alice node:​

docker run --rm -d --network host sugarfunge-node:local --chain=local --enable-offchain-indexing true --alice --base-path=.tmp/a --port=30334 --ws-port 9944 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external

bob node:​

docker run --rm -d --network host sugarfunge-node:local --chain=local --enable-offchain-indexing true --bob --base-path=.tmp/b --port=30335 --ws-port 9945 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external --bootnodes /ip4/127.0.0.1/tcp/30334/p2p/12D3KooWNxmYfzomt7EXfMSLuoaK68JzXnZkNjXyAYAwNrQTDx7Y

charlie node:​

docker run --rm -d --network host sugarfunge-node:local --chain=local --enable-offchain-indexing true --charlie --base-path=.tmp/c --port=30336 --ws-port 9946 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external --bootnodes /ip4/127.0.0.1/tcp/30334/p2p/12D3KooWNxmYfzomt7EXfMSLuoaK68JzXnZkNjXyAYAwNrQTDx7Y
- + \ No newline at end of file diff --git a/blockchain/Services/NodeAPI.html b/blockchain/Services/NodeAPI.html index 7b874886..db408862 100644 --- a/blockchain/Services/NodeAPI.html +++ b/blockchain/Services/NodeAPI.html @@ -5,13 +5,13 @@ Node API | Functionland - +

Node API

Compile from Source

Install OS dependencies and Rust​

Clone the Node API​

git clone https://github.com/functionland/sugarfunge-api.git

Run the Node API​

Requires a Node running.

cargo run --release

Using Docker

Install Docker​

Build the image​

docker build -t sugarfunge-api:local -f docker/Dockerfile .

Edit the .env​

sudo nano .ev.example

Save it and then:

sudo mv .env.example /var/lib/.sugarfunge-node/.env

Run the Node API​

Requires a Node running.

docker run --rm -d --name MyNode03API --network host -v /var/lib/.sugarfunge-node/.env:/.env -v /var/lib/.sugarfunge-node/data/node03:/data sugarfunge-api:local --db-uri=/data --node-server ws://127.0.0.1:9946

Available arguments

sugarfunge-api 0.1.0

USAGE:
sugarfunge-api [OPTIONS]

FLAGS:
-h, --help Prints help information
-V, --version Prints version information

OPTIONS:
-d, --db-uri <db>
-l, --listen <listen> [default: http://127.0.0.1:4000]
-s, --node-server <node-server> [default: ws://127.0.0.1:9944]

Subscriptions

Basic support for WebSockets subscriptions is available. Any tool that offers features for WebSockets connections and subscriptions will apply. For example, websocat

websocat ws://127.0.0.1:4000/ws

API Metadata Generation

If you update the Node manually and added pallets, it's required to generate the metadata with the SugarFunge fork of subxt to access the new state of the chain using the API.

cargo install subxt-cli

subxt-cli metadata -f bytes > sugarfunge_metadata.scale --url http://localhost:9934/
- + \ No newline at end of file diff --git a/blockchain/Services/ProofEngine.html b/blockchain/Services/ProofEngine.html index 58db6268..1da67626 100644 --- a/blockchain/Services/ProofEngine.html +++ b/blockchain/Services/ProofEngine.html @@ -5,13 +5,13 @@ Proof Engine | Functionland - +

Proof Engine

Compile from Source

Install OS dependencies and Rust​

Install Bevy dependencies for your OS​

Clone the Proof Engine​

git clone https://github.com/functionland/proof-engine.git

Run the Proof Engine​

Requires a Node, Node API and an IPFS node running.

RUST_LOG="warn,proof_engine=info" cargo run --release -- //Alice --pool-id 1000000

Using Docker

Install Docker​

Build the image​

docker build -t proof-engine:local -f docker/Dockerfile .

Run the Proof Engine​

Requires a Node, Node API and an IPFS node running.

docker run --rm -d --network host proof-engine:local
- + \ No newline at end of file diff --git a/blockchain/Services/RunNode.html b/blockchain/Services/RunNode.html index 6d7bf570..05b79157 100644 --- a/blockchain/Services/RunNode.html +++ b/blockchain/Services/RunNode.html @@ -5,7 +5,7 @@ Run Node | Functionland - + @@ -16,7 +16,7 @@ --base-path= .temp/node02 --suri β€œ the corresponding secret phrase”

5) COMMANDS TO START THE NODES

a) For the main validator node execute (replace the node-key with correct key of peer id):

cargo run --release -- --chain ./customSpecRaw.json --enable-offchain-indexing true --base-path=.tmp/node01 --port=30334 --ws-port 9944 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external --validator --name MyNode01 --password-interactive --node-key=4ac42a38b622dd9943c49ca9300000236406d35a43f0ce82eef556c1d81a4157

b) For the rest of validator nodes execute (replacing node-key with second peer id key and peerID after /p2p/ with the main node peer id) :

cargo run --release -- --chain ./customSpecRaw.json --enable-offchain-indexing true --base-path=.tmp/node02 --port=30335 --ws-port 9945 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external --bootnodes /ip4/127.0.0.1/tcp/30334/p2p/12D3KooWC9nU1QzG8m3dZKSNqssmasdupLPhgu9adYe1h4ToBW7r --validator --name MyNode02 --password-interactive --node-key=5ed89682d5d0d2efd35f98a248b97cc1f6155e6af169719f3d54900d34a98a4a

Note: For each of the commands the following fields should be change accordingly:

--base-path = .temp/node02 or .temp/node03
--port = To a port not used in other commands
--ws-port = To a port not used in other commands
--bootnodes = Update the last segment value to the peer-id of the main validator obtained in step 2
--name = to the given name
--node-key with the node key values obtained in step 2 for each account

Run Non-Validator Nodes

To add new nodes to the network that are not authorized:

1) GENERATE THE NODE-KEY AND PEER-ID FOR THE USER-THREE

a) Generate a random node key and peer-id

./target/release/sugarfunge-node key generate-node-key

sample output:

Peer-id: 12D3KooWF3MLTqgFRAKVqAdscdfZSSb9xXKFJ8paNEbtETKczUto
key: 239afb9dae01b5c010c454f1e1df64ce83b3e13803540df079677860a745d168

b) Save the key as a file

echo -n "239afb9dae01b5c010c454f1e1df64ce83b3e13803540df079677860a745d168" > user-three-key

c) Verify that the peer-id is correct using the node-key stored

./target/release/sugarfunge-node key inspect-node-key --file user-three-key

2) START NODE COMMAND FOR THE NOT AUTHORIZE NODE

cargo run --release -- --chain ./customSpecRaw.json --enable-offchain-indexing true --base-path=.tmp/node03 --port=30336 --ws-port 9946 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external --bootnodes /dns4/node.functionyard.fx.land/tcp/30334/p2p/12D3KooWBeXV65svCyknCvG1yLxXVFwRxzBLqvBJnUF6W84BLugv --name MyNode03 --node-key=[key3] --offchain-worker always

Note: For each of the commands the following fields should be change accordingly:

--base-path = .temp/node02 or .temp/node03
--port = To a port not used in other commands
--ws-port = To a port not used in other commands
--name = to the given name
--node-key with the node key values obtained in step 2 for each account

Here is the official Fula customSpecRaw.json file: Fula official raw specs


Using Docker

Install Docker​

Build the image​

cd sugarfunge-node

sudo mkdir /var/lib/.sugarfunge-node
sudo chmod 777 /var/lib/.sugarfunge-node
sudo mkdir /var/lib/.sugarfunge-node/passwords
sudo mkdir /var/lib/.sugarfunge-node/keys
sudo mkdir /var/lib/.sugarfunge-node/keys/node01
sudo mkdir /var/lib/.sugarfunge-node/keys/node02
sudo mkdir /var/lib/.sugarfunge-node/data
sudo mkdir /var/lib/.sugarfunge-node/data/node01
sudo mkdir /var/lib/.sugarfunge-node/data/node02

Now insert Keys:

./target/release/sugarfunge-node key insert --base-path=/var/lib/.sugarfunge-node/keys/node01 --chain customSpecRaw.json --scheme Sr25519 --suri "YOUR SECRET WORDS" --password-interactive --key-type aura

./target/release/sugarfunge-node key insert --base-path=/var/lib/.sugarfunge-node/keys/node01 --chain customSpecRaw.json --scheme Sr25519 --suri "YOUR SECRET WORDS" --password-interactive --key-type gran

Redo the same for node02 and put the keys for node02.

sudo nano /var/lib/.sugarfunge-node/passwords/password1.txt

Insert the password for node1 and redo with password2 for node2. Then revert the permission:

sudo chmod 755 /var/lib/.sugarfunge-node

Build:

docker build -t sugarfunge-node:local -f docker/Dockerfile .

Then you can run the validator nodes like:

docker run --rm -d --name MyNode01 --network host -v /var/lib/.sugarfunge-node/passwords/password1.txt:/password.txt -v /var/lib/.sugarfunge-node/keys/node01:/keys -v /var/lib/.sugarfunge-node/data/node01:/data sugarfunge-node:local --chain /customSpecRaw.json --enable-offchain-indexing true --base-path=/data --keystore-path=/keys --port=30334 --ws-port 9944 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external --validator --name MyNode01 --password-filename "/password.txt" --node-key=[key1]

docker run --rm -d --name MyNode02 --network host -v /var/lib/.sugarfunge-node/passwords/password2.txt:/password.txt -v /var/lib/.sugarfunge-node/keys/node02:/keys -v /var/lib/.sugarfunge-node/data/node02:/data sugarfunge-node:local --chain ./customSpecRaw.json --enable-offchain-indexing true --base-path=/data --keystore-path=/keys --port=30335 --ws-port 9945 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external --bootnodes /ip4/127.0.0.1/tcp/30334/p2p/[peerId1] --validator --name MyNode02 --password-filename "/password.txt" --node-key=[key2]

For non-validator node on Functionyard network, you can run:

docker run --rm -d --name MyNode03 --network host -v /var/lib/.sugarfunge-node/passwords/password3.txt:/password.txt -v /var/lib/.sugarfunge-node/keys/node03:/keys -v /var/lib/.sugarfunge-node/data/node03:/data sugarfunge-node:local --chain ./customSpecRaw.json --enable-offchain-indexing true --base-path=/data --keystore-path=/keys --port=30336 --ws-port 9946 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external --bootnodes /dns4/node.functionyard.fx.land/tcp/30334/p2p/12D3KooWBeXV65svCyknCvG1yLxXVFwRxzBLqvBJnUF6W84BLugv --name MyNode03 --node-key=[key3] --offchain-worker always

Run as service​

sudo nano /etc/systemd/system/docker-sugarfunge-node1.service

And insert:

[Unit]
Description=Docker Sugarfunge Node 1
After=docker.service
Requires=docker.service

[Service]
TimeoutStartSec=0
Type=simple
ExecStart=/usr/bin/docker run --rm --name MyNode01 --network host -v /var/lib/.sugarfunge-node/passwords/password1.txt:/password.txt -v /var/lib/.sugarfunge-node/keys/node01:/keys -v /var/lib/.sugarfunge-node/data/node01:/data sugarfunge-node:local --chain /customSpecRaw.json --enable-offchain-indexing true --base-path=/data --keystore-path=/keys --port=30334 --ws-port 9944 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external --validator --name MyNode01 --password-filename "/password.txt" --node-key=[key]
ExecStop=/usr/bin/docker stop MyNode01
Restart=always
StandardOutput=file:/var/log/MyNode01.log
StandardError=file:/var/log/MyNode01.err

[Install]
WantedBy=multi-user.target
sudo nano /etc/systemd/system/docker-sugarfunge-node2.service

And insert:

[Unit]
Description=Docker Sugarfunge Node 2
After=docker.service
Requires=docker.service

[Service]
TimeoutStartSec=0
Type=simple
ExecStart=/usr/bin/docker run --rm --name MyNode02 --network host -v /var/lib/.sugarfunge-node/passwords/password2.txt:/password.txt -v /var/lib/.sugarfunge-node/keys/node02:/keys -v /var/lib/.sugarfunge-node/data/node02:/data sugarfunge-node:local --chain ./customSpecRaw.json --enable-offchain-indexing true --base-path=/data --keystore-path=/keys --port=30335 --ws-port 9945 --ws-external --rpc-cors=all --rpc-methods=Unsafe --rpc-external --bootnodes /ip4/127.0.0.1/tcp/30334/p2p/[peerId1] --validator --name MyNode02 --password-filename "/password.txt" --node-key=[Key2]
ExecStop=/usr/bin/docker stop MyNode02
Restart=always
StandardOutput=file:/var/log/MyNode02.log
StandardError=file:/var/log/MyNode02.err

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable docker-sugarfunge-node1.service
sudo systemctl enable docker-sugarfunge-node2.service
sudo systemctl start docker-sugarfunge-node1.service
sudo systemctl start docker-sugarfunge-node2.service
- + \ No newline at end of file diff --git a/blockchain/Services/Status.html b/blockchain/Services/Status.html index afa42630..edc224a0 100644 --- a/blockchain/Services/Status.html +++ b/blockchain/Services/Status.html @@ -5,13 +5,13 @@ Status | Functionland - +

Status

Compile from Source

Install NodeJS​

Install Yarn​

Clone the Status​

git clone https://github.com/functionland/functionland-status.git

Run the Status​

Requires a Node running.

yarn
PORT=8000 REACT_APP_PROVIDER_SOCKET=ws://127.0.0.1:9944 yarn start

Using Docker

Install Docker​

Build the image​

docker build -t sugarfunge-status:local -f docker/Dockerfile .

Run the Status​

Requires a Node running.

docker run --rm -d --network host --env PORT=8000 --env REACT_APP_PROVIDER_SOCKET=ws://127.0.0.1:9944 sugarfunge-status:local
- + \ No newline at end of file diff --git a/blockchain/blockchain-intro.html b/blockchain/blockchain-intro.html index ba66864a..150f4d7f 100644 --- a/blockchain/blockchain-intro.html +++ b/blockchain/blockchain-intro.html @@ -5,13 +5,13 @@ Blockchain Documentation | Functionland - +

Blockchain Documentation

Here you can find the documenation on blockchain API and Services.

FULA Testnet

  • Network Name: Functionyard
  • Token Name: $BORG
  • Total Token Cap: 20B

Audit​

An Audit Report ic created by 0xMacro

Functionyard Audit Report

Contracts​

And also smart contracts are deployed:

1- Goerli Network

2- Mumbai Network

Explorer​

And a network explorer is made avaialbe here:

Network Explorer

Simulation​

Finally functionlard token simulations are available here:

Token Simulation

- + \ No newline at end of file diff --git a/blockchain/recipes.html b/blockchain/recipes.html index 11295143..b80302e6 100644 --- a/blockchain/recipes.html +++ b/blockchain/recipes.html @@ -5,13 +5,13 @@ Blockchain APIs | Functionland - + - + \ No newline at end of file diff --git a/blockchain/services.html b/blockchain/services.html index 5e300295..c2ed2252 100644 --- a/blockchain/services.html +++ b/blockchain/services.html @@ -5,13 +5,13 @@ Blockchain Services | Functionland - + - + \ No newline at end of file diff --git a/blog/archive.html b/blog/archive.html index ae82517b..5e752616 100644 --- a/blog/archive.html +++ b/blog/archive.html @@ -5,13 +5,13 @@ Archive | Functionland - +

Archive

Archive

- + \ No newline at end of file diff --git a/components/WorkInProgress.html b/components/WorkInProgress.html index 6dd010ab..8623d36d 100644 --- a/components/WorkInProgress.html +++ b/components/WorkInProgress.html @@ -5,13 +5,13 @@ WorkInProgress | Functionland - +

WorkInProgress

WIP Alert

Please note: these instructions remain a work in progress as we continue to evolve, refine and perfect the Fula API. Make sure to check back soon for more details!

- + \ No newline at end of file diff --git a/design/encryption.html b/design/encryption.html index edcb9409..3b6abad3 100644 --- a/design/encryption.html +++ b/design/encryption.html @@ -5,13 +5,13 @@ encryption | Functionland - +

encryption

Current Process:

Upload:

1- Get the wallet address and signature (time-based) from metamask

2- randomly create symmetric key on client per content

3- encrypt the file and send it to the backend

Sharing:

1- I get the person DID (which can be seeded with wallet address)

2- I generate the jwe specific to the DID

3- If we want the revoke, we need to also put some information in the jwe that we need to fetch from a globally accessible source(ceramic, blockchain,...) to validate access. Otherwise, we still have the time-based revokation feature

4- Share the jwe with the signature included in the header

5- The other person can validate and open the file

Cons:

1- Encryption is CPU insentive

2- revokation before the time expires require a globally accessible source

Pros:

1- size of jwe does not depend on the size of the file

2- one encrypted file can be shared with multiple people

3- jwe file can be shared on public ipfs without any security problem

- + \ No newline at end of file diff --git a/design/test.html b/design/test.html index 06ef3b80..eaa6d049 100644 --- a/design/test.html +++ b/design/test.html @@ -5,13 +5,13 @@ test | Functionland - +

test

this is a test

- + \ No newline at end of file diff --git a/functionyard.html b/functionyard.html index b00e0e1f..e9296ea7 100644 --- a/functionyard.html +++ b/functionyard.html @@ -5,13 +5,13 @@ Functionyard | Functionland - +

Functionyard Testnet Launch Guide

This comprehensive guide is designed to assist in preparing a FxBlox owner for the testnet launch. The testnet is called "Functionyard" and the token is "BORG".

- + \ No newline at end of file diff --git a/functionyard/add-storage.html b/functionyard/add-storage.html index b8fb4ebc..a4571ca5 100644 --- a/functionyard/add-storage.html +++ b/functionyard/add-storage.html @@ -5,7 +5,7 @@ Add Storage | Functionland - + @@ -14,7 +14,7 @@ :::If it asks to choose between files If it asks to choose (y/n) between two file versions, enter n. :::
  • Download parted app with sudo apt install parted
  • Identify new disk(s) with lsblk. External drives will show up as sdX. Internal drives would show up as the type of device.
  • info

    In the following commands, replace sdx with the device name(s) found in the output of the above command. Repeat steps 10-12 for any new drives you have, one at a time.

    1. Assign your drive the GPT partition standard with sudo parted /dev/sdx mklabel gpt
    2. Partition your drive with sudo parted -a opt /dev/sdx mkpart primary ext4 0% 100%
    3. Format the newly created partition with sudo mkfs.ext4 /dev/sdx1
    4. Wait for it to complete. Then restart FxBlox app.
    5. You should now see that your total maximum storage has increased by the size of the drive you installed. You may also need to hit the refresh button.

    If you have any issues, checkout the Troubleshoot section for more information.

    MacOS (Terminal)​

    Ext4 is a linux standard that MacOS does not support without some third-party help. You will not be able to use the Disk Utility app on Mac, to partition to Ext4. We do not need to mount our drive to Mac, we just need to partition and format it. To do so:

    Video Guide​

    Written Guide​

    1. Start by downloading the fdisk command-line tool on sourceforge
    2. Install app by double-clicking on the downloaded dpkg file
    3. You will not be able to open it, because of Apple security measures. To circumvent them, open Settings -> Privacy & Security -> Security
    4. Click on Allow Anyways
    5. Connect drive to Mac, if not already done. Click Allow to allow access to drive and now click Ignore to keep it discoverable
    6. Open up your Terminal app by searching your Applications or search with Spotlight by pressing CMD + SPACEBAR, then type Terminal
    7. Identify disk location with diskutil list. You'll want to keep note of the path, it should be something like /dev/disk#
    8. Now start command-line utility with sudo gdisk. See Example Output and Troubleshoot for more information.
    9. Enter device path found in step 7.
    10. Hit n, to create a new GPT partition
      • If partition already exists, press d to delete it.
      • if multiple partitions exist, checkout Troubleshoot section.
    11. Accept the default partition number by just pressing return/Enter.
    12. Accept the default starting and ending sectors (creates a partition that spans 100% of the drive) by just pressing return/Enter
    13. Enter 8300 for the Hex-code/GUID. This is short form to select the 'Linux Filesystem'
    14. Enter w to write table to disk and exit tool
    15. Hit y to proceed, wait for it to complete, and safely eject and reinsert drive.

    Example Output​

    After partitioning is complete. Now we can format using the e2fsprogs command.

    1. Download with brew install e2fsprogs. This might take a while if Brew is not up-to-date.
    2. Now verify disk path again with diskutil list.
    3. Run sudo `brew --prefix e2fsprogs`/sbin/mkfs.ext4 /dev/diskXs1
    replace the X in /dev/diskXs1 with the path found in step 18!
    1. Wait for it to complete and safely eject drive.
    2. Connect your drive to the FxBlox.
    3. Close FxBlox app. Now open your Fxblox app now and see your total maximum storage increase in the FxBlox app.

    If the drive does not show within the next 5 minutes there maybe a variety of issues occurring. Checkout the Troubleshooting section for more details.

    Windows (Free Third-Party App)​

    Ext4 is a linux standard that Windows does not support without some third-party help. There are various paid and free options out there, but we recommend Parition Master Free by EaseUS.

    Video Guide​

    Written Guide​

    1. Install Partition Master Free by EaseUS if not already done

    2. Plug in storage device to your Windows computer, if not already done

    3. Open the app. Select Partition Manager from the left sidebar

      • It may immediately recognize the drive and push you to use the Partition Wizard. The partition wizard is a paid service, so if you exit out of that window you can continue to use the app normally (as described below).
    4. Select the new drive

    blank drive

    1. Ensure drive partition type is listed as GPT instead of MBR.
      • If it is not, select drive. Then, in right sidebar, select Initialize to GPT to add it to task list queue.
      • Optionally, execute task.
    1. Select unallocated drive, and on the right sidebar, click Create

    2. Make sure EXT4 is selected under File system

    3. Click OK

    4. Click Execute # Task(s) at the bottom of the right sidebar of the main window

    1. Wait for task(s) to complete, then close app and eject drive

    2. Connect your drive to the FxBlox

    3. Close FxBlox app if its currently opened, otherwise open your Fxblox app now and see your total maximum storage increase in the FxBlox app.

    Troubleshoot​

    • Drive not recognized in Windows. If your windows computer doesn't see the connected drive, try restarting your computer first. Then look into potentially installing drivers for the storage device.
    • Storage capacity not updating This could be for a variety of issues:
      • Try closing/opening your app a couple of times, but also press the retry buttons a once or twice in between.
      • Restart the FxBlox by unplug-plugging it back in.
      • The usb3 drive is connected to a usb2 port. On a FxBlox Lite, the top two ports are USB2.0 and the bottom is USB3.0. On a FxBlox Lite Plus, the top port is USB2.0 and the bottom two are USB3.0.
    • Additional storage devices not showing up under Device Tab. This is a known bug, as of app version 1.6.2. Currently, newly added storage gets added to the total instead of as a separate device.
    • Partition Exists already (MacOS). If a partition exists already, then you will want to delete it first, write to drive, and rerun the command:
      1. Get to step 9 in the Manually Partition and Format for Mac instructions
      2. Hit d, to delete partition(s).
      3. Hit w, confirm by hitting y and saving state.
      4. Continue Manually Partition and Format for Mac instructions, from step 7.
    info

    Our apps are open-source and built in React Native for cross-platform support. So if you would like to contribute to the project, that would be greatly appreciated!

    - + \ No newline at end of file diff --git a/functionyard/dapps.html b/functionyard/dapps.html index 39b3cb98..048c4fc2 100644 --- a/functionyard/dapps.html +++ b/functionyard/dapps.html @@ -5,13 +5,13 @@ Decentralized Apps | Functionland - +

    Decentralized Apps

    Download FxFotos App​

    • Download FxFotos from Google Play for decentralized media storage. FxFotos app is available as a replacement for other Media storage apps (like Apple Photos or Google Photos).
    • We are also working on the FxFiles app which is right now available on Google Play but the integration with Fula protocol is not completed, so acts as a local file storage right now but with very cool features.
    - + \ No newline at end of file diff --git a/functionyard/fxblox-app.html b/functionyard/fxblox-app.html index cb834dd0..52b3b1d7 100644 --- a/functionyard/fxblox-app.html +++ b/functionyard/fxblox-app.html @@ -5,13 +5,13 @@ FxBlox App Setup | Functionland - +
    -

    FxBlox App Setup

    Installing the FxBlox App​

    Initial Setup​

    1. Download the App:
    2. Metamask Wallet: Ensure you have a Metamask wallet for setting up your identity.

    App Configuration Steps​

    info

    If adding more than one FxBlox to your app, get familiar with these instructions first.

    info

    For a successful setup you should either have the Blox with internal storage, or attach an external storage to it.

    info

    Please make sure you first uninstall (not update) any previous version of FxBlox on your phone and then re-install the latest version

    1. Open Metamask Wallet. We recommend having the opening network set to "Ethereum Mainnet" for a smoother setup process.
    2. Minimize Metamask (not close) and open the FxBlox app.
    3. Read the Terms and Condition and if you agree, then select Agree and Setup Blox in the app.
    4. Enter a memorable password for data encryption and click Sign (Note: This is not your Metamask password).
    5. Complete the connection in the Metamask app, then return to the FxBlox app.
      • You may need to click back to manually return to the app if it does not open Blox automatically after you sign in Metamask
      • It does not matter which chain (Ethereum, Mumbai, etc) you are on in your Metamask wallet.
    6. Tap Connect to new blox.
    7. Manually connect your phone to the "FxBlox" WiFi/Hotspot, and turn off "mobile data", then continue in the app.
    warning

    Everyone should format their storage in step 8. If you have Blox with internal storage, disconnect any external disk. If you have Blox with no internal storage, attach your external storage. At the "set Authorizer" page, wait for 10 seconds and a green button named "Format Disk" appears. click on it and blox turns purple and reboots after a few minutes. You should wait for the light to turn flashing light blue again and then reconnect your phone to FxBlox again to continue the process

    1. Make sure you have attached at least 300GB of external storage to your FxBlox. Proceed by clicking Next once the app recognizes the storage.
      • If the storage is not recognized ensure that is it correctly formatted by clicking on the Format button.
        • The light will turn purple, to indicate it is formatting. Formatting times depend on storage medium and capacity, so be patient during this time. Device will reboot automatically and eventually start flashing light blue again when it is ready to proceed.
      • If you have an FxBlox version with internal storage, there is no need to attach external storage.
    2. Select your desired WiFi network for the FxBlox and enter the password.
      • If you entered the wrong password, double check you're connected to FxBlox Wifi and just go back to the wifi selection screen to choose and re-enter your password.
    3. Finally, on the last screen reconnect your mobile device to your home WiFi and you can turn on the mobile data again if you want to. The app will confirm the successful setup. Please note the app does not continue if you do not have an active internet connection. When Blox is connected to the internet, the LEDs turn green for 30 seconds and then turn off.
    4. We recommend unplugging and replugging the Blox after the initial setup once for a hard reboot and ensuring that everything is set. After you re-plug the power and it boots, it may reboot automatically once as well.

    Troubleshoot​

    • Final step connection issues: Connect to mobile or home wifi, restart the FxBlox app, select Connect to Existing Blox. If that doesn't work, restart the FxBlox device. Close app and reopen to proceed with Connect to new Blox.
    • If Metamask doesn't redirect after signing transaction: Manually go back to the FxBlox app.
    • App issues with Metamask: On some phones, if you cannot get the "Connect" and "sign" prompts in Metamask, you may need to put both the Metamask app and Blox app in Unrestricted mode from the "Battery Optimization". Go to: Settings > Apps > FxBlox > Battery / App Battery > Choose Unrestricted. Do the same for the Metamask app. After the setup, you can return it back to the default of Optimized

    Add Multiple FxBloxes​

    As of Android/iOS app version 1.6.7, there is not an easy way to add more than one blox to your account. Follow these additional steps if you would like to connect more than one blox:

    1. If not already done, complete setup of your first Blox.
    2. Verify Blox is listed as Authorized under Settings->Blox Discovery. If not, restart your Blox by unplug/plug-ing it back in.
    3. Log Out of your account by going to Settings -> Log Out.
    4. Proceed and complete set-up of your next FxBlox.
    5. Repeat steps 2-4 for all the FxBloxes you have, except for the last one.
      info

      If you're using the default naming scheme Blox unit #X, then name your last Blox Blox unit #1. The reason for this is because the app will auto-number the rest of your Bloxes when you add them back in.

    6. When you've finally added the last FxBlox, go to Settings -> Blox Discovery.
    7. All FxBloxes should say Authorized, so select them and click Add selected blox(s).
    8. Verify you can see all of them by going to Blox tab and swiping left/right between them.
    info

    As you can see the functionality is there, but prioritization of an easier way to add them is scheduled for after testnet launch.

    Our apps are open-source and built in React Native for cross-platform support. So if you would like to contribute to the project, that would be greatly appreciated!

    Format Drive​

    If you were eager to test out nightly releases on your own, you may have trouble joining the official launch of the testnet. This is because the blocks from the temporary chains are incompatible with the official testnet blocks. To fix this, you need to erase all previous blocks, easiest way is to format the drive.

    To format your drive:

    1. Tap on the Blox tab to see this screen
    2. Tap and hold the Hard Disk you want to format
    3. When the pop-up shows, click the Format button
    4. Now wait! The light will turn purple. This process may take more or less than 5 minutes, dependent on the speed of your drive.
    5. The FxBlox will auto-reboot, after it is done the lights will turn off.

    FxBlox will automatically connect to testnet and save chain history. You should be able to join testnet now.

    App features​

    1- You can transfer your earned tokens to your wallet by holding your finger on the Earnings section in the Home Page and paste the address of you wallet by clicking the icon (Please note manually entering is not allowed)

    2- You can format the storage by holding your finger on the Hard Disks section of the Home Page

    3- You can check blox details by clicking on the blox icon in Home page and some other details by clicking on the profile icon on top right

    4- You can see added or existing Bloxes in the network, when you are connected to the same wifi as blox and choose Blox Discovery from Settings tab

    - +

    FxBlox App Setup

    Installing the FxBlox App​

    Initial Setup​

    1. Download the App:
    2. Metamask Wallet: Ensure you have a Metamask wallet for setting up your identity.

    App Configuration Steps​

    info

    If adding more than one FxBlox to your app, get familiar with these instructions first.

    info

    For a successful setup you should either have the Blox with internal storage, or attach an external storage to it.

    warning

    Please make sure to first uninstall (not update) any previous version of FxBlox on your phone and then re-install the latest version

    1. Open Metamask Wallet. We recommend having the opening network set to "Ethereum Mainnet" for a smoother setup process.
    2. Minimize Metamask (not close) and open the FxBlox app.
    3. Read the Terms and Condition and if you agree, then select Agree and Setup Blox in the app.
    4. Enter a memorable password for data encryption and click Sign (Note: This is not your Metamask password).
    5. Complete the connection in the Metamask app, then return to the FxBlox app.
      • You may need to click back to manually return to the app if it does not open Blox automatically after you sign in Metamask
      • It does not matter which chain (Ethereum, Mumbai, etc) you are on in your Metamask wallet.
    6. Tap Connect to new blox.
    7. Manually connect your phone to the "FxBlox" WiFi/Hotspot, and turn off "mobile data", then continue in the app.
    warning

    Everyone should format their storage in step 8. If you have Blox with internal storage, disconnect any external disk. If you have Blox with no internal storage, attach your external storage. At the "set Authorizer" page, wait for 10 seconds and a green button named "Format Disk" appears. click on it and blox turns purple and reboots after a few minutes. You should wait for the light to turn flashing light blue again and then reconnect your phone to FxBlox again to continue the process

    1. Make sure you have attached at least 300GB of external storage to your FxBlox. Proceed by clicking Next once the app recognizes the storage.
      • If the storage is not recognized ensure that is it correctly formatted by clicking on the Format button.
        • The light will turn purple, to indicate it is formatting. Formatting times depend on storage medium and capacity, so be patient during this time. Device will reboot automatically and eventually start flashing light blue again when it is ready to proceed.
      • If you have an FxBlox version with internal storage, there is no need to attach external storage.
    2. Select your desired WiFi network for the FxBlox and enter the password.
      • If you entered the wrong password, double check you're connected to FxBlox Wifi and just go back to the wifi selection screen to choose and re-enter your password.
    3. Finally, on the last screen reconnect your mobile device to your home WiFi and you can turn on the mobile data again if you want to. The app will confirm the successful setup. Please note the app does not continue if you do not have an active internet connection. When Blox is connected to the internet, the LEDs turn green for 30 seconds and then turn off.
    4. We recommend unplugging and replugging the Blox after the initial setup once for a hard reboot and ensuring that everything is set. After you re-plug the power and it boots, it may reboot automatically once as well.

    Troubleshoot​

    • Final step connection issues: Connect to mobile or home wifi, restart the FxBlox app, select Connect to Existing Blox. If that doesn't work, restart the FxBlox device. Close app and reopen to proceed with Connect to new Blox.
    • If Metamask doesn't redirect after signing transaction: Manually go back to the FxBlox app.
    • App issues with Metamask: On some phones, if you cannot get the "Connect" and "sign" prompts in Metamask, you may need to put both the Metamask app and Blox app in Unrestricted mode from the "Battery Optimization". Go to: Settings > Apps > FxBlox > Battery / App Battery > Choose Unrestricted. Do the same for the Metamask app. After the setup, you can return it back to the default of Optimized

    Add Multiple FxBloxes​

    As of Android/iOS app version 1.6.7, there is not an easy way to add more than one blox to your account. Follow these additional steps if you would like to connect more than one blox:

    1. If not already done, complete setup of your first Blox.
    2. Verify Blox is listed as Authorized under Settings->Blox Discovery. If not, restart your Blox by unplug/plug-ing it back in.
    3. Log Out of your account by going to Settings -> Log Out.
    4. Proceed and complete set-up of your next FxBlox.
    5. Repeat steps 2-4 for all the FxBloxes you have, except for the last one.
      info

      If you're using the default naming scheme Blox unit #X, then name your last Blox Blox unit #1. The reason for this is because the app will auto-number the rest of your Bloxes when you add them back in.

    6. When you've finally added the last FxBlox, go to Settings -> Blox Discovery.
    7. All FxBloxes should say Authorized, so select them and click Add selected blox(s).
    8. Verify you can see all of them by going to Blox tab and swiping left/right between them.
    info

    As you can see the functionality is there, but prioritization of an easier way to add them is scheduled for after testnet launch.

    Our apps are open-source and built in React Native for cross-platform support. So if you would like to contribute to the project, that would be greatly appreciated!

    Format Drive​

    If you were eager to test out nightly releases on your own, you may have trouble joining the official launch of the testnet. This is because the blocks from the temporary chains are incompatible with the official testnet blocks. To fix this, you need to erase all previous blocks, easiest way is to format the drive.

    To format your drive:

    1. Tap on the Blox tab to see this screen
    2. Tap and hold the Hard Disk you want to format
    3. When the pop-up shows, click the Format button
    4. Now wait! The light will turn purple. This process may take more or less than 5 minutes, dependent on the speed of your drive.
    5. The FxBlox will auto-reboot, after it is done the lights will turn off.

    FxBlox will automatically connect to testnet and save chain history. You should be able to join testnet now.

    App features​

    1- You can transfer your earned tokens to your wallet by holding your finger on the Earnings section in the Home Page and paste the address of you wallet by clicking the icon (Please note manually entering is not allowed)

    2- You can format the storage by holding your finger on the Hard Disks section of the Home Page

    3- You can check blox details by clicking on the blox icon in Home page and some other details by clicking on the profile icon on top right

    4- You can see added or existing Bloxes in the network, when you are connected to the same wifi as blox and choose Blox Discovery from Settings tab

    + \ No newline at end of file diff --git a/functionyard/fxfotos.html b/functionyard/fxfotos.html index b5b68495..d65bf355 100644 --- a/functionyard/fxfotos.html +++ b/functionyard/fxfotos.html @@ -5,14 +5,14 @@ FxFotos Apps | Functionland - +

    FxFotos Apps

    Use case​

    FxFotos is a decentralized media manager. It automatically syncs up your media files (pictures and videos), and allows you to open and view media files on your phone. It comes with features such as:

    • Thumb scroll to quickly browse earlier dates
    • Pinch to change number of columns
    • Highlights
    • Video and Photos player support for a variety of formats
    • Basic search functionality

    Use FxFotos App​

    1. Install FxFotos from Google Play

    2. Wait for a minute for the loading bar to disappear (This makes the experience smoother and just needed for the first time)

    It is smoother if you open Metamask here before continuing with login
    1. Click on the profile icon on the top right

    2. Click allow notifications

    3. Enter an arbitrary password (This can be the same or different from FxBlox and other dApps). Make sure you do not lose this password as there is no way to retrieve it.

    4. Click Login and complete the signing steps in Metamask. After which you will be redirected back to FxFotos automatically.

    5. After a successful login, you will see relevant information about your account:

    • Your Did: This is your decentralized ID based on your password
    • Your Content Root CID (This is hidden by default): This value is needed in order to retrieve your data on another account. We are working to enhance the protocol side to make this value retrievable but right now if you lose it there is no retrieval method. This value changes after each upload (Private)
    • Your Private Key (This is hidden by default): This value is needed in order to retrieve your data on another account. There is no need to save this as this is automatically being created from the DID (Private)
    • Fula Account: This is the Fula account that the tokens/payments for backing up your data will be deducted from. For testnet initially there is no charge but also no guarantee for hte data you upload (Not private)
    • Your PeerID: This is the peer id that the application uses to connect to other nodes (Not private)
    1. Click on the 'open in new window' icon next to the Fula Account and follow the instructions on the page to join.

    2. Click on Choose a pool for uploads and select a pool close to you. If you make a mistake, you can Clear pool selection and select another pool.

    3. Click back and go to main screen.

    4. To upload/backup a media file, click on it to open, then tap one time on the screen and you see a back up icon shown at the bottom of screen.

    info

    We have deactivated the auto-sync initially during testnet launch to give us better troubleshooting and debugging opportunity. We thank you for your patience.

    How to see my uploaded/backed-up data?​

    We are working on a web interface that shows you the backed up data, but for now there is an unreleased app which you can copy the "Private Key" and "root Cid" From FxFotos over to that application, and it shows you the list of uploaded files. The app does not transfer the keys outside or to any third party and is totally safe. It can be downloaded from here:

    Future Plans​

    1. Completing the browser based application
    2. Sharing with others. You can easily share the uploaded files with others in or outside of Fula network and set expiry date, give write permission, and anything you can do on the cloud. This feature already exists in the protocol and we just need to implement the required interfaces for it.
    3. Integration with AI. We are working on integrating the application with on-device face-detection algorithms.
    4. Easy import from Google/Apple Photos. We implement a feature to easily migrate your files over from other applications.
    - + \ No newline at end of file diff --git a/functionyard/hardware/fxblox-hardware-rk1.html b/functionyard/hardware/fxblox-hardware-rk1.html index 0fe49261..1d640e17 100644 --- a/functionyard/hardware/fxblox-hardware-rk1.html +++ b/functionyard/hardware/fxblox-hardware-rk1.html @@ -5,13 +5,13 @@ FxBlox Lite Plus (RK1) | Functionland - +

    FxBlox Lite Plus (RK1)

    Updating Your FxBlox Lite Plus (RK1)​

    warning

    If you were helping test nightly firmware releases before official testnet launch, you will be required to format drive to clear out old/incompatible chain data. See more details here.

    Step 1: Download the Firmware​

    Step 2: Unzip and Transfer to FAT32 USB​

    info

    Before starting, make sure that your USB stick is 32GB or smaller. Anything larger than 32GB may not work due to the FAT32 file system limitations. Instructions must be done in this order to avoid complications.

    1. Use a USB drive formatted as FAT32.

    2. First, unzip minimal_update.zip onto your computer.

    3. Then, copy unzipped files to USB drive to avoid potential file corruption.

    4. Make sure to copy unzipped files directly to the root of the USB drive. So the files boot.scr, update.img.0, update.img.1 and update.img.2 , etc... must be in the root of your USB disk.

    Step 3: Updating FxBlox​

    1. Ensure your FxBlox is turned off.

    2. Connect the USB drive to the top USB port of the FxBlox. (Only the top port is designed for updates)

    3. Turn on your FxBlox. The LED will display green, blue, and then yellow, indicating the update process.

    4. After about 15 minutes, the LED blinks green and blue. Remove the USB drive.

    5. Restart the FxBlox by unplugging and plugging back the power.

    Step 4: Post-Update​

    Be patient on the first boot, post-update! The FxBlox automatically reboots 3 times, and will go through a series of lights. This full process should take about 30 minutes to fully process the update and show the FxBlox WiFi.

    Leave it plugged in! At any time, you may think it is done or stuck or it is turned off, but be rest assured that it is processing the update. After automatic restarts are done, the FxBlox will proceed to show a variety of colors including: blue, green, cyan, yellow, off, red; in that order. This process make take around 10 minutes until LEDs turn flashing light-blue.

    info

    Future firmware updates will be over the air, eliminating the need for manual updates.

    - + \ No newline at end of file diff --git a/functionyard/hardware/fxblox-hardware-rpi-reimage.html b/functionyard/hardware/fxblox-hardware-rpi-reimage.html index f4e823e5..c2eecbe8 100644 --- a/functionyard/hardware/fxblox-hardware-rpi-reimage.html +++ b/functionyard/hardware/fxblox-hardware-rpi-reimage.html @@ -5,13 +5,13 @@ Re-imaging CM4 | Functionland - +

    Re-imaging CM4

    Re-imaging CM4​

    If for any reason the CM4 fulatower gets stuck in a blue/white light without going through the whole boot process, or it is not connected to the Wi-Fi or propagating the FxBlox hotspot, you need to perform a full re-image. This process requires you to first open the tower, which involves unscrewing parts of it. The process of opening the tower is shown in the video below:

    How to open the tower

    Steps for Re-imaging​

    1. Unplug the Tower from Power

      Ensure the tower is not connected to any power source before proceeding.

    2. Opening the Tower

      Follow the instructions in the video linked above to open the tower safely.

    3. Connect the USB-C Port

      Connect the USB-C port on the side of the tower to your laptop or PC.

      Placeholder for USB-C connection image

    4. Short Circuit the Two Pins

      Short circuit the two pins located on the bottom left side of the Raspberry Pi module. You can use anything to short circuit them, like putting hte head of a USC-C cable between them. but make sure hte material you are using is conductive nad not Aluminum for example (key rings for example are usually aluminum)

      Placeholder for short circuit pins image

    5. Power On the Tower

      Plug the tower back into power. It should display a blue/white light and remain like that, indicating it is in image mode. You can remove the short circuit from step 4 at this stage.

    6. Installing and Running rpiboot

      • For Windows:

        • Download and install rpiboot from here.
        • Type rpiboot in your search bar and run it. After a few seconds it starts printing some stuff and automatically closes after 15 seconds or so. Wait for the terminal to close before proceeding.
      • For Mac:

        git clone --recurse-submodules --shallow-submodules --depth=1 https://github.com/raspberrypi/usbboot
        cd usbboot
        brew install libusb
        brew install pkg-config
        make
        sudo ./rpiboot

        After a few seconds it starts printing some stuff and automatically closes after 15 seconds or so. Wait for the terminal to close before proceeding.

    7. Download the Latest Image

      Download the latest image for your CM4, from the official GitHub repository. Download all the files that start with rpi_cm4_fulimage into one folder on your computer.

    8. Unzip the Image Content

      Right click on the one that ends with .zip.001 and use 7zip application to extract. Extract the contents of the downloaded image to a known location on your computer.

    9. Install and Run Raspberry Pi Imager

      • For Windows: Download from here.
      • For Mac: Download from here.
    10. Configure Raspberry Pi Imager

      Open Raspberry Pi Imager and select the following:

      • Raspberry Pi Device: RASPBERRY PI 4
      • Operating System: Scroll down and choose "custom image," then select the .img file inside the folder you unzipped in the previous step.
      • Storage: Click on "Choose storage" and select the newly added storage, which should be around 30GB and named RPi-Msd.

      Placeholder for Raspberry Pi Imager configuration image

    11. Start the Imaging Process

      Click "Next." Choose "No" for the first popup asking if you want custom configs, and "Yes" for the second one asking for confirmation.

    12. Wait for Completion

      The imaging process might take about 3 hours. Please be patient.

    13. Final Steps

      After completion, remove the short circuit from the pins, disconnect the USB-C cable connecting the tower to the computer, and then unplug and re-plug the tower to power.

    14. Set Up Using FxBlox App

      Now that you have the updated fulatower, use the FxBlox app to set it up. There's no need for any other manual updates.

    15. Closing the Tower

      Once you've confirmed a successful setup through the FxBlox app, close up the tower again to protect it from damage.

    • If at the end of setup, you see a message that the app could not connect to Blox, Close the app, unplug and re-plug the blox and wait for 1 minute and open the app.
    - + \ No newline at end of file diff --git a/functionyard/hardware/fxblox-hardware-rpi.html b/functionyard/hardware/fxblox-hardware-rpi.html index 02b5802e..5ae53d35 100644 --- a/functionyard/hardware/fxblox-hardware-rpi.html +++ b/functionyard/hardware/fxblox-hardware-rpi.html @@ -5,7 +5,7 @@ FxBlox Lite (CM4) | Functionland - + @@ -13,7 +13,7 @@

    FxBlox Lite (CM4)

    Updating Your FxBlox Lite (RPI)​

    warning

    If you were helping test nightly firmware releases before official testnet launch, you will be required to format drive to clear out old/incompatible chain data. See more details here.

    Step 1: Download the firmware​

    info

    If this is your very first time setting up your FxBlox Lite, see these instructions first

    • Download: Find rpi_cm4_usb_update.zip files in the latest release under the Assets section on GitHub, and download all files that start with rpi_cm4_usb_update.

    • Download: You need 7zip to unzip the downloaded chunked zip files. You can download it from their website here, and then right click on the file that ends with .zip.001 and choose 7zip > extract

    • Download: Download Win32 Disk Imager for writing update firmware to USB. https://win32diskimager.org/

    Step 2: Unzip and Write image to USB​

    1. Unzipping: Unzip rpi_update.zip on your computer. After unzipping there must be a .img file.

    2. Writing Image to USB:

      • In Image File section select rpi_update.img file.
      • In Device section select USB Disk Partion letter.
      • Click Write to start flashing USB Disk.

      Win32 Disk Imager

    Step 3: Updating FxBlox​

    1. Turn Off: Ensure your FxBlox (RPI) Lite is turned off.
    2. USB Connection: Connect the USB drive to the BOTTOM USB port of the FxBlox Lite (RPI).
    3. Power On: Turn on your FxBlox Lite (RPI). After about 30 sec, the LED will blink yellow 5 times that indicating the update process started.
      warning

      In update process the LED blinks red and green. This phase is very critical, and any mistake in this phase cause breaking FxBlox Lite (RPI).

    4. After about 10 minutes, the LED blinks red only. Remove the USB drive.
    5. Restart the FxBlox Lite (RPI) by unplugging and plugging back the power (Make sure an external storage, without the img files, is plugged to the bottom port of blox before powering it back on or the sequence of lighting you would see might defer from this documentation). The best partitioning format for storage devices is ext4 but vfat is also acceptable.

    Note If the blox stays in blue/white color, or does not connect to wifi and neither shows FxBlox hotspot or you rebooted during the update and think it is broken, you need to do a full re-image by following the instructions here.

    Step 4: Post-Update​

    1. Ensure your FxBlox is turned off.
    2. Connect the external storage USB drive (not needed if you have internal) to the bottom USB port of the FxBlox.
    3. Turn on your FxBlox. After automatic restarts are done, the FxBlox will proceed to show a variety of colors including: blue, green, cyan, yellow, off, red; in that order. This process make take around 10 minutes until LEDs turn flashing light-blue

    Please wait for 10-15 minutes before doing anything. You may think it is done or stuck or it is turned off, but be sure that it is processing the update for 10-15 minutes after the first boot. At the end of process the LED starts blinking light blue (cyan) consistently if an external storage is plugged to the blox or it has internal storage (XL orders). If no external storage is plugged, then you cannot see this sequence until you plug one.

    Use FxBlox App: AFter the lights become a flashing blue, you can start setting up the Blox with the application. Follow on-screen instructions in the app. Please make sure follow instructions as detailed in the documentation

    • If at the end of setup through the FxBlox app, you see a message that the app could not connect to Blox, Close the app, unplug and re-plug the blox and wait for 1 minute and open the app.
    info

    Future firmware updates will be automatic, eliminating the need for manual updates.

    First Time Setup​

    If this is your very first time setting up your FxBlox Lite (RPI), you will not be able to install the latest usb update. The reason for that is because "updating via usb" feature was not added in until a later firmware version.

    To automatically get that version, you need to connect the Blox to the wifi first. You can do so by following these steps:

    1. Download the latest iOS/Android app.
    2. Follow prompts to create password and connect Metamask.
    3. On the authorize blox screen wait for 15 seconds and a "skip" button appears in the bottom left. click that to skip the authorization and then click yes to confirm. *
    4. Connect Blox to wifi. *
    5. Now, wait 24 hours for the update to install. *
    6. With new version installed, you can proceed with the normal upgrading process.

    Troubleshoot​

    • You may need to wait somewhere between 20-30 seconds for the button to appear.
    • You may not get a setup complete message after connecting to wifi, because you don't have the latest firmware version. Check your router settings to see if it connected properly.
    • We recommend waiting 24 hours, because there are no indicators for when it is completed.
    • If the blox stays in blue/white color for a long time after reboot, or does not connect to wifi and neither shows FxBlox hotspot or you rebooted during hte update and think it is broken, you need to do a full re-image by following the instructions here
    - + \ No newline at end of file diff --git a/functionyard/hardware/fxblox-hardware.html b/functionyard/hardware/fxblox-hardware.html index ced8e524..aa33b035 100644 --- a/functionyard/hardware/fxblox-hardware.html +++ b/functionyard/hardware/fxblox-hardware.html @@ -5,13 +5,13 @@ FxBlox Hardware | Functionland - +

    FxBlox Hardware

    The Difference Between Lite and Lite Plus​

    The two models look identical from the outside

    It is important to know which Blox you have. The manual firmware update process varies between the two and their steps need to be followed exactly as shown!

    The FxBlox Lite has a CPU from Raspberry Pi and it is alternatively known as the CM4. Only about 100 of these were distributed during the Indiegogo delivery phase. You would have had to fill in a form to specifically opt-in to receive this FxBlox. Other than that there are two key ways to tell if you have this model.
    1. Check the barcode. On the side of the original box that the device came in. It should look like this.
    2. Open up the device. You can do this by removing the four black screws of the three-port USB housing, then the four silver screws on the bottom of the Blox. You will be able to slide out the board and see this device.
      • Front
      • Back
    - + \ No newline at end of file diff --git a/functionyard/join.html b/functionyard/join.html index 137f7f47..a850ff24 100644 --- a/functionyard/join.html +++ b/functionyard/join.html @@ -5,13 +5,13 @@ Joining Testnet | Functionland - +

    Joining Testnet

    Joining the Testnet​

    1. In the FxBlox App, go to the Users Page and click Join Testnet
    • Or you can manually visit the testnet page at Functionyard Testnet and enter your Indiegogo campaign order details and account id from the Blox app.
    • If the Account and Join buttons are greyed out, it means the blox is still syncing the chain data. You can check the progress of sync in the Settings -> Pools page.
    info

    If after the sync is over you get any errors, you can tap on the tower icon in the home page and click "Reset Chain Data"

    1. In the FxBlox app, go to Settings > Pools. Join a pool nearest to your city. Choose the one closest to you from the list. Please note, that if you choose a pool that is far from you, the request will automatically rejected by the system.
    1. Wait for approval from 5 pool members (may take up to 2 hours right now).
    1. Once approved, the pool button changes to "Leave". You can now start storing and earning. You should start using FxFotos app to maximize earnings.

    Add Multiple FxBloxes​

    info

    If you do not already have all Bloxes added in your app, then checkout this guide on how to add them.

    Every FxBlox is not automatically enrolled in the testnet. The Blox that is showing in the Blox tab, is the "Active" Blox which populates the rest of the settings. There are two scenarios that you may fall under.

    Bought during Indiegogo campaign​

    To add any extra Bloxes to the testnet, you need to:

    1. Make sure you have already followed the steps above to add your first Blox to the testnet.
    2. Swipe left/right to display the next Blox you want to add.
    3. Go to Settings -> Pool, select the testnet pool closest to you.
    4. Repeat steps 2-3 for any following Blox.

    Bought Blox outside of campaign​

    If you bought a Blox from the available units on the shop.fx.land or a second-hand resellers site. Then you will need to send a message to sales@fx.land to have your Blox Account ID added to testnet backend. You Blox Account ID is shown under the User Tab after completing setup.

    After this has been completed, you will have to wait a couple hours for the testnet to sync and then you will be able to join.

    - + \ No newline at end of file diff --git a/functionyard/metamask.html b/functionyard/metamask.html index 1a97af05..e8b58def 100644 --- a/functionyard/metamask.html +++ b/functionyard/metamask.html @@ -5,13 +5,13 @@ Token in Metamask | Functionland - +

    Token in Metamask

    Adding BORG Token to MetaMask on Mumbai Chain​

    This guide explains how to add the BORG token, which is not automatically listed in MetaMask, to your wallet on the Mumbai test network. There is an easy way and a manual way!

    Easy Way (Desktop)​

    1. Adding Mumbai Network to Metamask: First, open this link to add Mumbai testnet to your MetaMask. Now click on the Add to Metamask button. It will open your Metamask extension on Chrome and add Mumbai Network to it (if not already added).

    mumbai connect button

    1. Adding the BORG token on Mumbai: First, open this link to add Borg to Mumbai network and on the bottom right (you may need to scroll), click on the Send Request button. It opens your Metamask extension on Chrome and adds the BORG token to the Mumbai network (if not already added).

    Easy Way (Mobile)​

    In Metamask mobile, you have to be using the browser that is available in the MetaMask app for the sites to recognize your Metamask wallet.

    1. Copy/Paste https://chainlist.org/chain/80001 into the Metamask web browser.
    2. Click on Connect Wallet under where it says Mumbai. Confirm popup.
    3. Copy/Paste, into a new tab of the Metamask web browser, https://docs.metamask.io/wallet/reference/wallet_watchasset/?type=ERC20&options[address]=0x99a8b2B50c4bFBf916Add5DFdf680fc873FA81f4&options[symbol]=BORG&options[decimals]=18&options[image]=https://raw.githubusercontent.com/functionland/sugarfunge-explorer/master/assets/BORG.svg&options[tokenId]=BORG.
    4. Scroll all the way down to the Send Request button. Confirm popup.

    Manual Way (Mobile/Desktop)​

    Step 1: Select the Mumbai Network in MetaMask​

    Ensure you have MetaMask installed and select the Mumbai Testnet. If Mumbai is not listed:

    1. Select "Add Network" manually.

      • Mobile: First, click on circled button. Then, Add Network

      • Desktop: First, click on circled button. Then, Add Network

      • Alternatively, you can go to Settings -> Networks -> Add network, then Custom Networks or Add a network manually.

    2. Enter the following details:

      • Network Name: Mumbai Testnet
      • New RPC URL: https://rpc-mumbai.maticvigil.com/
      • Chain ID: 80001
      • Currency Symbol: MATIC
      • Block Explorer URL: https://polygonscan.com/

    Step 2: Add BORG Token​

    1. Open the MetaMask extension
    2. Go to the Assets or Tokens tab
    3. Scroll down and click Import Tokens
    4. Switch to the Custom Token tab
    5. Enter the BORG Token Contract Address: 0x99a8b2B50c4bFBf916Add5DFdf680fc873FA81f4
      • The token symbol and decimals should auto-fill. If not, you may need to enter them manually.
    6. Click Add Custom Token
    7. Review the token details and click Import Tokens

    Congratulations, the BORG token is now added to your MetaMask wallet on the Mumbai chain!

    Troubleshoot​

    1. BORG token no longer shows in Metamask wallet. This may be because the Mumbai chain rpc provider is unavailable. You can remedy this by redoing the steps outlined in this guide (easy way or manual way).
    2. Error when adding Mumbai chain. This may occur because the Mumbai chain rpc provider is unavailable, if you are selecting a provider from the list, make sure that it has a green check mark for both Score and Privacy. This will most likely occur when doing the manual way.

    mumbai chain options

    - + \ No newline at end of file diff --git a/functionyard/support.html b/functionyard/support.html index 54597387..7d67b770 100644 --- a/functionyard/support.html +++ b/functionyard/support.html @@ -5,13 +5,13 @@ Support | Functionland - +

    Support

    How to request support​

    No matter what happens we are here to support you as a valued member of Fula network. However, to allow us spend time on development, please first make sure you follow the instructions carefully. I understand reading the documentations can be a boring chore, but that would save your valuable time from troubleshooting.

    • In case you still need support please post your question on our support portal
    • You can also get the support from community by posting in our telegram group, however, support from the team will only be provided on the support portal.

    To ensure we can support everyone, please do not DM or email the individuals in Functionland. We appreciate your cooperation.

    - + \ No newline at end of file diff --git a/getting-started.html b/getting-started.html index 0f97f62b..4dc84856 100644 --- a/getting-started.html +++ b/getting-started.html @@ -5,13 +5,13 @@ Getting Started | Functionland - +

    Getting Started

    In order to start developing your own DApps on Fula, complete these two steps:

    1. Get the Box server up and running.

    2. Develop your own front-end, leveraging the Fula API.

    - + \ No newline at end of file diff --git a/getting-started/box-setup.html b/getting-started/box-setup.html index ec5c8abb..b678fbe5 100644 --- a/getting-started/box-setup.html +++ b/getting-started/box-setup.html @@ -5,13 +5,13 @@ Running a Box locally | Functionland - +

    Running a Box locally

    The easiest way to get your Box server running locally is to clone our repo and use docker.

      > git clone https://github.com/functionland/fula
    > docker-compose -f docker-compose.dev.yaml up

    Next, take note of the PeerID the Box server creates on startup. You can find this by taking a look at your docker-compose logs for the following -

    box_1             | Swarm listening on /dns4/wrtc-star1.par.dwebops.pub/tcp/443/wss/p2p-webrtc-star/p2p/12D3KooWPeEhynWyG7dHytppDP6ZG6jhEv7LcDLWsExGq1YD784E

    Now head over to using the samples to verify that the Box server is running properly and you are able to connect to it.

    - + \ No newline at end of file diff --git a/getting-started/fula-client.html b/getting-started/fula-client.html index 36688bcf..7b01c027 100644 --- a/getting-started/fula-client.html +++ b/getting-started/fula-client.html @@ -5,13 +5,13 @@ The Fula Client Library | Functionland - +

    The Fula Client Library

    Fula client lets you connect your web application to the Box using libp2p. It helps DApp developers to use a Box as the back-end for their applications. You can use the File and Graph APIs to store and retrieve your data.

    Installation​

    The Fula client is available in javascript, and it can be installed like any other NPM package:

    npm i @functionland/fula

    Alternatively, you can use the CDN version:

    <script src="https://cdn.jsdelivr.net/npm/@functionland/fula/dist/index.js"></script>

    Usage​

    Once you've imported the package in your project, in order to connect to your Box you should create a client:

    import {createClient} from '@functionland/fula'

    const fulaClient = await createClient();

    Now that you have a Fula client instance, you can connect it to the Box server. You must have the base58 PeerID string provided by your Box server.

    await fulaClient.connect(serverId)

    Helper Libraries​

    In addition to the Fula client library you might also find one of our framework helpers useful.

    We currently support:

    What Next?​

    Now that you are up and running, head on over to the Fula Reference API to see everything you can do with Box.

    WIP Alert

    Please note: these instructions remain a work in progress as we continue to evolve, refine and perfect the Fula API. Make sure to check back soon for more details!

    - + \ No newline at end of file diff --git a/getting-started/rpi-setup.html b/getting-started/rpi-setup.html index 7612aca9..46854bc5 100644 --- a/getting-started/rpi-setup.html +++ b/getting-started/rpi-setup.html @@ -5,13 +5,13 @@ Installing Box on Raspberry Pi OS | Functionland - +

    Installing Box on Raspberry Pi OS

    WIP Alert

    Please note: these instructions remain a work in progress as we continue to evolve, refine and perfect the Fula API. Make sure to check back soon for more details!

    Pre-requisites​

    It is assumed you have taken the necessary steps to appropriately secure the linux environment before installing the Box software.

    For example, you should change the default pi user password if starting from the current release of raspberry Pi OS.

    You might also create a different user with root priviledges and remove ssh / sudo access for the pi user.

    This guide was written using Debian GNU/Linux 11 (bullseye) on a Raspberry Pi 4.

    Setup Steps​

    1. Install git to clone the FULA repo.
      > sudo apt update
    > sudo apt install git
    1. Install docker and docker-compose according to your linux distro. If you get an error during the install process see troubleshooting below.

    2. Create a non-sudo user for the Box server app and other dependencies to run under and add them to the docker group.

      > sudo adduser -m fuman
    > sudo passwd fuman
    > sudo usermod -a -G docker fuman

    Log in as 'fuman' in a new shell

      > ssh fuman@yourhost
    1. Run docker in rootless mode.

    2. Start Box and it's dependencies.

      > git clone https://github.com/functionland/fula
    > docker-compose -f docker-compose.dev.yaml up
    1. Verify you are able to connect to the Box on the rPi from a sample DApp. The most straightforward way to do that is to follow the regular 'getting-started' process. On the step to connect to a Box just enter the PeerId of the Box running on your rPi instead of the one that is running on your local dev. machine.

    Troubleshooting​

    Ensure the there is a directory matching kernel version in /lib/modules

    - + \ No newline at end of file diff --git a/getting-started/using-samples.html b/getting-started/using-samples.html index 14227ef2..b8b41211 100644 --- a/getting-started/using-samples.html +++ b/getting-started/using-samples.html @@ -5,13 +5,13 @@ Using Fula Samples | Functionland - +

    Using the Fula Samples

    All the Fula samples can be found in the Fula GitHub repo under examples.

    To get things started and give you an idea of how to work with the Graph API, we will set up the TODO Sample App.

    Running the TODO Sample​

    If you followed the previous step, it should already be running. All you have to do is navigate to http://localhost:3001 in a browser.

    There you should see the following dialog:

    Todo Connect Prompt

    Todo Connect Prompt

    Connect to the Box​

    Copy the PeerId from the Box server logs available in the previous step and paste it into the text input.

    After clicking 'Connect'...

    The app should redirect you to the TODOs app.

    Todo App

    Todo App

    Editing the Sample​

    Open /path/to/fula/examples/react-todo-app/src/components/TodoList.tsx in your favorite editor.

    Change the headline from -

    <h1>Functionland Todo App</h1>

    to -

    <h1>My Todo App</h1>

    You should now see the change reflected in your browser.

    Congrats! Your Box server is now up and running, and you've verified you can connect to it. You have also learned how to update one of the samples so that you can use it as a starting point for your own DApp.

    Now that you are up and running, head on over to the Fula Reference API to see everything you can accomplish with Box.

    - + \ No newline at end of file diff --git a/index.html b/index.html index f8a5eab0..18e187db 100644 --- a/index.html +++ b/index.html @@ -5,13 +5,13 @@ Welcome | Functionland - +

    Welcome to Functionland

    Functionland was founded on a core set of Web3 principles. At the heart of these principles is a simple premise: We each have an inalienable right to own our own data.

    We set out to build a better future around this simple premise. We started by developing an app that liberates a set of "own data" we think is particularly important to people: personal home photos and video.

    We developed Fotos as a Web3 alternative to available photo and video sharing and backup applications.

    But while developing Fotos, we realized there are still many pieces missing from the Web3 stack; pieces that are necessary to achieving the better future we envision.

    What We Realized​

    With big tech cloud companies having unfettered access to our data, we needed to created a system that will:

    1. Never lose access to our photos, video, and other personal data, for as long as we choose.
    2. Give access to information to anyone in the world without regard for who they are.
    3. Enable any developer to easily build and get paid for their products and services.

    Which is when we realized, there was no single chain agnostic token we can use to incentivize people to offer up both their storage and computer power for blockchain products and services.

    Enter $FULA token​

    $FULA will be the catalyst for keeping the infrastructure online at all times and getting users to store their photos and video, for as long as they want. Storage providing and compute providers are two sides of the same coin. Providers require payment for offering their service to the public. And consumers need a corresponding way to pay for said services.

    Enter BAS​

    We created the first uniform Blockchain Attached Storage (BAS) device! As a provider, you can use your storage device(s) to completely own your data and gain rewards for offering up your extra storage to the public. And as a consumer, can pay-as-you-go! It'll be like you have access to infinite storage and just pay for what you need to keep your data alive for as long as you like.

    Enter FxBlox​

    FxBlox, or Blox, is the brand-new hardware that is empowering it all. Beautiful design, power-efficient board, and next-gen processing is not gate-kept by inflated pricing. Bloxes are competitively priced and offer the lowest barrier to entry in any decentralized storage blockchain. Our network has the potential to vertically and horizontally scale faster than any protocol before.

    Enter Fula API​

    To enable any developer to build apps and services on this brand new protocol, we introduce the Fula API. An open, interoperable specifications that enables developers to write permissionless, decentralized apps for consumers and to get paid for their work.

    Fula Network​

    All together we get the Fula Network. This network has power in numbers, it is for the people, and will create a new internet that fixes the security and other fundamental problems with the internet of today.

    - + \ No newline at end of file diff --git a/introduction/bas.html b/introduction/bas.html index e2f923dc..d70ce42e 100644 --- a/introduction/bas.html +++ b/introduction/bas.html @@ -5,13 +5,13 @@ Blockchain Attached Storage | Functionland - +

    Blockchain Attached Storage

    You've heard of a network attached storage (NAS), but you haven't heard of a blockchain attached storage (BAS).

    There is currently no modular, open-source, datacenter-grade server hardware option available. Hardware that is fully customizable and aesthetically appealing enough to sit comfortably in your home.

    Which is why we are creating just that!

    Blox to BAS​

    The mission behind creating the Blox is to disrupt the centralized cloud storage status-quo. To do this, we need to create a truly people-owned internet. The idea is, get uniform hardware into the hands of the people to ease early development processes and enable users to upload photos and videos to the chain of devices.

    Blox owners are incentivized to always stay online and not act maliciously thanks to the blockchain mechanisms in place. Even if an owner were to delete user's files from their Blox, that user's files would still be safe because they would have already been replicated to multiple other Bloxes in geographically different locations.

    BAS for Web2​

    We aim to offer a cloud service that will enable FxBlox owners and non-owners to use decentralized cloud storage just as easily as with big cloud companies.

    Each individual FxBlox owner will be able to help provide storage to the network by adding more as they scale. And we will be able to horizontally scale, by getting the FxBlox into the hands of more people. Together we will be able to grow into a truly people-owned internet!

    For non-technical people who want to join the movement by providing storage, we make it easy to set up your device with a simple app.

    For everyday people who want to take advantage of the low-cost decentralized storage, we created two apps that people can use to upload their photos, videos, and files!

    Open Source Everything​

    We want every step of this product to be as open and adoptable as possible. That is why we use all open source technology for hardware design, APIs to add content to network, inter-Blox communications, and of course blockchain.

    To enable this infrastructure, we utilize IPFS for data transfer, data replication, and security in immutability.

    We layer WNFS on top to enable encryption over IPFS, public and private file sharing, as well as decentralized authentication and identity.

    We are a layer two blockchain utilizing the Polygon and Ethereum networks.

    - + \ No newline at end of file diff --git a/introduction/blox.html b/introduction/blox.html index bc925091..79bed51d 100644 --- a/introduction/blox.html +++ b/introduction/blox.html @@ -5,13 +5,13 @@ Blox as a Service | Functionland - +

    Blox as a Service

    What we are missing in the web2 (and web3) space is a freemium option for consumers to compute on and store larger sets of data.

    Web2 companies offer you free limited-storage when you make an account with them. In our case, Bloxes will empower that decentralized storage network and offer paid services for more premium features. It is our goal to be as open and for-the-people as possible.

    Blox Hardware​

    ARM-based single board computers (SBCs) have grown in popularity and performance. They consume a fraction of the energy that typical home NAS servers do and perform just as good. We have two models currently in user's hands, the FxBlox Lite and FxBlox Lite Plus.

    FxBlox LiteFxBlox Lite Plus
    Unavailable$400
    Raspberry Pi CM4Rockchip RK3588
    8GB RAM8/32GB RAM
    16GB EMMC16GB EMMC
    3 Modular I/O Ports3 Modular I/O Ports
    NVMe supportNVMe support
    Dual 4KDual 4K
    Wifi 6Wifi 6

    As the name implies, the Plus model is a more powerful unit, which is a direct result of the upgraded CPU, the Rockchip RK3588!

    As for storage, the FxBlox is compatible with most storage types via usb-c cable or adapter. It also has a single slot for an internal M.2 NVMe drive.

    Decentralized Storage​

    Our very first mission has been to offer decentralized cloud storage for the masses. It comes from our Founders' desire to store photo and video in a more friendly way outside of centralized cloud storage solutions. We have already been making large strides towards realizing this goal.

    Official testnet launch of the Fula network is set for first week of April 2024. And mainnet is scheduled for end of year 2024.

    Decentralized Compute​

    Offering storage for the masses is achievable with the use of apps and webpages, but our FxBloxes are powerful, efficient server-ready devices. Decentralized computation goes deeper than that, offering you the ability to train LLMs on the FxBloxes neural computer units. You could operate a network of Oracles for on-chain events. Or run real-world scientific physics models with the dedicated GPU.

    With FxBlox XLs, owners will not just have upgraded CPUs and I/O, but also Thunderbolt support for external graphics cards.

    The FxBlox will create the backbone for the Fula network where both decentralized storage and computation will be accessible to anyone who wants to join.

    - + \ No newline at end of file diff --git a/introduction/contribute.html b/introduction/contribute.html index c5a0d0bb..1cb57764 100644 --- a/introduction/contribute.html +++ b/introduction/contribute.html @@ -5,13 +5,13 @@ How to Contribute | Functionland - +

    How to Contribute

    Thank you for your interest in contributing to our open source repositories on GitHub! Your contributions help us improve the services and make everyone's experience even better. Here's how you can get involved:

    Hold Discussions​

    The Discussion tab on the Functionland GitHub page can be used for general questions, feedback, raising bugs/feature requests, or discussions related to our projects. Feel free to engage with other community members and share your ideas or suggestions.

    discussions tab on github

    Submit an issue​

    If you encounter a bug, have a feature request, or come across an explicit error, please submit an issue to the appropriate repository. Follow these guidelines for formatting the subject line:

    • For bugs: [BUG] - subject line
    • For feature requests: [Feature Request] - subject line
    • For explicit errors: [Error] - error message

    Make sure to include which device you have (Lite or Lite Plus), app version number, what happened leading up to the issue, and the symptom you are experiencing. You can find logs under Settings -> Blox logs, please submit Go-Fula and Node logs if you can or applicable.

    You can also follow the templates in Github to know what information to include in your post.

    Submit a pull request (PR)​

    We welcome contributions from the community! If you'd like to fix a bug, add a feature, or improve documentation, please submit a pull request. Make sure to follow our contribution guidelines and include a clear description of the changes you've made.

    You can also follow the templates in Github to know what information to include in your post.

    Choose the right repository​

    When deciding where to submit your issue or PR, consider where you encountered the problem or want to make a change:

    Please ensure that you submit your contribution to the appropriate repository based on where you experienced the issue or want to make a change. If you are unsure which repository to raise the concern in, start a Discussion thread so we can narrow down the problem!

    Contribute to Fula docs​

    Technical writers of any level are greatly appreciated. If you are considering contributing to the documentation, please take a look at our Styling and Writing guides to learn more about our writing styles.

    Thank you for contributing to our projects and helping us build better software together!

    - + \ No newline at end of file diff --git a/introduction/contribute/contribution-tutorial.html b/introduction/contribute/contribution-tutorial.html index 03f75d5b..4d460e1b 100644 --- a/introduction/contribute/contribution-tutorial.html +++ b/introduction/contribute/contribution-tutorial.html @@ -5,13 +5,13 @@ Contribution Tutorial | Functionland - +

    Contribution Tutorial

    This style guide is adapted from IPFS's "Contribution Tutorial" article.

    While the grammar, formatting, and style and the writing guide can both help you write good content for the Fula docs, they don't delve into how you can submit your content changes. This guide will walk you through finding an issue, fixing it, and then submitting your fix to functionland/docs.

    There are plenty of small-sized issues around IPFS documentation that make for easy, helpful contributions to the Fula net project. Here, we'll walk through:

    1. Finding an issue.
    2. Discussing the issue.
    3. Creating a fix.
    4. Submitting a pull request.
    5. Waiting for a review.
    6. Merging your fix.

    This may look like a lot of steps for a small issue fix, but they're all necessary to make sure we keep the docs in this project up to standard. Plus, you're not on your own β€” half these steps can be completed by Fula staff!

    Finding an issue​

    The Fula net project is hosted in GitHub. There's a bunch of reasons for this, one of them being that GitHub comes with an issue tracker, which enables the core Fula team to field problems from the community. All community issues can read the docs, find issues, and raise issues in the docs repository (called a repo for short).

    All issues involving the Fula docs themselves can be found in the functionland/docs repo under the Issues tab. Here you can see all the issues that are currently open. We try to tag each issue with relevant descriptive tags. Tags like difficulty and size can give a sense of the amount of effort a task will take to complete.

    Let's jump into finding an issue.

    1. Go to the Functionland repository at github.com/functionland/docs.
    2. Select the Issues tab.
    3. Click the Label dropdown and select the help wanted tag.
    4. Select an issue that interests you.

    Make a note of the issue number and keep it handy for later.

    Discussing the issue​

    As you can probably tell from the available tags, there are lots of different types of issues. Some are tiny one-sentence changes, and others are sizable projects that require a rewrite of several pages. For small issues, there may be very little or no discussion. There's no need to waste everybody's time talking about changing a broken link. But more significant issues will likely need input from different members of the project.

    When adding to a discussion, remember that it may take days or weeks to conclude an issue. With this in mind, try to include all the relevant information anyone might need within each message.

    Let's add to the discussion of the issue you've chosen:

    1. Read through all the previous posts to get up to speed on the issue.
    2. Add any comments you feel are necessary.
    3. If you still want to tackle this issue, post a message saying that you'd like to take ownership of it.

    Once you've claimed ownership of an issue, a member of the core Fula team will assign you to it. If this is a large issue, someone from the Fula team will check in with you from time to time and make sure you've got everything you need to progress with the issue.

    Creating a fix​

    If you've got this far, then you should have an issue in hand and a basic idea of how to fix it. Next up is implementing your fix! The process goes something like this:

    1. Create a fork.
    2. Make changes locally on your machine.
    3. Push your changes.

    If you're not familiar with Git and GitHub, then the phrase fork might not mean much to you. Essentially, a fork of a project is your own personal copy of that project. You can make as many changes to this copy whenever you want because you own it. The idea is that you can modify this personal copy and send your changes to the project team, who can then review all the work you've done.

    The process for creating a fork of an existing piece of Fula documentation is incredibly simple:

    1. Go to the functionland/docs repository in GitHub.

    2. Select Fork to create a copy of the project.

    3. Clone your copy of the project down to your local machine:

      git clone https://github.com/YOUR_USERNAME/docs.git
    4. Make your changes locally.

    5. Once all your changes are complete, make sure to push everything back to GitHub:

      git add .
      git commit -m "Fixed a broken URL, issue #123."
      git push

    When adding a commit comment that actively fixes an issue within the project, try to summarize the fix in a few words and quote the issue number. Following this convention makes it easier for other people to quickly see what you've done.

    Create a pull request​

    Once you're done making commits and are ready to get a core team member's review of your work, it's time to create a pull request.

    1. Go to the functionland/docs repository on GitHub.
    2. Select the Pull requests tab.
    3. Click New pull request.
    4. Click compare across forks and select your repository from the head repository dropdown.
    5. Leave a comment to expand upon your changes.
    6. Click Create pull request.

    GitHub will check if your changes create any merge conflicts with the branch you are trying to merge into.

    Waiting for a review​

    Before your changes can be merged into the project, they have to pass a review. functionland/docs has automatic tests that run against a pull request. These tests must pass before the changes can be merged into the project. If they fail, you will see a red x on the last commit. If you have email preferences turned on, you would also receive an email of the result.

    Depending on the size of the pull request, this could take anywhere from a few minutes to a few days to review everything. Depending on the complexity of the pull request, there may be further discussion regarding your changes. Keep returning to GitHub and checking your notifications page to make sure you don't miss anything.

    Merge your fix​

    Once your pull request has been approved, it's ready to be merged into the project! Only project members with the correct rights can merge changes into the project, but you'll be notified as soon as the merge is complete.

    Finishing up​

    So there you have it! You've successfully completed your first contribution to the Fula documentation. We're always on the lookout for great writers and educators to help us improve the Fula docs and make the internet better for everyone, so keep up the good work!

    - + \ No newline at end of file diff --git a/introduction/contribute/styling.html b/introduction/contribute/styling.html index f673c5c5..93a9ddc2 100644 --- a/introduction/contribute/styling.html +++ b/introduction/contribute/styling.html @@ -5,13 +5,13 @@ Style Guide | Functionland - +

    Style Guide

    This style guide is adapted from IPFS's "Grammer, formatting, and style" rules.

    This page details the syntax and formatting rules for writing Fula documentation. For more conceptual ideas of writing, check out the writing guide.

    Grammar and spelling​

    Here are some language-specific rules that the Fula documentation follows. If you use a writing service like Grammarly, most of these rules are turned on by default.

    American English​

    While Fula is a global project, the fact is that American English is the most commonly used style of English used today. With that in mind, when writing content for the Fula project, use American English spelling. The basic rules for converting other styles of English into American English are:

    1. Swap the s for a z in words like categorize and pluralize.
    2. Remove the u from words like color and honor.
    3. Swap tre for ter in words like center.

    The Oxford comma​

    Follow each list of three or more items with a comma ,:

    UseDon't use
    One, two, three, and four.One, two, three and four.
    Henry, Elizabeth, and George.Henry, Elizabeth and George.

    Acronyms​

    If you have to use an acronym, spell the full phrase first and include the acronym in parentheses () the first time it is used in each document.

    Example: Virtual Machine (VM), Decentralized Web (DWeb).

    Differentiation between token and network​

    Capitalization is required when referring to the $FULA token, but not required when referring to the Fula network.

    Example:

    $FULA is going to the moon!

    I uploaded my files to the Fula net to save my files to the decentralized cloud.

    Formatting​

    How the Markdown syntax looks, and code formatting rules to follow.

    Syntax​

    The Fula Docs project follows the GitHub Flavored Markdown syntax for markdown. This way, all articles display properly within GitHub itself. This gives readers the option to view articles on the docs website or its GitHub repo.

    Relative links in Docusaurus can be created using a pages' ID tag, or their file name. If you include internal (relative) links to other content on the Fula docs site, please link to them using full relative paths (e.g. use ../ for climbing a directory) and specifying the file's full name (e.g. awesome-tutorial.md#subheading). This ensures that users who read docs content directly in-repo on GitHub's web UI are able to follow relative links correctly.

    Rules​

    We use the rules set out in the VSCode Markdownlint extension. You can import these rules into any text editor like Vim or Sublime. All rules are listed within the Markdownlint repository.

    We highly recommend installing VSCode with the Markdownlint extension to help with your writing. The extension shows warnings within your markdown whenever your copy doesn't conform to a rule.

    Style​

    The following rules explain how we organize and structure our writing. The rules outlined here are in addition to the rules found within the Markdownlinter extension.

    Text​

    The following rules apply to editing and styling text.

    Titles​

    1. All titles follow sentence structure. Only names and places are capitalized, along with the first letter of the title. All other letters are lowercase:

      ## This is a title

      ### Only capitalize names and places

      #### The capital city of France is Paris
    2. Every article starts with a front-matter title and id:

      ---
      title: Example article
      id: arbitrary-id
      ---

      ## This is a subtitle

      Example body text.

      In the above example, title: serves as a <h1> or # tag. There is only ever one title of this level in each article.

    3. Titles do not contain punctuation. If you have a question within your title, rephrase it as a statement:

      <!-- This title is wrong. -->

      ## What is Fula net?

      <!-- This title is better. -->

      ## Fula net explained

    Back ticks​

    Back ticks `` are used to highlight keywords. For example, when the reader must interact with something displayed in an app for example: buttons, hyperlinks, images with text in them, window names, icons, or needs directions.

    To `Log Out` first go to `Home`->`Settings`->`Log Out`.

    In the `Login` window, enter your email into the `Username` field and click `Sign in`.

    Italics​

    Underscores _ are used to define italic text. Style the names of things in italics, except input fields or buttons:

    Here are some American things:

    - The _Spirit of St Louis_.
    - The _White House_.
    - The United States _Declaration of Independence_.

    Quotes or sections of quoted text are styled in italics and surrounded by double quotes ":

    In the wise words of Winnie the Pooh _"People say nothing is impossible, but I do nothing every day."_

    Code blocks​

    Tag code blocks with the syntax of the code they are presenting:

        ```javascript
    console.log(error);
    ```
    Command-line examples​

    Write command-line inputs without any other characters. Precede outputs from the command line with a greater-than sign >. Include an empty line between the input and output of a command-line example:

        ```bash
    ping Fula.io

    > PING Fula.io (209.94.90.1): 56 data bytes
    > 64 bytes from 209.94.90.1: icmp_seq=0 ttl=53 time=15.830 ms
    > 64 bytes from 209.94.90.1: icmp_seq=1 ttl=53 time=19.779 ms
    > 64 bytes from 209.94.90.1: icmp_seq=2 ttl=53 time=20.778 ms
    > 64 bytes from 209.94.90.1: icmp_seq=3 ttl=53 time=20.578 ms
    > --- Fula.io ping statistics ---
    > 4 packets transmitted, 4 packets received, 0.0% packet loss
    ```

    Command-line examples can be truncated with three periods ... to remove extraneous information:

        ```bash
    ping Fula.io

    > PING Fula.io (209.94.90.1): 56 data bytes
    > 64 bytes from 209.94.90.1: icmp_seq=0 ttl=53 time=15.830 ms
    > ...
    > 4 packets transmitted, 4 packets received, 0.0% packet loss
    ```

    Inline code tags​

    Back ticks also are used to surround directories, file names, and version numbers between inline code tags `.

    Version `1.2.0` of the program is stored in `~/code/examples`. Open `exporter.exe` to run the program.

    List items​

    All list items follow sentence structure. Only names and places are capitalized, along with the first letter of the list item. All other letters are lowercase:

    1. Never leave Nottingham without a sandwich.
    2. Brian May played guitar for Queen.
    3. Oranges.

    List items end with a period ., or a colon : if the list item has a sub-list:

    1. Charles Dickens novels:
      1. Oliver Twist.
      2. Nicholas Nickelby.
      3. David Copperfield.
    2. J.R.R Tolkien non-fiction books:
      1. The Hobbit.
      2. The Silmarillion.
      3. Letters from Father Christmas.
    Unordered lists​

    Use the dash character - for un-numbered list items:

    - An apple.
    - Three oranges.
    - As many lemons as you can carry.
    - Half a lime.

    Special characters​

    Whenever possible, spell out the name of the special character, followed by an example of the character itself within a code block.

    Use the dollar sign `$` to enter debug-mode.

    Keyboard shortcuts​

    When instructing the reader to use a keyboard shortcut, surround individual keys in code tags:

    Press `ctrl` + `c` to copy the highlighted text.

    The plus symbol + stays outside of the code tags.

    Images​

    The following rules and guidelines define how to use and store images.

    Docusaurus allows for both markdown and HTML in their markdown files.

    You can add a markdown file with:

    ![this is an alt text box](/img/path/here.png)

    You can add HTML images using the <img> tag. Using HTML for images is helpful because you are able to center images like this:

    <div class="text--center">
    <img src="/img/path/here.png">
    </div>

    Now you can transform the image with in-line HTML styling tags.

    Alt text​

    All images contain alt text so that screen-reading programs can describe the image to users with limited sight:

    ![Screenshot of an image being uploaded through the Fula desktop application.](/img/Fula-desktop-image-upload-screen.png)

    Storage location​

    Store images under a subfolder in the ./static/img/ directory. The subfolder must be named the same as the parent folder of the article the image is in. Docusaurus makes it easy to reference images from this directory. This also makes all articles and images separate, which makes for a better navigating experience when working under the docs directory.

    ![Screenshot of an image being uploaded through the FxBlox iOS app.](/img/upload-a-photo/fxblox-upload-screen.png)

    The directory structure of this article looks like this:

    static/
    β”œβ”€β”€ img/
    | └── upload-a-photo/
    | β”œβ”€β”€Fula-desktop-image-upload-screen.png
    | └── ...
    | └── delete-a-photo/

    File names​

    All file names are lower-case with dashes - between words, including image files:

    Fula-desktop/
    β”œβ”€β”€ add-a-user.md
    β”œβ”€β”€ enable-debug-mode.md
    β”œβ”€β”€ images
    β”‚ β”œβ”€β”€ additional-information-screen.png
    β”‚ β”œβ”€β”€ dark-mode-enabled.png
    β”‚ └── user-profile-image.png
    β”œβ”€β”€ log-into-the-application.md
    └── upload-a-photo.md
    - + \ No newline at end of file diff --git a/introduction/contribute/writing.html b/introduction/contribute/writing.html index 04812aa7..09076360 100644 --- a/introduction/contribute/writing.html +++ b/introduction/contribute/writing.html @@ -5,13 +5,13 @@ Writing Guide | Functionland - +

    Writing Guide

    This writing guide is adapted from IPFS's "writing guide" rules.

    This guide explains how to write an article. While the grammar, formatting, and style guide lets you know the rules you should follow, this guide will help you to properly structure your writing and choose the correct tone for your audience.

    Walkthroughs​

    The purpose of a walkthrough is to tell the user how to do something. They do not need to convince the reader of something or explain a concept. Walkthroughs are a list of steps the reader must follow to achieve a process or function.

    Goals​

    Use the following goals when writing walkthroughs:

    GoalKeywordExplanation
    AudienceGeneralEasy for anyone to read with minimal effort.
    FormalityNeutralSlang is restricted, but standard casual expressions are allowed.
    DomainTechnicalAcronyms and tech-specific language is used and expected.
    ToneNeutralWriting contains little to no emotion.
    IntentInstructTell the reader how to do something.

    Function or process​

    The end goal of a walkthrough is for the reader to achieve a very particular function. Mannually upgrading the FxBlox firmware_ is an example. Following this walkthrough isn't going to teach the reader much about working with the decentralized web or what Fula is. Still, by the end, they would have successfully upgraded the firmware on their FxBlox.

    Short length​

    Since walkthroughs cover one particular function or process, they tend to be quite short. The estimated reading time of a walkthrough is somewhere between 2 and 10 minutes. Most of the time, the most critical content in a walkthrough is presented in a numbered list. Images and GIFs can help the reader understand what they should be doing.

    If a walkthrough is converted into a video, that video should be no longer than 5 minutes.

    Walkthrough structure​

    Walkthroughs are split into three major sections:

    1. What we're about to do.
    2. The steps we need to do.
    3. Summary of what we just did and potential next steps.

    Conceptual articles​

    Articles are written with the intent to inform and explain something. These articles don't contain any steps or actions that the reader has to perform right now.

    These articles are vastly different in tone when compared to walkthroughs. Some topics and concepts can be challenging to understand, so creative writing and interesting diagrams are highly sought-after for these articles; whatever writers can do to make a subject more understandable, the better.

    Article goals​

    Use the following goals when writing conceptual articles:

    GoalKeywordExplanation
    AudienceKnowledgeableRequires a certain amount of focus to understand.
    FormalityNeutralSlang is restricted, but standard casual expressions are allowed.
    DomainAnyUsually technical, but it depends on the article.
    ToneConfident and friendlyThe reader must feel confident that the writer knows what they're talking about.
    IntentDescribeTell the reader why something does the thing that it does, or why it exists.

    Article structure​

    Articles are separated into five major sections:

    1. Introduction to the thing we're about to explain.
    2. What the thing is.
    3. Why it's essential.
    4. What other topics it relates to.
    5. Summary review of what we just read.

    Tutorials​

    When writing a tutorial, you're teaching a reader how to achieve a complex end-goal. Tutorials are a mix of walkthroughs and conceptual articles. Most tutorials will span several pages and contain multiple walkthroughs within them.

    Take the hypothetical tutorial Store on Fula net with Fula API, for example. This tutorial will likely have the following pages:

    1. A brief introduction to what the Fula net is and what Fula API can achieve.
    2. Download and introduce template code for uploading files.
    3. Upload and serve a file through the Fula API.
    4. Search, Filter, and update files with Fula API.
    5. Pinning and why it's useful.
    6. How to view and share files with Fula API.

    Pages 1 and 6 are conceptual articles, describing particular design patterns and ideas to the reader. All the other pages are walkthroughs instructing the user how to perform one specific action.

    When designing a tutorial, keep in mind the walkthroughs and articles that already exist, and note down any additional content items that would need to be completed before creating the tutorial.

    - + \ No newline at end of file diff --git a/introduction/fula.html b/introduction/fula.html index 82dd37c8..390e66ef 100644 --- a/introduction/fula.html +++ b/introduction/fula.html @@ -5,13 +5,13 @@ Fula Network | Functionland - +

    Fula Network

    Fula Network Architecture

    How does it work?​

    To become a truly viable alternative to Big Tech cloud storage, we need to guarantee:

    • reliability

    • availability

    • security

    To guarantee reliability, availability, and security, we designed a system that utilizes an already existent decentralized web.

    The Fula network is peer-to-peer architecture designed with open protocols and specifications such as libp2p, IPFS and decentralized identity.

    This allows us to achieve an unprecedented level of interoperability and makes every participant in the ecosystem future proof, including DApp developers.

    By developing on the Fula platform, you earn $FULA from your open-source contributions. At the same time, you avoid locking yourself in to a single platform with proprietary APIs and archaic approval processes.

    By decoupling data from the application, DApp developers can focus on providing rich user experiences without having to worry about what happens to customer data.

    It also means Blox customers will not be locked in to using any one, single DApp.

    The Fula network provides a free, open market for service providers. Box customers are not just consumers; they can become producers within this new ecosystem too.

    In short, it's a positive sum protocol for everyone.

    Like what you hear?​

    Become a pioneer. Join us on our journey to bring Web3 into the mainstream.

    You can do that by:

    • joining the revolution and ordering your FxBlox on shop.fx.land

    • heading over to Fula API docs to learn how to develop your own DApps on the FxBlox

    • providing feedback/input on our RFCs

    • sign into one of our socials and join the conversation! Let us know what you would like to learn more of.

    - + \ No newline at end of file diff --git a/mvp.html b/mvp.html index 5c42ffcb..f5b874a9 100644 --- a/mvp.html +++ b/mvp.html @@ -5,13 +5,13 @@ Minimum Valuable Product | Functionland - +

    Minimum Valuable Product

    The following describes how the Fula network software will work from the network participant's perspective.

    Fotos

    Pools

    - + \ No newline at end of file diff --git a/mvp/admin-reporting.html b/mvp/admin-reporting.html index 8caf10ac..a1771803 100644 --- a/mvp/admin-reporting.html +++ b/mvp/admin-reporting.html @@ -5,13 +5,13 @@ Admin Reporting & Alerts | Functionland - +

    Admin Reporting & Alerts

    - + \ No newline at end of file diff --git a/mvp/box-admin.html b/mvp/box-admin.html index 4d8de184..9c0b1f4f 100644 --- a/mvp/box-admin.html +++ b/mvp/box-admin.html @@ -5,13 +5,13 @@ Box Admin | Functionland - +

    Box Admin

    After loading the Box Admin DApp.

    I am asked to enter the username and password I created during Unboxing

    After logging in.

    I am presented with a dashboard where I can:

    • update my personal info
    • manage my $FULA token account
    • view a list of Boxes that I own and their resource usage
    • view installed DApps
    • manage private pool
    • manage public pools
    • manage other members of their Box
    - + \ No newline at end of file diff --git a/mvp/forgot-password.html b/mvp/forgot-password.html index e913f652..70b53205 100644 --- a/mvp/forgot-password.html +++ b/mvp/forgot-password.html @@ -5,14 +5,14 @@ Forgot Password | Functionland - +

    Forgot Password

    If I ever lose or forget my password. I can recover it by...

    • email recovery?
    • two factor authentication?
      • email + mobile device?
    • having a group of friends multisig it back to me?
    - + \ No newline at end of file diff --git a/mvp/fotos.html b/mvp/fotos.html index d35856f4..12c18132 100644 --- a/mvp/fotos.html +++ b/mvp/fotos.html @@ -5,13 +5,13 @@ Fotos | Functionland - + - + \ No newline at end of file diff --git a/mvp/fotos/availability.html b/mvp/fotos/availability.html index 436dc54a..48376af2 100644 --- a/mvp/fotos/availability.html +++ b/mvp/fotos/availability.html @@ -5,13 +5,13 @@ Fotos Availability | Functionland - +

    Fotos Availability

    Acceptance Criteria​

    You uploaded a photo to your Fula API server.

    Your Fula environment goes offline and you are still able to retrieve the photo from a second Fula environment in your pool.

    Preconditions​

    1. You have already set up a cluster.

    2. You have already set up Fotos with your own wallet account and connected it to your Fula API server.

    3. You already backed up a photo that you would like to share.

    Steps​

    Here is a video demonstrating the following steps.

    1. Delete the photo from your device by long pressing the photo and selecting the 'delete' icon.

    2. Remove the first Box from your list and add the second using the multiaddress from the server logs of the second Box.

    3. Verify that the second Box is in fact storing the image and that you are able to retrieve it by tapping on the placeholder thumbnail that appears in the deleted image's place.

    - + \ No newline at end of file diff --git a/mvp/fotos/backup.html b/mvp/fotos/backup.html index a533a47c..23779f46 100644 --- a/mvp/fotos/backup.html +++ b/mvp/fotos/backup.html @@ -5,13 +5,13 @@ Fotos Backup to Fula environment | Functionland - +

    Fotos Backup to Fula environment

    Acceptance Criteria​

    You can backup a photo to your Fula environment and retrieve it from the Fula environment at a later date.

    Preconditions​

    1. You already have a Fula environment running.

    2. You have already set up Fotos with your own wallet account and connected it to your Fula environment.

    Steps​

    Here is a video demonstrating the following steps.

    1. Tap on a photo to enter browse mode and tap the 'upload to cloud' icon in the top right.

    2. After the image has uploaded succesfully you should see a 'cloud with a checkbox' icon and a 'share' icon in browse mode for the image.

    3. You can verify that the Fula environment is in fact storing the image for you and that you are able to retrieve it by deleting the image from your device and tapping on the placeholder thumbnail that appears in its place to download it.

    - + \ No newline at end of file diff --git a/mvp/fotos/setup.html b/mvp/fotos/setup.html index c07b6cad..e9c25828 100644 --- a/mvp/fotos/setup.html +++ b/mvp/fotos/setup.html @@ -5,13 +5,13 @@ Fotos Setup | Functionland - +

    Fotos Setup

    Acceptance Criteria​

    You set up Fotos with your wallet account and connect it to the Fula API server.

    Once set up correctly you are able to perform all other Fotos stories.

    Preconditions​

    1. You have already downloaded and installed Fotos.

    2. You already have a Fula environment running and have acquired the Fula API server's multiaddress from the server logs that is reachable from your phone.

    Steps​

    Connect Fotos to your wallet​

    Here is a video demonstrating the following steps.

    1. Go to Account -> Connect your wallet

    2. Authorize the Dapp from your wallet.

    3. Tap 'sign your address' when redirected back to Fotos.

    4. Perform the signing request from the wallet.

    Connect Fotos to your Fula API server​

    Here is a video demonstrating the following steps.

    1. Acquire the Fula API server multiaddress from it's server logs.

    2. Copy the Fula API server's multiaddress to your clipboard.

    3. Go to Account -> Boxes.

    4. Add a new Box.

      a ) Give the Box a name for identification purposes (can be anything).

      b ) Paste the Box's multiaddress .

    - + \ No newline at end of file diff --git a/mvp/fotos/sharing.html b/mvp/fotos/sharing.html index 33c6e02e..e64144f8 100644 --- a/mvp/fotos/sharing.html +++ b/mvp/fotos/sharing.html @@ -5,13 +5,13 @@ Fotos Sharing | Functionland - +

    Fotos Sharing

    Story​

    You can share a photo with a friend.

    Preconditions​

    1. You already have a running Fula environment.

    2. You have already set up Fotos with your own wallet account and connected it to your Fula environment.

    3. You already backed up a photo that you would like to share.

    4. You have already set up Fotos on a second device you would like to share the photo with (connected to the same Fula environment with a different wallet).

    Steps​

    Have your friend send you there DID​

    Here is a video demonstrating the following steps.

    1. Tell them to go to 'Account' -> 'share' icon.

    2. Tell them to send their DID to you in a secure/private channel (eg/ copy to their clipboard and send it to you as an email) back to your friend.

    Here is a video demonstrating the following steps.

    1. Tap on the photo to share.

    2. Tap the 'share' icon.

    3. Paste the DID that your friend sent you.

    4. You should see a 'shared' message stating the asset was added to a shared collection. Tap 'yes' to get the sharing link and send it over a secure/private channel.

    Your friend views the shared photo​

    Here is a video demonstrating the following steps.

    1. Have your friend tap on the link and it should open Fotos on their phone and display the image you shared with them.
    - + \ No newline at end of file diff --git a/mvp/my-account.html b/mvp/my-account.html index 75aa22c8..9210131c 100644 --- a/mvp/my-account.html +++ b/mvp/my-account.html @@ -5,14 +5,14 @@ My Account | Functionland - +

    My Account

    On my account page. I am able to edit my password.

    - + \ No newline at end of file diff --git a/mvp/pools.html b/mvp/pools.html index cdbb6b40..a501246e 100644 --- a/mvp/pools.html +++ b/mvp/pools.html @@ -5,13 +5,13 @@ Pools | Functionland - + - + \ No newline at end of file diff --git a/mvp/pools/storage-provide.html b/mvp/pools/storage-provide.html index dc51f168..5e6ee8be 100644 --- a/mvp/pools/storage-provide.html +++ b/mvp/pools/storage-provide.html @@ -5,13 +5,13 @@ Providing Storage | Functionland - +

    Providing Storage

    Acceptance Criteria​

    You see your balance increase on the chain explorer after uploading a file to your node using Fotos.

    Preconditions​

    1. You are a running a fula testnet environment.

    2. You have already set up Fotos and connected it to your Box running in the fula testnet environment.

    Steps​

    Here is a video demonstrating the following steps.

    1. In the Fotos app, tap on a photo to enter browse mode and tap the 'upload to cloud' icon in the top right.

    2. Take note of the CID for the file that you just uploaded.

    3. Add the file you uploaded to your IPFS node's MFS (so that it can be found by the proof engine).

    4. Take note of your Account ID.

    5. Let the proof engine know that you are storing the file by creating a new manifest for the file you just uploaded.

    6. Restart the proof engine to ensure it picks up the latest manifest.

    7. See that your balance has increased either by viewing the proof engine logs from docker-compose or by looking for your account in the chain explorer.

    - + \ No newline at end of file diff --git a/mvp/privacy-dashboard.html b/mvp/privacy-dashboard.html index 2b7a3149..68c91acf 100644 --- a/mvp/privacy-dashboard.html +++ b/mvp/privacy-dashboard.html @@ -5,13 +5,13 @@ privacy-dashboard | Functionland - +

    privacy-dashboard

    • I can see all of my data and what DApps are creating/encrypting content.
    - + \ No newline at end of file diff --git a/mvp/questions.html b/mvp/questions.html index 2743ae5e..822ec762 100644 --- a/mvp/questions.html +++ b/mvp/questions.html @@ -5,13 +5,13 @@ questions | Functionland - +

    Questions about the MVP

    New Questions​

    • who has control over my pinset?

      • only I can delete them?
    • what should happen if someone gets access to my phone?

    Local Pools​

    • local pools

      • public pools = anyone can join?
      • private pools = you must have invite or approval from a pool admin?
    • global pools = ?

    • is there a name for a pool of Boxes that I own?

      • is the availability story for pools of Boxes that I own only or for local pools (private + public)?
    • what happens if everyone in my pool pulls the plug all of a sudden?

    • can I choose to join as either a consumer or a producer or do I have to join as both a consumer and a producer?

    • what happens when I run out of $FULA tokens to:

      • the data stored by peers in my local pool?
    • does any member of a pool have administrator privileges?

    • what are the tradeoffs we are making that Filecoin is not making?

    Storage​

    • when I join a pool should I be able to tell it how much storage I want to allocate to the pool?

    • what happens if I offer 1 Tb and there is no demand?

    • whitelisting

      • where will I whitelist photos and other files/data to be included in a pool?

      • is there a separate whitelist for each pool I am a member of?

    • member of multiple pools?

      • should I select what photos to back up in each pool I join?
    • if I am the only member of my local pool, will I have to pay myself?

    • how does proof of resource work and what is difference between this and proof of space-time / proof of replication?

    • how will I know that my data is safely stored and that I won't have to worry about data loss?

    • confirmation = if database is replicated then only protection is encryption (no gatekeeping process)?

    • sharing

      • in order to share a photo with someone I need to give them access - does that mean they need to be a member of my pool or are the concepts decoupled?

    Computation​

    • how will I know that my data is being shared with peers to be computed on in a way that preserves my privacy?

    Administration​

    • if I lose or forget my account password then how will I recover it?

      • email recovery means no zero knowledge?

      • other options

        • two factor auth?

    $FULA Account​

    • should I know what my $FULA is being spent on?
      • eg/ in the last month I spent 50 $FULA on Fotos and 200 on 'Pool A' and 150 on 'Pool B'?
    • should there also be a way to tell my balance and earnings over time?
    • should I give approval before $FULA is spent?
    - + \ No newline at end of file diff --git a/mvp/technical-questions.html b/mvp/technical-questions.html index 0d1bda22..3b795f34 100644 --- a/mvp/technical-questions.html +++ b/mvp/technical-questions.html @@ -5,13 +5,13 @@ technical questions | Functionland - +

    Questions about the MVP

    Local Pools​

    • what is purpose of the swarm key in a public pool?

    • how is PoR going to work on an rPi?

      • for our PoR algo to work on the rPi we are going to have to consume a lot less resources

    Hardware​

    • what is devkit and what are framework extension cards for?
    - + \ No newline at end of file diff --git a/mvp/unboxing.html b/mvp/unboxing.html index 863471ce..50095dd4 100644 --- a/mvp/unboxing.html +++ b/mvp/unboxing.html @@ -5,7 +5,7 @@ Unboxing | Functionland - + @@ -16,7 +16,7 @@ I am told to load the Box Admin DApp on another device.

    When I first load the Box Admin DApp. I am prompted to enter some information about my identity and to create a new administrative password.

    After creating my account. I am redirected to a Box Admin dashboard.

    - + \ No newline at end of file diff --git a/reference-api.html b/reference-api.html index 0d7932e6..8f38efcd 100644 --- a/reference-api.html +++ b/reference-api.html @@ -5,13 +5,13 @@ Reference | Functionland - +

    Fula API Reference

    The Fula API includes the following:

    • a Graph API for storing and querying structured data (JSON) over a graphql interface

    • a File API for uploading and retrieving files

    Typical API Usage​

    The File and Graph APIs can be used together to build many different types of DApps.

    To better understand how they work together, here is an illustration of the basic flow you would use if you wanted to build your own photos DApp.

    At a high level you will write a client that enables the user to upload a bunch of files and retrieve a list of the files so that they can be displayed in your DApp.

    In order to do this you need to tell the Graph API where to store the collection of photos. You can give this collection any name you choose.

    Photo Upload​

    Photo-Upload

    Photo-Upload

    Gallery-Retrieve

    Gallery-Retrieve

    Under the Covers​

    To understand how the Fula client connects to a Box, it may help to understand what is going on under the covers.

    The following Box <-> Client class diagram shows relationships and responsibilities for each component.

    Client Box architecture

    - + \ No newline at end of file diff --git a/release/testnet-alpha.html b/release/testnet-alpha.html index 5d0914b1..1d360931 100644 --- a/release/testnet-alpha.html +++ b/release/testnet-alpha.html @@ -5,13 +5,13 @@ Protocol Testnet Alpha Pre-release | Functionland - +

    Protocol Testnet Alpha Pre-release

    Last updated: July 29, 2022

    What is it?​

    The protocol testnet alpha pre-release includes the Fotos mobile application and some of the Fula components that will be pre-installed on FxBlox customer's raspberry Pis when they are shipped.

    What to expect​

    The software we are delivering to you today can give you an idea of how the Fotos mobile app will back up and store your photos to the Fula testnet environment.

    Once you have everything set up, you should have a Fula API server, IPFS and Fula funge components all talking to each other running on your host machine.

    You should be able to upload your media using Fotos from your mobile phone to the Fula testnet environment encrypted with a key from your own wallet.

    You can also get an idea of how a decentralized identity might be generated from your and your friend' wallets in order to enable sharing of photos with each other.

    Lastly, you can get a first glimpse of how backing up files (that you uploaded with Fotos) will cause rewards to be generated for you on the Fula testnet blockchain.

    Requirements​

    • one Android phone

    • a second Android phone for sharing photos with a friend

    • your own computer that can run Docker

      • Linux is required for the last step
    • each phone must be on the same network as the computer where the Fula testnet environment is running

    • a mobile ethereum compatible wallet (eg/ Metamask or Trust Wallet)

    Submitting feedback​

    We would love to know how it went for you!

    Especially if you cannot complete any of the steps due to a bug you encountered or because you cannot satisfy the above requirements.

    You can send us feedback via Github or as an email.

    Here is some boilerplate text you can copy/paste when you are ready to send the feedback.

    Subject: Protocol testnet alpha

    Feedback Type: [ Bug | Feature Request ]

    Feedback:

    [ I completed all of the steps successfully. This rocked but I have a few suggestions for the next release...]

    OR

    [ I was unable to complete X step(s). The following happened when I tried to complete the step: ...]

    If you believe the issue is happening in the Fula API then you can create an issue on the Fula repo and include the docker-compose server logs.

    If you believe the issue has something to do with the testnet setup you can create an issue on the testnet repo and include the docker-compose server logs.

    If you believe the issue is happening in the Fotos mobile client then you can create an issue on the Fotos repo and describe what is going wrong.

    If you don't know where the problem exists or don't have a Github account then please send us an email and attach the server logs if you are reporting a bug.

    To output the server logs to a file​

    Open a terminal and enter the following in the same directory that you ran docker-compose in the previous steps.

      > docker-compose logs >  out.log

    Beware of Risks​

    The Functionland protocol testnet alpha pre-release includes client side encryption as a first layer of security to help prevent others from gaining access to your photos and video.

    However, because the software we are delivering is fresh off the press and still not properly audited, PLEASE USE WITH CAUTION.

    At this point, we recommend you not upload any highly sensitive media to the Fula testnet environment, use it as a primary backup facility or expose any of the services over untrusted networks.

    How to get started​

    Fula testnet environment setup​

    First, you can follow the instructions over here for setting up a Fula testnet environment on your host machine with Docker.

    Fotos installation​

    Download the latest release of Fotos from the google play store and install it.

    Testing steps​

    Once you have Fotos and the Fula testnet environment properly installed you can proceed with the following steps:

    1. See here for instructions on setting up Fotos before moving on to anything else.

    2. See here for instructions on backing up an image from your device to the Fula API server using Fotos.

    3. See here for instructions on sharing the image with a friend.

    4. See here for instructions on how to give yourself $FULA rewards for storing a file uploaded from your Fotos application.

    - + \ No newline at end of file diff --git a/whitepaper.html b/whitepaper.html index 9a36c7fd..a26cc2d4 100644 --- a/whitepaper.html +++ b/whitepaper.html @@ -5,13 +5,13 @@ Whitepaper | Functionland - + - + \ No newline at end of file diff --git a/work_in_progress.html b/work_in_progress.html index a8431381..e5a46ca2 100644 --- a/work_in_progress.html +++ b/work_in_progress.html @@ -5,13 +5,13 @@ work_in_progress | Functionland - +

    work_in_progress

    - + \ No newline at end of file