Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: upload btc execution metadata to ipfs #339

Merged
merged 20 commits into from
Aug 14, 2024
Merged
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions chains/btc/executor/executor.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package executor

import (
"bytes"
"context"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
"sync"
"time"

Expand Down Expand Up @@ -33,6 +39,8 @@ var (
INPUT_SIZE uint64 = 180
OUTPUT_SIZE uint64 = 34
FEE_ROUNDING_FACTOR uint64 = 5
IPFS_JWT_TOKEN string = os.Getenv("IPFS_JWT_TOKEN")
IPFS_URL string = os.Getenv("IPFS_URL")
)

type MempoolAPI interface {
Expand All @@ -45,6 +53,10 @@ type PropStorer interface {
PropStatus(source, destination uint8, depositNonce uint64) (store.PropStatus, error)
}

type IPFSResponse struct {
IpfsHash string `json:"IpfsHash"`
}

type Executor struct {
coordinator *tss.Coordinator
host host.Host
Expand Down Expand Up @@ -273,6 +285,8 @@ func (e *Executor) rawTx(proposals []*BtcTransferProposal, resource config.Resou

func (e *Executor) outputs(tx *wire.MsgTx, proposals []*BtcTransferProposal) (uint64, error) {
outputAmount := uint64(0)
var dataToUpload []map[string]interface{}

for _, prop := range proposals {
addr, err := btcutil.DecodeAddress(prop.Data.Recipient, &e.chainCfg)
if err != nil {
Expand All @@ -282,10 +296,40 @@ func (e *Executor) outputs(tx *wire.MsgTx, proposals []*BtcTransferProposal) (ui
if err != nil {
return 0, err
}

txOut := wire.NewTxOut(int64(prop.Data.Amount), destinationAddrByte)
tx.AddTxOut(txOut)

dataToUpload = append(dataToUpload, map[string]interface{}{
"sourceDomain": prop.Source,
"depositNonce": prop.Data.DepositNonce,
})

outputAmount += prop.Data.Amount
}

// Convert the array to JSON
jsonData, err := json.Marshal(dataToUpload)
if err != nil {
log.Error().Err(err).Msg("Error occured while handling data for upload")

}

// Upload to IPFS
cid, err := uploadToIpfs(jsonData)
if err != nil {
log.Error().Err(err).Msg("Error occured while uploading metadata to ipfs")
}

// Store the CID in OP_RETURN
opReturnData := []byte("syg_" + cid)
opReturnScript, err := txscript.NullDataScript(opReturnData)
if err != nil {
log.Error().Err(err).Msg("Error occured while constructiong OP_RETURN data")
}

opReturnOut := wire.NewTxOut(0, opReturnScript)
tx.AddTxOut(opReturnOut)
return outputAmount, nil
}

Expand Down Expand Up @@ -402,3 +446,50 @@ func (e *Executor) storeProposalsStatus(props []*BtcTransferProposal, status sto
}
e.propMutex.Unlock()
}

func uploadToIpfs(data []byte) (string, error) {
tcar121293 marked this conversation as resolved.
Show resolved Hide resolved
// Create a new multipart form file
body := new(bytes.Buffer)
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("file", "metadata.json")
if err != nil {
return "", err
}
_, err = part.Write(data)
if err != nil {
return "", err
}
writer.Close()

// Create a new request
req, err := http.NewRequest("POST", IPFS_URL, body)
if err != nil {
return "", err
}

// Set the headers
req.Header.Add("Authorization", "Bearer "+IPFS_JWT_TOKEN)
req.Header.Add("Content-Type", writer.FormDataContentType())

// Make the request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()

// Read the response
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}

// Parse the response
var ipfsResponse IPFSResponse
if err := json.Unmarshal(respBody, &ipfsResponse); err != nil {
return "", err
}

return ipfsResponse.IpfsHash, nil
}
Loading