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 }