sorare/mutations/transfer.go

223 lines
6.3 KiB
Go

package mutations
import (
"math/big"
"strconv"
"strings"
"github.com/pkg/errors"
"git.lehouerou.net/laurent/sorare/starkware"
)
type Transfer struct {
Amount string `graphql:"amountAsString:amount"`
Nonce int `graphql:"nonce"`
SenderVaultId int `graphql:"senderVaultId"`
Token string `graphql:"token"`
ReceiverVaultId int `graphql:"receiverVaultId"`
ReceiverPublicKey string `graphql:"receiverPublicKey"`
ExpirationTimestamp int `graphql:"expirationTimestamp"`
Condition string `graphql:"condition"`
FeeInfoUser *struct {
FeeLimit string `graphql:"feeLimit"`
TokenId string `graphql:"tokenId"`
SourceVaultId int `graphql:"sourceVaultId"`
}
}
func (t Transfer) hash() (string, error) {
token := t.Token
if strings.HasPrefix(token, "0x") {
token = token[2:]
}
receiverPublicKey := t.ReceiverPublicKey
if strings.HasPrefix(receiverPublicKey, "0x") {
receiverPublicKey = receiverPublicKey[2:]
}
condition := t.Condition
if strings.HasPrefix(condition, "0x") {
condition = condition[2:]
}
amountInt, err := strconv.ParseInt(t.Amount, 10, 64)
if err != nil {
return "", errors.Wrap(err, "parsing amount")
}
amountBn := big.NewInt(amountInt)
nonceBn := big.NewInt(int64(t.Nonce))
senderVaultIdBn := big.NewInt(int64(t.SenderVaultId))
receiverVaultIdBn := big.NewInt(int64(t.ReceiverVaultId))
expirationTimestampBn := big.NewInt(int64(t.ExpirationTimestamp))
if t.FeeInfoUser != nil {
feeVaultIdBn := big.NewInt(int64(t.FeeInfoUser.SourceVaultId))
feeLimitInt, err := strconv.ParseInt(t.FeeInfoUser.FeeLimit, 10, 64)
if err != nil {
return "", errors.Wrap(err, "parsing feeLimit")
}
feeLimitBn := big.NewInt(feeLimitInt)
feeToken := t.FeeInfoUser.TokenId
if strings.HasPrefix(feeToken, "0x") {
feeToken = feeToken[2:]
}
instructionType := big.NewInt(4)
if t.Condition != "" {
instructionType = big.NewInt(5)
}
return hashTransferWithFee(
instructionType,
senderVaultIdBn,
receiverVaultIdBn,
amountBn,
nonceBn,
expirationTimestampBn,
token,
receiverPublicKey,
feeToken,
feeVaultIdBn,
feeLimitBn,
condition,
)
} else {
instructionType := big.NewInt(1)
if t.Condition != "" {
instructionType = big.NewInt(2)
}
return hashMsg(
instructionType,
senderVaultIdBn,
receiverVaultIdBn,
amountBn,
big.NewInt(0),
nonceBn,
expirationTimestampBn,
token,
receiverPublicKey,
condition,
)
}
}
func hashMsg(
instructionType *big.Int,
senderVaultId *big.Int,
receiverVaultId *big.Int,
amount0 *big.Int,
amount1 *big.Int,
nonce *big.Int,
expirationTimestamp *big.Int,
transferToken string,
reveiverPublicKey string,
condition string) (string, error) {
packedMessage1 := big.NewInt(0).Set(instructionType)
packedMessage1.Lsh(packedMessage1, 31)
packedMessage1.Add(packedMessage1, senderVaultId)
packedMessage1.Lsh(packedMessage1, 31)
packedMessage1.Add(packedMessage1, receiverVaultId)
packedMessage1.Lsh(packedMessage1, 63)
packedMessage1.Add(packedMessage1, amount0)
packedMessage1.Lsh(packedMessage1, 63)
packedMessage1.Add(packedMessage1, amount1)
packedMessage1.Lsh(packedMessage1, 31)
packedMessage1.Add(packedMessage1, nonce)
packedMessage1.Lsh(packedMessage1, 22)
packedMessage1.Add(packedMessage1, expirationTimestamp)
transferTokenBn, ok := big.NewInt(0).SetString(transferToken, 16)
if !ok {
return "", errors.Errorf("transferToken is not a hex string: %s", transferToken)
}
reveiverPublicKeyBn, ok := big.NewInt(0).SetString(reveiverPublicKey, 16)
if !ok {
return "", errors.Errorf("reveiverPublicKey is not a hex string: %s", reveiverPublicKey)
}
if condition == "" {
return starkware.PedersenHash(
starkware.PedersenHash(transferTokenBn.String(), reveiverPublicKeyBn.String()),
packedMessage1.String(),
), nil
}
conditionBn, ok := big.NewInt(0).SetString(condition, 16)
if !ok {
return "", errors.Errorf("condition is not a hex string: %s", condition)
}
return starkware.PedersenHash(
starkware.PedersenHash(
starkware.PedersenHash(
transferTokenBn.String(),
reveiverPublicKeyBn.String(),
),
conditionBn.String(),
),
packedMessage1.String(),
), nil
}
func hashTransferWithFee(
instructionType *big.Int,
senderVaultId *big.Int,
receiverVaultId *big.Int,
amount *big.Int,
nonce *big.Int,
expirationTimestamp *big.Int,
transferToken string,
reveiverPublicKey string,
feeToken string,
feeVaultId *big.Int,
feeLimit *big.Int,
condition string) (string, error) {
packedMessage1 := big.NewInt(0).Set(senderVaultId)
packedMessage1.Lsh(packedMessage1, 64)
packedMessage1.Add(packedMessage1, receiverVaultId)
packedMessage1.Lsh(packedMessage1, 64)
packedMessage1.Add(packedMessage1, feeVaultId)
packedMessage1.Lsh(packedMessage1, 32)
packedMessage1.Add(packedMessage1, nonce)
packedMessage2 := big.NewInt(0).Set(instructionType)
packedMessage2.Lsh(packedMessage2, 64)
packedMessage2.Add(packedMessage2, amount)
packedMessage2.Lsh(packedMessage2, 64)
packedMessage2.Add(packedMessage2, feeLimit)
packedMessage2.Lsh(packedMessage2, 32)
packedMessage2.Add(packedMessage2, expirationTimestamp)
packedMessage2.Lsh(packedMessage2, 81)
packedMessage2.Add(packedMessage2, big.NewInt(0))
transferTokenBn, ok := big.NewInt(0).SetString(transferToken, 16)
if !ok {
return "", errors.Errorf("transferToken is not a hex string: %s", transferToken)
}
reveiverPublicKeyBn, ok := big.NewInt(0).SetString(reveiverPublicKey, 16)
if !ok {
return "", errors.Errorf("reveiverPublicKey is not a hex string: %s", reveiverPublicKey)
}
feeTokenbn, ok := big.NewInt(0).SetString(feeToken, 16)
if !ok {
return "", errors.Errorf("feeToken is not a hex string: %s", feeToken)
}
tmpHash := starkware.PedersenHash(
starkware.PedersenHash(transferTokenBn.String(), feeTokenbn.String()),
reveiverPublicKeyBn.String(),
)
if condition == "" {
return starkware.PedersenHash(
starkware.PedersenHash(tmpHash, packedMessage1.String()),
packedMessage2.String(),
), nil
}
conditionBn, ok := big.NewInt(0).SetString(condition, 16)
if !ok {
return "", errors.Errorf("condition is not a hex string: %s", condition)
}
return starkware.PedersenHash(
starkware.PedersenHash(
starkware.PedersenHash(tmpHash, conditionBn.String()), packedMessage1.String()),
packedMessage2.String(),
), nil
}