Skip to content

Commit

Permalink
Merge pull request #57 from sCrypt-Inc/fix_p2p2h_transfer
Browse files Browse the repository at this point in the history
Fix #56 p2p2h transfer
  • Loading branch information
zhfnjust authored Dec 12, 2023
2 parents ae610b2 + d606163 commit ac4ad10
Show file tree
Hide file tree
Showing 20 changed files with 269 additions and 68 deletions.
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "scrypt-ord",
"version": "1.0.13",
"version": "1.0.14",
"description": "A sCrypt office 1Sats Ordinals SDK.",
"main": "dist/index.js",
"types": "src/index.ts",
Expand Down Expand Up @@ -31,7 +31,7 @@
},
"dependencies": {
"@types/superagent": "^4.1.20",
"scrypt-ts": "^1.3.17",
"scrypt-ts": "^1.3.20",
"scrypt-ts-lib": "^0.1.23"
},
"devDependencies": {
Expand Down
21 changes: 17 additions & 4 deletions src/contracts/bsv20V1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,10 @@ export abstract class BSV20V1 extends SmartContract {
tick: ByteString,
amt: bigint
): ByteString {
return BSV20V1.createTransferInsciption(tick, amt) +
return (
BSV20V1.createTransferInsciption(tick, amt) +
Utils.buildPublicKeyHashScript(address)
)
}

@method()
Expand Down Expand Up @@ -136,6 +138,8 @@ export abstract class BSV20V1 extends SmartContract {
throw new Error(`no utxo found for address: ${address}`)
}

const feePerKb = (await this.provider?.getFeePerKb()) as number

const deployTx = new bsv.Transaction()
.from(utxos)
.addOutput(
Expand All @@ -151,6 +155,7 @@ export abstract class BSV20V1 extends SmartContract {
satoshis: 1,
})
)
.feePerKb(feePerKb)
.change(address)

return this.signer.signAndsendTransaction(deployTx)
Expand Down Expand Up @@ -195,9 +200,9 @@ export abstract class BSV20V1 extends SmartContract {
| FTReceiver
const tokenChangeAmt = Array.isArray(recipients)
? current.getAmt() -
recipients.reduce((acc, receiver) => {
return (acc += receiver.amt)
}, 0n)
recipients.reduce((acc, receiver) => {
return (acc += receiver.amt)
}, 0n)
: current.getAmt() - recipients.amt
if (tokenChangeAmt < 0n) {
throw new Error(`Not enough tokens`)
Expand Down Expand Up @@ -270,6 +275,8 @@ export abstract class BSV20V1 extends SmartContract {
})
}

const feePerKb = await current.provider?.getFeePerKb()
tx.feePerKb(feePerKb as number)
tx.change(changeAddress)

if (options.sequence !== undefined) {
Expand Down Expand Up @@ -340,4 +347,10 @@ export abstract class BSV20V1 extends SmartContract {
)
return instance as T
}

override next(opt?: { refCloneProps?: string[] }): this {
const cloned = super.next(opt)
cloned.prependNOPScript(this.getPrependNOPScript())
return cloned
}
}
39 changes: 30 additions & 9 deletions src/contracts/bsv20V1P2PKH.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,26 @@ export class BSV20V1P2PKH extends BSV20V1 {
return bsv20Utxos.map((utxo) => BSV20V1P2PKH.fromUTXO(utxo))
}

/**
* Transfer BSV20 tokens which held by multiple BSV20V1P2PKH instances
* @param senders BSV20V1P2PKH instances
* @param feeSigner used to sign UTXOs that pay transaction fees
* @param receivers token receiving contract
* @param tokenChangeAddress Token change address
* @param sendersPubkey The sender’s public key. By default, the default public key of the Signer connected to BSV20V1P2PKH is used.
* @returns
*/
static async transfer(
senders: Array<BSV20V1P2PKH>,
signer: Signer,
receivers: Array<FTReceiver>
feeSigner: Signer,
receivers: Array<FTReceiver>,
tokenChangeAddress: bsv.Address,
sendersPubkey?: Array<bsv.PublicKey>
) {
const ordPubKey = await signer.getDefaultPubKey()
if (!senders.every((sender) => sender.tick === senders[0].tick)) {
throw new Error('The tick of all senders must be the same!')
}
sendersPubkey = sendersPubkey || []

const totalTokenAmt = senders.reduce((acc, sender) => {
acc += BigInt(sender.getAmt())
Expand Down Expand Up @@ -247,7 +261,7 @@ export class BSV20V1P2PKH extends BSV20V1 {
senders[0].max,
senders[0].lim,
senders[0].dec,
Addr(ordPubKey.toAddress().toByteString())
Addr(tokenChangeAddress.toByteString())
)

p2pkh.setAmt(tokenChangeAmt)
Expand All @@ -266,7 +280,11 @@ export class BSV20V1P2PKH extends BSV20V1 {
})
}

tx.change(ordPubKey.toAddress())
const bsvAddress = await feeSigner.getDefaultAddress()

const feePerKb = await feeSigner.provider?.getFeePerKb()
tx.feePerKb(feePerKb as number)
tx.change(bsvAddress)

for (let i = 0; i < senders.length; i++) {
const p2pkh = senders[i]
Expand All @@ -290,17 +308,20 @@ export class BSV20V1P2PKH extends BSV20V1 {
}
)

const pubkey =
sendersPubkey[i] || (await p2pkh.signer.getDefaultPubKey())

await p2pkh.methods.unlock(
(sigResps: SignatureResponse[]) => findSig(sigResps, ordPubKey),
PubKey(ordPubKey.toByteString()),
(sigResps: SignatureResponse[]) => findSig(sigResps, pubkey),
PubKey(pubkey.toByteString()),
{
transfer: [],
partialContractTx: {
tx: tx,
atInputIndex: 0,
nexts: [],
},
pubKeyOrAddrToSign: ordPubKey,
pubKeyOrAddrToSign: pubkey,
multiContractCall: true,
} as OrdiMethodCallOptions<BSV20V1P2PKH>
)
Expand All @@ -312,7 +333,7 @@ export class BSV20V1P2PKH extends BSV20V1 {
atInputIndex: 0,
nexts: nexts,
},
signer
feeSigner
)
}
}
Expand Down
18 changes: 14 additions & 4 deletions src/contracts/bsv20V2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,10 @@ export abstract class BSV20V2 extends SmartContract {
id: ByteString,
amt: bigint
): ByteString {
return BSV20V2.createTransferInsciption(id, amt) +
return (
BSV20V2.createTransferInsciption(id, amt) +
Utils.buildPublicKeyHashScript(address)
)
}

@method()
Expand Down Expand Up @@ -186,9 +188,9 @@ export abstract class BSV20V2 extends SmartContract {
| FTReceiver
const tokenChangeAmt = Array.isArray(recipients)
? current.getAmt() -
recipients.reduce((acc, receiver) => {
return (acc += receiver.amt)
}, 0n)
recipients.reduce((acc, receiver) => {
return (acc += receiver.amt)
}, 0n)
: current.getAmt() - recipients.amt
if (tokenChangeAmt < 0n) {
throw new Error(`Not enough tokens`)
Expand Down Expand Up @@ -261,6 +263,8 @@ export abstract class BSV20V2 extends SmartContract {
})
}

const feePerKb = await current.provider?.getFeePerKb()
tx.feePerKb(feePerKb as number)
tx.change(changeAddress)

if (options.sequence !== undefined) {
Expand Down Expand Up @@ -306,4 +310,10 @@ export abstract class BSV20V2 extends SmartContract {
instance.from = utxo
return instance
}

override next(opt?: { refCloneProps?: string[] }): this {
const cloned = super.next(opt)
cloned.prependNOPScript(this.getPrependNOPScript())
return cloned
}
}
42 changes: 33 additions & 9 deletions src/contracts/bsv20V2P2PKH.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,31 @@ export class BSV20V2P2PKH extends BSV20V2 {
return bsv20Utxos.map((utxo) => BSV20V2P2PKH.fromUTXO(utxo))
}

/**
* Transfer BSV20 tokens which held by multiple BSV20V2P2PKH instances
* @param senders BSV20V2P2PKH instances
* @param feeSigner used to sign UTXOs that pay transaction fees
* @param receivers token receiving contract
* @param tokenChangeAddress Token change address
* @param sendersPubkey The sender’s public key. By default, the default public key of the Signer connected to BSV20V2P2PKH is used.
* @returns
*/
static async transfer(
senders: Array<BSV20V2P2PKH>,
signer: Signer,
receivers: Array<FTReceiver>
feeSigner: Signer,
receivers: Array<FTReceiver>,
tokenChangeAddress: bsv.Address,
sendersPubkey?: Array<bsv.PublicKey>
) {
const ordPubKey = await signer.getDefaultPubKey()
if (
!senders.every(
(sender) => sender.getTokenId() === senders[0].getTokenId()
)
) {
throw new Error('The TokenId of all senders must be the same!')
}

sendersPubkey = sendersPubkey || []

const totalTokenAmt = senders.reduce((acc, sender) => {
acc += BigInt(sender.getAmt())
Expand Down Expand Up @@ -275,7 +294,7 @@ export class BSV20V2P2PKH extends BSV20V2 {
sym,
senders[0].max,
senders[0].dec,
Addr(ordPubKey.toAddress().toByteString())
Addr(tokenChangeAddress.toByteString())
)

p2pkh.setAmt(tokenChangeAmt)
Expand All @@ -294,7 +313,10 @@ export class BSV20V2P2PKH extends BSV20V2 {
})
}

tx.change(ordPubKey.toAddress())
const bsvAddress = await feeSigner.getDefaultAddress()
const feePerKb = await feeSigner.provider?.getFeePerKb()
tx.feePerKb(feePerKb as number)
tx.change(bsvAddress)

for (let i = 0; i < senders.length; i++) {
const p2pkh = senders[i]
Expand All @@ -318,18 +340,20 @@ export class BSV20V2P2PKH extends BSV20V2 {
throw new Error('No partialContractTx found!')
}
)
const pubkey =
sendersPubkey[i] || (await p2pkh.signer.getDefaultPubKey())

await p2pkh.methods.unlock(
(sigResps: SignatureResponse[]) => findSig(sigResps, ordPubKey),
PubKey(toHex(ordPubKey)),
(sigResps: SignatureResponse[]) => findSig(sigResps, pubkey),
PubKey(pubkey.toByteString()),
{
transfer: [],
partialContractTx: {
tx: tx,
atInputIndex: 0,
nexts: [],
},
pubKeyOrAddrToSign: ordPubKey,
pubKeyOrAddrToSign: pubkey,
multiContractCall: true,
} as OrdiMethodCallOptions<BSV20V2P2PKH>
)
Expand All @@ -341,7 +365,7 @@ export class BSV20V2P2PKH extends BSV20V2 {
atInputIndex: 0,
nexts: nexts,
},
signer
feeSigner
)
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/contracts/ordinalNFT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,12 @@ export abstract class OrdinalNFT extends SmartContract {
balance: 1,
atOutputIndex: nexts.length,
})
} else {
throw new Error('No NFTReceiver found!')
}

const feePerKb = await current.provider?.getFeePerKb()
tx.feePerKb(feePerKb as number)
tx.change(changeAddress)

if (options.sequence !== undefined) {
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export type NFTReceiver = SmartContract

export interface OrdiMethodCallOptions<T extends SmartContract>
extends MethodCallOptions<T> {
transfer: Array<FTReceiver> | FTReceiver | NFTReceiver
transfer?: Array<FTReceiver> | FTReceiver | NFTReceiver
tokenChangeAddress?: bsv.Address
skipTokenChange?: boolean
}
3 changes: 3 additions & 0 deletions tests/contracts/counterNFT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ export class CounterNFT extends OrdinalNFT {
const nextInstance = current.next()
nextInstance.incCounter()

const feePerKb = await current.provider?.getFeePerKb()

const tx = new bsv.Transaction()
.addInput(current.buildContractInput())
.addOutput(
Expand All @@ -95,6 +97,7 @@ export class CounterNFT extends OrdinalNFT {
satoshis: current.balance,
})
)
.feePerKb(feePerKb as number)
.change(options.changeAddress || defaultAddress)

return {
Expand Down
Loading

0 comments on commit ac4ad10

Please sign in to comment.