Skip to content

Commit

Permalink
Merge pull request #146 from keefertaylor/fix-token-contract
Browse files Browse the repository at this point in the history
Upgrade `TokenContractClient` to use the FA1.2 Token Specification
  • Loading branch information
keefertaylor authored Jan 20, 2020
2 parents a4b03a3 + 9018255 commit d63c378
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 23 deletions.
28 changes: 25 additions & 3 deletions Tests/IntegrationTests/Dexter/TokenContractIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import XCTest
///
/// Before running the tests, you should make sure that there's sufficient tokens in the owners account (which is
/// tz1XVJ8bZUXs7r5NV8dHvuiBhzECvLRLR3jW) in the token contract at:
/// Token Contract: https://alphanet.tzscan.io/KT1PARMPddZ9WD1MPmPthXYBCgErmxAHKBD8
/// Address: https://alphanet.tzscan.io/tz1XVJ8bZUXs7r5NV8dHvuiBhzECvLRLR3jW
/// Token Contract: https://better-call.dev/babylon/KT1U3cebEK95hbkg574qin45jLARg5PEV4yr
/// Address: https://babylonnet.tzstats.com/tz1XVJ8bZUXs7r5NV8dHvuiBhzECvLRLR3jW

extension Address {
public static let tokenContractAddress = "KT1LKSFTrGSDNfVbWV4JXRrqGRD8XDSv5NAU"
public static let tokenContractAddress = "KT1U3cebEK95hbkg574qin45jLARg5PEV4yr"
public static let tokenRecipient = "tz1XarY7qEahQBipuuNZ4vPw9MN6Ldyxv8G3"
}

Expand Down Expand Up @@ -63,6 +63,28 @@ class TokenContractClientIntegrationTests: XCTestCase {
wait(for: [ completionExpectation ], timeout: .expectationTimeout)
}

public func testApproveAllowanceTokens() {
let completionExpectation = XCTestExpectation(description: "Completion called")

tokenContractClient.approveAllowance(
source: Wallet.tokenOwner.address,
spender: Address.tokenRecipient,
allowance: 1,
signatureProvider: Wallet.tokenOwner
) { result in
switch result {
case .success(let hash):
print(hash)
completionExpectation.fulfill()
case .failure(let error):
print(error)
XCTFail()
}
}

wait(for: [ completionExpectation ], timeout: .expectationTimeout)
}

public func testGetBalance() {
let completionExpectation = XCTestExpectation(description: "Completion called")

Expand Down
12 changes: 6 additions & 6 deletions TezosKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
1283CBD6F35544031013F520 /* ConseilEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C935B8FA02AA0F4D639B200 /* ConseilEntity.swift */; };
142AB23ED4D91C70AF3695C1 /* OperationWithCounterTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274E2A45E6EB2DCA9A6D1E3F /* OperationWithCounterTest.swift */; };
150BC04519380FB34ABE25AF /* OperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB59AEAEB019E7B641B448B1 /* OperationFactory.swift */; };
154FD7E8B299099904F4FD66 /* GetBigMapValueByID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45DC175F77A75BF249FD6180 /* GetBigMapValueByID.swift */; };
156B321DCC4509F69AFDFEEE /* OperationFeePolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 207E6BD1F08A190CAD16F7AA /* OperationFeePolicy.swift */; };
1625E43AF077065705ADBFFD /* GetProposalsListRPC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C714AAB4A35FE0C6B5BEB154 /* GetProposalsListRPC.swift */; };
1687014ACB8A3903AAEA3BFE /* GetBigMapValueByIDRPC.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC366A9719F3F6D07093E37 /* GetBigMapValueByIDRPC.swift */; };
17502DA144CE9470DAEB95AA /* NetworkClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E212CD2F0656857B66156D04 /* NetworkClient.swift */; };
17A22163503974F022A7BC47 /* TestObjects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F1D1F6B1DDF04EB174551D3 /* TestObjects.swift */; };
181ADCB55F2BE6E20455E914 /* GetBallotsListRPCTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99377915F3FBFFD013D5DEA1 /* GetBallotsListRPCTest.swift */; };
Expand Down Expand Up @@ -88,6 +88,7 @@
34473DC68AF5DC541FC41AD8 /* SipHash.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 737132D7F972BD110818F565 /* SipHash.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
346B3C1348BED784D82EF921 /* OperationWithCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04781056C289A009489C072C /* OperationWithCounter.swift */; };
34E43B75D92CE9FE2726F960 /* ConseilClientIntegrationTests+Promises.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B2484FD06C8D95BB5ACDCC /* ConseilClientIntegrationTests+Promises.swift */; };
35079BDCFCAA9CC2FF318C53 /* GetBigMapValueByIDRPC.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC366A9719F3F6D07093E37 /* GetBigMapValueByIDRPC.swift */; };
3591C65A03D45513CC06B457 /* AbstractOperationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD5FAF254AF66B1A805ABF27 /* AbstractOperationTest.swift */; };
3698330EA50903CD0AEEC185 /* Hex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6067C4058BC42C52B64AF93A /* Hex.swift */; };
369AFABBC4DC7B34F4122FE7 /* GetAddressCounterRPC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF147FA8F9FDDEBA70FA2759 /* GetAddressCounterRPC.swift */; };
Expand Down Expand Up @@ -281,7 +282,6 @@
A5BA4DFA80A9734ED61F1BC6 /* InjectOperationRPCTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4090B8A708287039DE6178F4 /* InjectOperationRPCTest.swift */; };
A78894097ED7DAEF4506FFDE /* RunOperationPayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E029B048FAFC8D60F794D0 /* RunOperationPayload.swift */; };
A88030B456653F6A73CC5077 /* DexterExchangeClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274BAF5E1A4B223F09042484 /* DexterExchangeClientTests.swift */; };
AA3BDE0C47B0E314CC7C7A52 /* GetBigMapValueByID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45DC175F77A75BF249FD6180 /* GetBigMapValueByID.swift */; };
AA82E884F2075A30018067CC /* DexterExchangeClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274BAF5E1A4B223F09042484 /* DexterExchangeClientTests.swift */; };
AB844D81BBE08DCFBD9FFF79 /* ForgingPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99191D08E7D0F08C52254D6B /* ForgingPolicy.swift */; };
ABAB89B9D4772B56744185DA /* GetReceivedTransactions.RPC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0675B789B9F5EF98BC4E4568 /* GetReceivedTransactions.RPC.swift */; };
Expand Down Expand Up @@ -601,7 +601,6 @@
407B756EB7320CC968E1C2ED /* GetProposalUnderEvaluationRPC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetProposalUnderEvaluationRPC.swift; sourceTree = "<group>"; };
4090B8A708287039DE6178F4 /* InjectOperationRPCTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InjectOperationRPCTest.swift; sourceTree = "<group>"; };
443F94AEAF2C38E5B751E7EC /* InjectionServiceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InjectionServiceTest.swift; sourceTree = "<group>"; };
45DC175F77A75BF249FD6180 /* GetBigMapValueByID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetBigMapValueByID.swift; sourceTree = "<group>"; };
47259C26A53DB562B22F087B /* CodingUtilTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodingUtilTest.swift; sourceTree = "<group>"; };
4C935B8FA02AA0F4D639B200 /* ConseilEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConseilEntity.swift; sourceTree = "<group>"; };
4E006B0AA63CD2D50D07762F /* GetExpectedQuorumRPC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetExpectedQuorumRPC.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -704,6 +703,7 @@
BCD4318870B3E4FE3F27C60D /* Sodium.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Sodium.framework; sourceTree = "<group>"; };
BCF068374D26E5AD6CE93407 /* TezResponseAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TezResponseAdapter.swift; sourceTree = "<group>"; };
BF24BCDA4254C7A2D50F5728 /* ConseilQueryRPC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConseilQueryRPC.swift; sourceTree = "<group>"; };
BFC366A9719F3F6D07093E37 /* GetBigMapValueByIDRPC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetBigMapValueByIDRPC.swift; sourceTree = "<group>"; };
C1968AE0A3A2B4DAD756FD72 /* ConseilClientIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConseilClientIntegrationTests.swift; sourceTree = "<group>"; };
C1FCF6EFDB51394D49E1479C /* PreapplicationServiceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreapplicationServiceTest.swift; sourceTree = "<group>"; };
C525A21D32496E9B7BB4F79A /* GetAddressCounterRPCTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetAddressCounterRPCTest.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1271,7 +1271,7 @@
B01627EE910CBE5821502281 /* GetAddressManagerKeyRPC.swift */,
7DF606714D021D4EFFA07E6A /* GetBallotsListRPC.swift */,
B84952454AD66BD8E378047D /* GetBallotsRPC.swift */,
45DC175F77A75BF249FD6180 /* GetBigMapValueByID.swift */,
BFC366A9719F3F6D07093E37 /* GetBigMapValueByIDRPC.swift */,
F0577D28D7A8761465FE76F9 /* GetBigMapValueRPC.swift */,
CCEA4823FE108BF24AC51A10 /* GetChainHeadHashRPC.swift */,
38FFC7595908A6BC3424370C /* GetChainHeadRPC.swift */,
Expand Down Expand Up @@ -1648,7 +1648,7 @@
26684AB4366572B8B2CD89D5 /* GetAddressManagerKeyRPC.swift in Sources */,
19BF852742C7D35BD097808B /* GetBallotsListRPC.swift in Sources */,
69D1108BBFEF81261566FF65 /* GetBallotsRPC.swift in Sources */,
154FD7E8B299099904F4FD66 /* GetBigMapValueByID.swift in Sources */,
1687014ACB8A3903AAEA3BFE /* GetBigMapValueByIDRPC.swift in Sources */,
F9BE3DBB7109326574DD8821 /* GetBigMapValueRPC.swift in Sources */,
A119F0B0B84DED49D2BDF2A0 /* GetChainHeadHashRPC.swift in Sources */,
0CD4F987EE82D3CEA1D6FD07 /* GetChainHeadRPC.swift in Sources */,
Expand Down Expand Up @@ -1853,7 +1853,7 @@
565974251F53ED2304F67976 /* GetAddressManagerKeyRPC.swift in Sources */,
E99BFF3E63A3086672E2E46D /* GetBallotsListRPC.swift in Sources */,
21DFB6D5F1C38A65473294A4 /* GetBallotsRPC.swift in Sources */,
AA3BDE0C47B0E314CC7C7A52 /* GetBigMapValueByID.swift in Sources */,
35079BDCFCAA9CC2FF318C53 /* GetBigMapValueByIDRPC.swift in Sources */,
BCE3F98F723E8ED5400723A1 /* GetBigMapValueRPC.swift in Sources */,
C59529A854409FB4806D2369 /* GetChainHeadHashRPC.swift in Sources */,
2699AF538FEBA53B91818459 /* GetChainHeadRPC.swift in Sources */,
Expand Down
6 changes: 4 additions & 2 deletions TezosKit/Common/Services/NetworkClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,11 @@ public class NetworkClientImpl: NetworkClient {
let remoteNodeEndpoint = remoteNodeURL.appendingPathComponent(rpc.endpoint)
var urlRequest = URLRequest(url: remoteNodeEndpoint)

if rpc.isPOSTRequest,
if
rpc.isPOSTRequest,
let payload = rpc.payload,
let payloadData = payload.data(using: .utf8) {
let payloadData = payload.data(using: .utf8)
{
urlRequest.httpMethod = "POST"
urlRequest.cachePolicy = .reloadIgnoringCacheData
urlRequest.httpBody = payloadData
Expand Down
61 changes: 49 additions & 12 deletions TezosKit/Dexter/TokenContractClient.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
// Copyright Keefer Taylor, 2019.

/// A client for a token contract.
/// A client for an FA1.2 Token Contract.
///
/// - See: https://gitlab.com/camlcase-dev/dexter
/// - See: https://gitlab.com/tzip/tzip/tree/master/proposals/tzip-7
public class TokenContractClient {
private enum EntryPoint {
public static let approve = "approve"
public static let transfer = "transfer"
}

private enum JSON {
public enum Keys {
public static let args = "args"
Expand Down Expand Up @@ -49,20 +54,52 @@ public class TokenContractClient {
completion: @escaping (Result<String, TezosKitError>) -> Void
) {
let amount = Tez.zeroBalance
let michelsonParameter = LeftMichelsonParameter(
arg: PairMichelsonParameter(
let parameter = PairMichelsonParameter(
left: PairMichelsonParameter(
left: StringMichelsonParameter(string: source),
right: PairMichelsonParameter(
left: StringMichelsonParameter(string: destination),
right: IntMichelsonParameter(int: numTokens)
)
)
right: StringMichelsonParameter(string: destination)
),
right: IntMichelsonParameter(int: numTokens)
)

tezosNodeClient.call(
contract: tokenContractAddress,
amount: amount,
entrypoint: EntryPoint.transfer,
parameter: parameter,
source: source,
signatureProvider: signatureProvider,
operationFeePolicy: .estimate,
completion: completion
)
}

/// Approve an allowance.
///
/// - Parameters:
/// - source: The address initiating the approval.
/// - spender: The address being approved.
/// - allowance: The number of tokens to approve.
/// - signatureProvider: An opaque object that can sign the transaction.
/// - completion: A completion block called with the operation hash or an error.
public func approveAllowance(
source: Address,
spender: Address,
allowance: Int,
signatureProvider: SignatureProvider,
completion: @escaping (Result<String, TezosKitError>) -> Void
) {
let amount = Tez.zeroBalance
let parameter = PairMichelsonParameter(
left: StringMichelsonParameter(string: spender),
right: IntMichelsonParameter(int: allowance)
)

tezosNodeClient.call(
contract: tokenContractAddress,
amount: amount,
parameter: michelsonParameter,
entrypoint: EntryPoint.approve,
parameter: parameter,
source: source,
signatureProvider: signatureProvider,
operationFeePolicy: .estimate,
Expand All @@ -77,8 +114,8 @@ public class TokenContractClient {
guard
case let .success(json) = result,
let args = json[JSON.Keys.args] as? [ Any ],
let firstArg = args.first as? [ String: Any ],
let balanceString = firstArg[JSON.Keys.int] as? String,
let second = args[1] as? [String: Any],
let balanceString = second[JSON.Keys.int] as? String,
let balance = Int(balanceString)
else {
completion(result.map { _ in 0 })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public class SmartContractInvocationOperation: TransactionOperation {
public override func mutableCopy(with zone: NSZone? = nil) -> Any {
return SmartContractInvocationOperation(
amount: amount,
entrypoint: entrypoint,
parameter: parameter,
source: source,
destination: destination,
Expand Down

0 comments on commit d63c378

Please sign in to comment.