Skip to content

Commit

Permalink
Merge branch 'feature/nft_transfer'
Browse files Browse the repository at this point in the history
  • Loading branch information
grishamsc committed Nov 2, 2023
2 parents 5efe699 + 523f88b commit 49636b0
Show file tree
Hide file tree
Showing 11 changed files with 299 additions and 6 deletions.
4 changes: 2 additions & 2 deletions Source/TonSwift/Cells/Cell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,15 @@ public struct Cell: Hashable {
- parameter src: source buffer
- returns array of cells
*/
static func fromBoc(src: Data) throws -> [Cell] {
public static func fromBoc(src: Data) throws -> [Cell] {
return try deserializeBoc(src: src)
}

/**
Helper class that deserializes a single cell from BOC in base64
- parameter src: source string
*/
static func fromBase64(src: String) throws -> Cell {
public static func fromBase64(src: String) throws -> Cell {
guard let data = Data(base64Encoded: src) else {
throw NSError()
}
Expand Down
59 changes: 59 additions & 0 deletions Source/TonSwift/Jettons/JettonTransferData.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// JettonTransferData.swift
//
//
// Created by Grigory on 11.7.23..
//

import Foundation
import BigInt

struct JettonTransferData: CellCodable {
let queryId: UInt64
let amount: BigUInt
let toAddress: Address
let responseAddress: Address
let forwardAmount: BigUInt
let comment: String?

func storeTo(builder: Builder) throws {
try builder.store(uint: 0xf8a7ea5, bits: 32)
try builder.store(uint: queryId, bits: 64)
try builder.store(coins: Coins(amount.magnitude))
try builder.store(AnyAddress(toAddress))
try builder.store(AnyAddress(responseAddress))
try builder.store(bit: false)
try builder.store(coins: Coins(forwardAmount.magnitude))
var commentCell: Cell?
if let comment = comment {
commentCell = try Builder().store(int: 0, bits: 32).writeSnakeData(Data(comment.utf8)).endCell()
}
try builder.store(bit: commentCell != nil)
try builder.storeMaybe(ref: commentCell)
}

static func loadFrom(slice: Slice) throws -> JettonTransferData {
_ = try slice.loadUint(bits: 32)
let queryId = try slice.loadUint(bits: 64)
let amount = try slice.loadCoins().amount
let toAddress: Address = try slice.loadType()
let responseAddress: Address = try slice.loadType()
try slice.skip(1)
let forwardAmount = try slice.loadCoins().amount

let hasComment = try slice.loadBoolean()
var comment: String?
if hasComment, let commentCell = try slice.loadMaybeRef() {
let slice = try commentCell.toSlice()
try slice.skip(32)
comment = try slice.loadSnakeString()
}

return JettonTransferData(queryId: queryId,
amount: amount,
toAddress: toAddress,
responseAddress: responseAddress,
forwardAmount: forwardAmount,
comment: comment)
}
}
34 changes: 34 additions & 0 deletions Source/TonSwift/Jettons/JettonTransferMessage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// JettonTransferMessage.swift
//
//
// Created by Grigory on 11.7.23..
//

import Foundation
import BigInt

public struct JettonTransferMessage {
public static func internalMessage(jettonAddress: Address,
amount: BigInt,
to: Address,
from: Address,
comment: String? = nil) throws -> MessageRelaxed {
let forwardAmount = BigUInt(stringLiteral: "1")
let jettonTransferAmount = BigUInt(stringLiteral: "640000000")
let queryId = UInt64(Date().timeIntervalSince1970)

let jettonTransferData = JettonTransferData(queryId: queryId,
amount: amount.magnitude,
toAddress: to,
responseAddress: from,
forwardAmount: forwardAmount,
comment: comment)

return MessageRelaxed.internal(
to: jettonAddress,
value: jettonTransferAmount,
body: try Builder().store(jettonTransferData).endCell()
)
}
}
8 changes: 7 additions & 1 deletion Source/TonSwift/Keys/KeyPair.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@

import Foundation

public struct KeyPair {
public struct KeyPair: Codable {
public let publicKey: PublicKey
public let privateKey: PrivateKey

public init(publicKey: PublicKey,
privateKey: PrivateKey) {
self.publicKey = publicKey
self.privateKey = privateKey
}
}
2 changes: 1 addition & 1 deletion Source/TonSwift/Keys/PrivateKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

public struct PrivateKey: Key, Equatable {
public struct PrivateKey: Key, Equatable, Codable {
public let data: Data

public init(data: Data) {
Expand Down
2 changes: 1 addition & 1 deletion Source/TonSwift/Keys/PublicKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

public struct PublicKey: Key {
public struct PublicKey: Key, Codable {
public let data: Data

public init(data: Data) {
Expand Down
48 changes: 48 additions & 0 deletions Source/TonSwift/NFT/NFTTransferData.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// NFTTransferData.swift
//
//
// Created by Grigory on 25.8.23..
//

import Foundation
import BigInt

struct NFTTransferData: CellCodable {
let queryId: UInt64
let newOwnerAddress: Address
let responseAddress: Address
let forwardAmount: BigUInt
let forwardPayload: Cell?

func storeTo(builder: Builder) throws {
try builder.store(uint: 0x5fcc3d14, bits: 32) // transfer op
try builder.store(uint: queryId, bits: 64)
try builder.store(AnyAddress(newOwnerAddress))
try builder.store(AnyAddress(responseAddress))
try builder.store(bit: false) // null custom_payload
try builder.store(coins: Coins(forwardAmount.magnitude))
try builder.store(bit: forwardPayload != nil) // forward_payload in this slice - false, separate cell - true
try builder.storeMaybe(ref: forwardPayload)
}

static func loadFrom(slice: Slice) throws -> NFTTransferData {
try slice.skip(32)
let queryId = try slice.loadUint(bits: 64)
let newOwnerAddress: Address = try slice.loadType()
let responseAddress: Address = try slice.loadType()
try slice.skip(1)
let forwardAmount = try slice.loadCoins().amount
let hasPayloadCell = try slice.loadBoolean()
var forwardPayload: Cell?
if hasPayloadCell, let payloadCell = try slice.loadMaybeRef() {
forwardPayload = payloadCell
}
return NFTTransferData(
queryId: queryId,
newOwnerAddress: newOwnerAddress,
responseAddress: responseAddress,
forwardAmount: forwardAmount,
forwardPayload: forwardPayload)
}
}
32 changes: 32 additions & 0 deletions Source/TonSwift/NFT/NFTTransferMessage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// NFTTransferMessage.swift
//
//
// Created by Grigory on 25.8.23..
//

import Foundation
import BigInt

public struct NFTTransferMessage {
public static func internalMessage(nftAddress: Address,
nftTransferAmount: BigUInt,
to: Address,
from: Address,
forwardPayload: Cell?) throws -> MessageRelaxed {
let forwardAmount = BigUInt(stringLiteral: "1")
let queryId = UInt64(Date().timeIntervalSince1970)

let nftTransferData = NFTTransferData(
queryId: queryId,
newOwnerAddress: to,
responseAddress: from,
forwardAmount: forwardAmount,
forwardPayload: forwardPayload)

return MessageRelaxed.internal(
to: nftAddress,
value: nftTransferAmount,
body: try Builder().store(nftTransferData).endCell())
}
}
2 changes: 1 addition & 1 deletion Source/TonSwift/Util/SHA256.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import CommonCrypto
import Foundation

extension Data {
func sha256() -> Self {
public func sha256() -> Self {
var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
withUnsafeBytes {
_ = CC_SHA256($0.baseAddress, CC_LONG(count), &hash)
Expand Down
53 changes: 53 additions & 0 deletions Tests/TonSwiftTests/Jettons/JettonTransferDataTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// JettonTransferDataTests.swift
//
//
// Created by Grigory on 12.7.23..
//

import XCTest
import BigInt
@testable import TonSwift

final class JettonTransferDataTests: XCTestCase {

private var transferJettonData: JettonTransferData {
let queryId: UInt64 = 543
let amount = BigUInt(stringLiteral: "63546")
let toAddress = Address.mock(workchain: 0, seed: "toAddressSeed")
let responseAddress = Address.mock(workchain: 0, seed: "responseAddressSeed")
let forwardAmount = BigUInt(stringLiteral: "789")
let comment = "Hello, this is a comment"

return JettonTransferData(queryId: queryId,
amount: amount,
toAddress: toAddress,
responseAddress: responseAddress,
forwardAmount: forwardAmount,
comment: comment)
}

func testJettonTransferDataEncodeAndDecode() throws {
let builder = Builder()
let transferJettonDataCell = try builder.store(transferJettonData).endCell()
let decodedJettonTransferData: JettonTransferData = try Slice(cell: transferJettonDataCell).loadType()

XCTAssertEqual(transferJettonData.queryId, decodedJettonTransferData.queryId)
XCTAssertEqual(transferJettonData.amount, decodedJettonTransferData.amount)
XCTAssertEqual(transferJettonData.toAddress, decodedJettonTransferData.toAddress)
XCTAssertEqual(transferJettonData.responseAddress, decodedJettonTransferData.responseAddress)
XCTAssertEqual(transferJettonData.forwardAmount, decodedJettonTransferData.forwardAmount)
XCTAssertEqual(transferJettonData.comment, decodedJettonTransferData.comment )
}

func testJettonTransferDataEncode() throws {
let builder = Builder()
let transferJettonDataCell = try builder.store(transferJettonData).endCell()

XCTAssertEqual(try transferJettonDataCell.toString(),
"""
x{0F8A7EA5000000000000021F2F83A8011740C74E876FBD00C1F39161C9DF68563FC469A730CBF932D464EB819239084F001AAD4BD6DAA342C7D03C496083C01AEC31F1A457B8C993C62823E3713E11FD8184062BC_}
x{0000000048656C6C6F2C2074686973206973206120636F6D6D656E74}
""")
}
}
61 changes: 61 additions & 0 deletions Tests/TonSwiftTests/NFT/NFTTransferDataTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//
// NFTTransferDataTests.swift
//
//
// Created by Grigory on 25.8.23..
//

import XCTest
import BigInt
@testable import TonSwift

final class NFTTransferDataTests: XCTestCase {

private var nftTransferData: NFTTransferData {
get throws {
let queryId: UInt64 = 543
let newOwnerAddress = Address.mock(
workchain: 0,
seed: "newOwnerAddressSeed"
)
let responseAddress = Address.mock(
workchain: 0,
seed: "responseAddressSeed"
)
let forwardAmount = BigUInt(stringLiteral: "05000000")
let comment = "Hello, this is a comment"
let commentCell = try Builder()
.store(int: 0, bits: 32)
.writeSnakeData(Data(comment.utf8)).endCell()

return NFTTransferData(queryId: queryId,
newOwnerAddress: newOwnerAddress,
responseAddress: responseAddress,
forwardAmount: forwardAmount,
forwardPayload: commentCell)
}
}

func testJettonTransferDataEncodeAndDecode() throws {
let builder = Builder()
let nftTransferDataCell = try builder.store(nftTransferData).endCell()
let decodedNFTTransferData: NFTTransferData = try Slice(cell: nftTransferDataCell).loadType()

XCTAssertEqual(try nftTransferData.queryId, decodedNFTTransferData.queryId)
XCTAssertEqual(try nftTransferData.newOwnerAddress, decodedNFTTransferData.newOwnerAddress)
XCTAssertEqual(try nftTransferData.responseAddress, decodedNFTTransferData.responseAddress)
XCTAssertEqual(try nftTransferData.forwardAmount, decodedNFTTransferData.forwardAmount)
XCTAssertEqual(try nftTransferData.forwardPayload, decodedNFTTransferData.forwardPayload)
}

func testJettonTransferDataEncode() throws {
let builder = Builder()
let nftTransferDataCell = try builder.store(try nftTransferData).endCell()

XCTAssertEqual(try nftTransferDataCell.toString(),
"""
x{5FCC3D14000000000000021F8006E2451A5FF8C5BEA1DC8505A789427312E714E1783A8DEBF2573D06BADDAD571001AAD4BD6DAA342C7D03C496083C01AEC31F1A457B8C993C62823E3713E11FD8186989681C_}
x{0000000048656C6C6F2C2074686973206973206120636F6D6D656E74}
""")
}
}

0 comments on commit 49636b0

Please sign in to comment.