Skip to content



Arweave is a new type of storage that backs data with sustainable and perpetual endowments, allowing users and developers to truly store data forever – for the very first time.

As a collectively owned hard drive that never forgets, Arweave allows us to remember and preserve valuable information, apps, and history indefinitely. By preserving history, it prevents others from rewriting it.

Scanning Blocks

The block scanner monitors fortuna addresses and looks for incoming transactions to those addresses. When it sees, it performs validations and witnesses to hermes chain.

      txInfo, err := c.client.GetTransactionByID(tx)

      // if tx is not found, invalid
      if err == argo.ErrNotFound || err == argo.ErrInvalidId {
      return types.TxInItem{}, err

      // converting signature data to owner address
      sender, err := arutils.OwnerToAddress(txInfo.Owner)

      if err != nil {
      return types.TxInItem{}, err

      winstonQtyStr := txInfo.Quantity
      winstonFeeStr := txInfo.Reward

      winstonQty, ok := cosmos.ParseUint(winstonQtyStr)

      if ok != nil {
      err = fmt.Errorf("invalid amount: %v", winstonQtyStr)
      return types.TxInItem{}, err

      _, ok = cosmos.ParseUint(winstonFeeStr)

      if ok != nil {
      err = fmt.Errorf("invalid fee: %v", winstonFeeStr)
      return types.TxInItem{}, err

      // when value is less than or equal to zero, it is data transaction not a transfer
      if winstonQty.IsZero() {
      return types.TxInItem{}, fmt.Errorf("not a transfer transaction, its a data transaction, so ignoring")

      client := argo.NewClient("")
      address := os.Getenv("AR_ADDRESS")
      reward, err := client.GetTransactionPrice([]byte(""), &address)
      convReward := cosmos.NewUint(uint64(reward))
      // till here

      if err != nil {
      c.logger.Error().Err(err).Msg("failed to get arweave fee")

      gasFee := common.Gas{
      common.NewCoin(common.ARAsset, convReward).WithDecimals(common.ARWEAVECHAIN.GetGasAssetDecimal()),
      // update memory cache

      toAddr := txInfo.Target

      //read memo from tags [{name, value}]
      var memo string
      for _, val := range txInfo.Tags {
      if strings.EqualFold(val.Name, "memo") {
      memo = val.Value
      c.logger.Debug().Str("memo", memo).Msg("found memo field")

      if memo == "" {
      c.logger.Debug().Str("memo", memo).Msg("found empty memo")

      return types.TxInItem{
      BlockHeight: height,
      Tx:          txInfo.ID,
      Sender:      sender,
      To:          toAddr,
      Coins: common.Coins{
      common.NewCoin(common.ARAsset, winstonQty).WithDecimals(common.ARWEAVECHAIN.GetGasAssetDecimal()),
      Memo: memo,
      Gas:  gasFee,
      }, nil

Arweave Signer

Signer works on signing the outbound transactions received txout from hermes chain that needs to sent on arweave chain. Signing transactions are done in two ways: using rsa tss signing algo and single wallet signing.

      _, err := tx.VaultPubKey.GetAddress(c.GetChain())
      //c.logger.Debug().Msgf("process outbound tx", fromAddr)
      if err != nil {
      return &types.Transaction{}, fmt.Errorf("failed to convert arweave address (%s): %w", tx.VaultPubKey.String(), err)

      // initialise to collect all received txout substractFee coins
      var coins = cosmos.NewUint(0)
      for _, coin := range tx.Coins {
      // handle sors return, leave enough coin to pay for gas.
      if strings.HasPrefix(tx.Memo, hermes.TxToStringMap[hermes.TxSorsReturn]) {
      if coin.Asset == c.cfg.ChainID.GetGasAsset() {
      substractFee := c.averageFee().Mul(cosmos.NewUint(3)).Quo(cosmos.NewUint(2))
      if coin.Amount.LT(substractFee) {
      return &types.Transaction{}, fmt.Errorf("not enough to pay for transaction, Origal amount %d, Fee %d", coin.Amount.Uint64(), substractFee.Uint64())

      coin.Amount = coin.Amount.Sub(substractFee)
      coins = coins.Add(coin.Amount)

      tag := types.Tag{
        Name:  "memo",
        Value: tx.Memo,

      var tags []types.Tag
      tags = append(tags, tag)
      encodeTag := utils.TagsEncode(tags)

      arTx := &types.Transaction{
      Format:   2,
      Quantity: coins.String(),
      Data:     "",
      DataSize: "0",
      Reward:   c.averageFee().String(),
      Target:   tx.ToAddress.String(),
      Tags:     encodeTag,

      return arTx, nil