@atomiqlabs/chain-evm 1.0.0-dev.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/dist/chains/citrea/CitreaChainType.d.ts +13 -0
- package/dist/chains/citrea/CitreaChainType.js +2 -0
- package/dist/chains/citrea/CitreaInitializer.d.ts +30 -0
- package/dist/chains/citrea/CitreaInitializer.js +120 -0
- package/dist/evm/btcrelay/BtcRelayAbi.d.ts +198 -0
- package/dist/evm/btcrelay/BtcRelayAbi.js +261 -0
- package/dist/evm/btcrelay/BtcRelayTypechain.d.ts +172 -0
- package/dist/evm/btcrelay/BtcRelayTypechain.js +2 -0
- package/dist/evm/btcrelay/EVMBtcRelay.d.ts +188 -0
- package/dist/evm/btcrelay/EVMBtcRelay.js +419 -0
- package/dist/evm/btcrelay/headers/EVMBtcHeader.d.ts +33 -0
- package/dist/evm/btcrelay/headers/EVMBtcHeader.js +84 -0
- package/dist/evm/btcrelay/headers/EVMBtcStoredHeader.d.ts +56 -0
- package/dist/evm/btcrelay/headers/EVMBtcStoredHeader.js +123 -0
- package/dist/evm/chain/EVMChainInterface.d.ts +51 -0
- package/dist/evm/chain/EVMChainInterface.js +90 -0
- package/dist/evm/chain/EVMModule.d.ts +9 -0
- package/dist/evm/chain/EVMModule.js +13 -0
- package/dist/evm/chain/modules/ERC20Abi.d.ts +168 -0
- package/dist/evm/chain/modules/ERC20Abi.js +225 -0
- package/dist/evm/chain/modules/EVMAddresses.d.ts +9 -0
- package/dist/evm/chain/modules/EVMAddresses.js +26 -0
- package/dist/evm/chain/modules/EVMBlocks.d.ts +20 -0
- package/dist/evm/chain/modules/EVMBlocks.js +64 -0
- package/dist/evm/chain/modules/EVMEvents.d.ts +36 -0
- package/dist/evm/chain/modules/EVMEvents.js +122 -0
- package/dist/evm/chain/modules/EVMFees.d.ts +35 -0
- package/dist/evm/chain/modules/EVMFees.js +73 -0
- package/dist/evm/chain/modules/EVMSignatures.d.ts +29 -0
- package/dist/evm/chain/modules/EVMSignatures.js +68 -0
- package/dist/evm/chain/modules/EVMTokens.d.ts +49 -0
- package/dist/evm/chain/modules/EVMTokens.js +105 -0
- package/dist/evm/chain/modules/EVMTransactions.d.ts +89 -0
- package/dist/evm/chain/modules/EVMTransactions.js +216 -0
- package/dist/evm/contract/EVMContractBase.d.ts +22 -0
- package/dist/evm/contract/EVMContractBase.js +34 -0
- package/dist/evm/contract/EVMContractModule.d.ts +8 -0
- package/dist/evm/contract/EVMContractModule.js +11 -0
- package/dist/evm/contract/modules/EVMContractEvents.d.ts +42 -0
- package/dist/evm/contract/modules/EVMContractEvents.js +75 -0
- package/dist/evm/events/EVMChainEvents.d.ts +22 -0
- package/dist/evm/events/EVMChainEvents.js +67 -0
- package/dist/evm/events/EVMChainEventsBrowser.d.ts +86 -0
- package/dist/evm/events/EVMChainEventsBrowser.js +294 -0
- package/dist/evm/spv_swap/EVMSpvVaultContract.d.ts +64 -0
- package/dist/evm/spv_swap/EVMSpvVaultContract.js +410 -0
- package/dist/evm/spv_swap/EVMSpvVaultData.d.ts +38 -0
- package/dist/evm/spv_swap/EVMSpvVaultData.js +159 -0
- package/dist/evm/spv_swap/EVMSpvWithdrawalData.d.ts +19 -0
- package/dist/evm/spv_swap/EVMSpvWithdrawalData.js +55 -0
- package/dist/evm/spv_swap/SpvVaultContractAbi.d.ts +91 -0
- package/dist/evm/spv_swap/SpvVaultContractAbi.js +849 -0
- package/dist/evm/spv_swap/SpvVaultContractTypechain.d.ts +450 -0
- package/dist/evm/spv_swap/SpvVaultContractTypechain.js +2 -0
- package/dist/evm/swaps/EVMSwapContract.d.ts +192 -0
- package/dist/evm/swaps/EVMSwapContract.js +373 -0
- package/dist/evm/swaps/EVMSwapData.d.ts +64 -0
- package/dist/evm/swaps/EVMSwapData.js +254 -0
- package/dist/evm/swaps/EVMSwapModule.d.ts +9 -0
- package/dist/evm/swaps/EVMSwapModule.js +11 -0
- package/dist/evm/swaps/EscrowManagerAbi.d.ts +120 -0
- package/dist/evm/swaps/EscrowManagerAbi.js +985 -0
- package/dist/evm/swaps/EscrowManagerTypechain.d.ts +475 -0
- package/dist/evm/swaps/EscrowManagerTypechain.js +2 -0
- package/dist/evm/swaps/handlers/IHandler.d.ts +13 -0
- package/dist/evm/swaps/handlers/IHandler.js +2 -0
- package/dist/evm/swaps/handlers/claim/ClaimHandlers.d.ts +10 -0
- package/dist/evm/swaps/handlers/claim/ClaimHandlers.js +13 -0
- package/dist/evm/swaps/handlers/claim/HashlockClaimHandler.d.ts +20 -0
- package/dist/evm/swaps/handlers/claim/HashlockClaimHandler.js +39 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.d.ts +24 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.js +59 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.d.ts +25 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.js +51 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.d.ts +21 -0
- package/dist/evm/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.js +28 -0
- package/dist/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.d.ts +48 -0
- package/dist/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.js +63 -0
- package/dist/evm/swaps/handlers/refund/TimelockRefundHandler.d.ts +17 -0
- package/dist/evm/swaps/handlers/refund/TimelockRefundHandler.js +28 -0
- package/dist/evm/swaps/modules/EVMLpVault.d.ts +69 -0
- package/dist/evm/swaps/modules/EVMLpVault.js +131 -0
- package/dist/evm/swaps/modules/EVMSwapClaim.d.ts +53 -0
- package/dist/evm/swaps/modules/EVMSwapClaim.js +101 -0
- package/dist/evm/swaps/modules/EVMSwapInit.d.ts +88 -0
- package/dist/evm/swaps/modules/EVMSwapInit.js +241 -0
- package/dist/evm/swaps/modules/EVMSwapRefund.d.ts +62 -0
- package/dist/evm/swaps/modules/EVMSwapRefund.js +132 -0
- package/dist/evm/typechain/common.d.ts +50 -0
- package/dist/evm/typechain/common.js +2 -0
- package/dist/evm/wallet/EVMSigner.d.ts +9 -0
- package/dist/evm/wallet/EVMSigner.js +16 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +53 -0
- package/dist/utils/Utils.d.ts +15 -0
- package/dist/utils/Utils.js +71 -0
- package/package.json +37 -0
- package/src/chains/citrea/CitreaChainType.ts +28 -0
- package/src/chains/citrea/CitreaInitializer.ts +167 -0
- package/src/evm/btcrelay/BtcRelayAbi.ts +258 -0
- package/src/evm/btcrelay/BtcRelayTypechain.ts +371 -0
- package/src/evm/btcrelay/EVMBtcRelay.ts +517 -0
- package/src/evm/btcrelay/headers/EVMBtcHeader.ts +110 -0
- package/src/evm/btcrelay/headers/EVMBtcStoredHeader.ts +153 -0
- package/src/evm/chain/EVMChainInterface.ts +157 -0
- package/src/evm/chain/EVMModule.ts +21 -0
- package/src/evm/chain/modules/ERC20Abi.ts +222 -0
- package/src/evm/chain/modules/EVMAddresses.ts +24 -0
- package/src/evm/chain/modules/EVMBlocks.ts +75 -0
- package/src/evm/chain/modules/EVMEvents.ts +139 -0
- package/src/evm/chain/modules/EVMFees.ts +105 -0
- package/src/evm/chain/modules/EVMSignatures.ts +76 -0
- package/src/evm/chain/modules/EVMTokens.ts +115 -0
- package/src/evm/chain/modules/EVMTransactions.ts +246 -0
- package/src/evm/contract/EVMContractBase.ts +63 -0
- package/src/evm/contract/EVMContractModule.ts +16 -0
- package/src/evm/contract/modules/EVMContractEvents.ts +102 -0
- package/src/evm/events/EVMChainEvents.ts +81 -0
- package/src/evm/events/EVMChainEventsBrowser.ts +390 -0
- package/src/evm/spv_swap/EVMSpvVaultContract.ts +533 -0
- package/src/evm/spv_swap/EVMSpvVaultData.ts +201 -0
- package/src/evm/spv_swap/EVMSpvWithdrawalData.ts +70 -0
- package/src/evm/spv_swap/SpvVaultContractAbi.ts +846 -0
- package/src/evm/spv_swap/SpvVaultContractTypechain.ts +685 -0
- package/src/evm/swaps/EVMSwapContract.ts +590 -0
- package/src/evm/swaps/EVMSwapData.ts +367 -0
- package/src/evm/swaps/EVMSwapModule.ts +16 -0
- package/src/evm/swaps/EscrowManagerAbi.ts +982 -0
- package/src/evm/swaps/EscrowManagerTypechain.ts +723 -0
- package/src/evm/swaps/handlers/IHandler.ts +17 -0
- package/src/evm/swaps/handlers/claim/ClaimHandlers.ts +20 -0
- package/src/evm/swaps/handlers/claim/HashlockClaimHandler.ts +47 -0
- package/src/evm/swaps/handlers/claim/btc/BitcoinNoncedOutputClaimHandler.ts +82 -0
- package/src/evm/swaps/handlers/claim/btc/BitcoinOutputClaimHandler.ts +76 -0
- package/src/evm/swaps/handlers/claim/btc/BitcoinTxIdClaimHandler.ts +46 -0
- package/src/evm/swaps/handlers/claim/btc/IBitcoinClaimHandler.ts +115 -0
- package/src/evm/swaps/handlers/refund/TimelockRefundHandler.ts +38 -0
- package/src/evm/swaps/modules/EVMLpVault.ts +153 -0
- package/src/evm/swaps/modules/EVMSwapClaim.ts +141 -0
- package/src/evm/swaps/modules/EVMSwapInit.ts +292 -0
- package/src/evm/swaps/modules/EVMSwapRefund.ts +198 -0
- package/src/evm/typechain/common.ts +131 -0
- package/src/evm/wallet/EVMSigner.ts +23 -0
- package/src/index.ts +44 -0
- package/src/utils/Utils.ts +81 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {EVMSwapData} from "../EVMSwapData";
|
|
2
|
+
import {EVMTx} from "../../chain/modules/EVMTransactions";
|
|
3
|
+
|
|
4
|
+
export interface IHandler<TCommitmentData, TWitnessData> {
|
|
5
|
+
|
|
6
|
+
readonly address: string;
|
|
7
|
+
|
|
8
|
+
getCommitment(data: TCommitmentData): string;
|
|
9
|
+
|
|
10
|
+
getWitness(signer: string, data: EVMSwapData, witnessData: TWitnessData, feeRate?: string): Promise<{
|
|
11
|
+
initialTxns: EVMTx[],
|
|
12
|
+
witness: Buffer
|
|
13
|
+
}>;
|
|
14
|
+
|
|
15
|
+
getGas(data: EVMSwapData): number;
|
|
16
|
+
|
|
17
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {HashlockClaimHandler} from "./HashlockClaimHandler";
|
|
2
|
+
import {ChainSwapType} from "@atomiqlabs/base";
|
|
3
|
+
import {IHandler} from "../IHandler";
|
|
4
|
+
import {BitcoinTxIdClaimHandler} from "./btc/BitcoinTxIdClaimHandler";
|
|
5
|
+
import {BitcoinOutputClaimHandler} from "./btc/BitcoinOutputClaimHandler";
|
|
6
|
+
import {BitcoinNoncedOutputClaimHandler} from "./btc/BitcoinNoncedOutputClaimHandler";
|
|
7
|
+
|
|
8
|
+
export interface IClaimHandler<C, W> extends IHandler<C, W> {
|
|
9
|
+
getType(): ChainSwapType;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ClaimHandlerType = {gas: number, type: ChainSwapType} & (new (address: string) => IClaimHandler<any, any>);
|
|
13
|
+
|
|
14
|
+
export const claimHandlersList: ClaimHandlerType[] = [
|
|
15
|
+
HashlockClaimHandler,
|
|
16
|
+
BitcoinTxIdClaimHandler,
|
|
17
|
+
BitcoinOutputClaimHandler,
|
|
18
|
+
BitcoinNoncedOutputClaimHandler
|
|
19
|
+
];
|
|
20
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {ChainSwapType} from "@atomiqlabs/base";
|
|
2
|
+
import {Buffer} from "buffer";
|
|
3
|
+
import {IClaimHandler} from "./ClaimHandlers";
|
|
4
|
+
import {hexlify} from "ethers";
|
|
5
|
+
import {EVMSwapData} from "../../EVMSwapData";
|
|
6
|
+
import {EVMTx} from "../../../chain/modules/EVMTransactions";
|
|
7
|
+
import {sha256} from "@noble/hashes/sha2";
|
|
8
|
+
|
|
9
|
+
export class HashlockClaimHandler implements IClaimHandler<Buffer, string> {
|
|
10
|
+
|
|
11
|
+
public readonly address: string;
|
|
12
|
+
public static readonly type: ChainSwapType = ChainSwapType.HTLC;
|
|
13
|
+
public static readonly gas: number = 5_000;
|
|
14
|
+
|
|
15
|
+
constructor(address: string) {
|
|
16
|
+
this.address = address;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
getCommitment(data: Buffer): string {
|
|
20
|
+
if(data.length!==32) throw new Error("Invalid swap hash");
|
|
21
|
+
return hexlify(data);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public getWitness(signer: string, data: EVMSwapData, witnessData: string): Promise<{
|
|
25
|
+
initialTxns: EVMTx[],
|
|
26
|
+
witness: Buffer
|
|
27
|
+
}> {
|
|
28
|
+
if(!data.isClaimHandler(this.address)) throw new Error("Invalid claim handler");
|
|
29
|
+
if(witnessData.length!==64) throw new Error("Invalid hash secret: string length");
|
|
30
|
+
const buffer = Buffer.from(witnessData, "hex");
|
|
31
|
+
if(buffer.length!==32) throw new Error("Invalid hash secret: buff length");
|
|
32
|
+
|
|
33
|
+
const witnessSha256 = Buffer.from(sha256(buffer));
|
|
34
|
+
if(!data.isClaimData(this.getCommitment(witnessSha256))) throw new Error("Invalid hash secret: poseidon hash doesn't match");
|
|
35
|
+
|
|
36
|
+
return Promise.resolve({initialTxns: [], witness: buffer});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
getGas(): number {
|
|
40
|
+
return HashlockClaimHandler.gas;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
getType(): ChainSwapType {
|
|
44
|
+
return HashlockClaimHandler.type;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {BigIntBufferUtils, ChainSwapType} from "@atomiqlabs/base";
|
|
2
|
+
import {BitcoinCommitmentData, IBitcoinClaimHandler} from "./IBitcoinClaimHandler";
|
|
3
|
+
import {BitcoinOutputWitnessData} from "./BitcoinOutputClaimHandler";
|
|
4
|
+
import {Transaction} from "@scure/btc-signer";
|
|
5
|
+
import {Buffer} from "buffer";
|
|
6
|
+
import {keccak256, solidityPackedKeccak256} from "ethers";
|
|
7
|
+
import {EVMSwapData} from "../../../EVMSwapData";
|
|
8
|
+
import {EVMTx} from "../../../../chain/modules/EVMTransactions";
|
|
9
|
+
|
|
10
|
+
export type BitcoinNoncedOutputCommitmentData = {
|
|
11
|
+
output: Buffer,
|
|
12
|
+
amount: bigint,
|
|
13
|
+
nonce: bigint
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function getTransactionNonce(btcTx: Transaction): bigint {
|
|
17
|
+
const locktimeSub500M = BigInt(btcTx.lockTime - 500000000);
|
|
18
|
+
if(locktimeSub500M < 0n) throw new Error("Locktime too low!");
|
|
19
|
+
const nSequence = BigInt(btcTx.getInput(0).sequence);
|
|
20
|
+
return (locktimeSub500M << 24n) | (nSequence & 0x00FFFFFFn);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class BitcoinNoncedOutputClaimHandler extends IBitcoinClaimHandler<BitcoinNoncedOutputCommitmentData, BitcoinOutputWitnessData> {
|
|
24
|
+
|
|
25
|
+
public static readonly type: ChainSwapType = ChainSwapType.CHAIN_NONCED;
|
|
26
|
+
public static readonly gas: number = 40_000;
|
|
27
|
+
|
|
28
|
+
protected serializeCommitment(data: BitcoinNoncedOutputCommitmentData & BitcoinCommitmentData): Buffer {
|
|
29
|
+
const txoHash = solidityPackedKeccak256(["uint64", "uint64", "bytes32"], [data.nonce, data.amount, keccak256(data.output)]);
|
|
30
|
+
return Buffer.concat([
|
|
31
|
+
Buffer.from(txoHash.substring(2), "hex"),
|
|
32
|
+
super.serializeCommitment(data)
|
|
33
|
+
]);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async getWitness(
|
|
37
|
+
signer: string,
|
|
38
|
+
swapData: EVMSwapData,
|
|
39
|
+
witnessData: BitcoinOutputWitnessData,
|
|
40
|
+
feeRate?: string
|
|
41
|
+
): Promise<{
|
|
42
|
+
initialTxns: EVMTx[];
|
|
43
|
+
witness: Buffer
|
|
44
|
+
}> {
|
|
45
|
+
if(!swapData.isClaimHandler(this.address)) throw new Error("Invalid claim handler");
|
|
46
|
+
|
|
47
|
+
const txBuffer = Buffer.from(witnessData.tx.hex, "hex");
|
|
48
|
+
const parsedBtcTx = Transaction.fromRaw(txBuffer);
|
|
49
|
+
const out = parsedBtcTx.getOutput(witnessData.vout);
|
|
50
|
+
|
|
51
|
+
const {initialTxns, commitment, blockheader, merkleProof} = await this._getWitness(signer, swapData, witnessData, {
|
|
52
|
+
output: Buffer.from(out.script),
|
|
53
|
+
amount: out.amount,
|
|
54
|
+
nonce: getTransactionNonce(parsedBtcTx)
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const voutAndTxData = Buffer.concat([
|
|
58
|
+
BigIntBufferUtils.toBuffer(BigInt(witnessData.vout), "be", 4),
|
|
59
|
+
BigIntBufferUtils.toBuffer(BigInt(txBuffer.length), "be", 32),
|
|
60
|
+
txBuffer
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
initialTxns,
|
|
65
|
+
witness: Buffer.concat([
|
|
66
|
+
commitment,
|
|
67
|
+
blockheader,
|
|
68
|
+
voutAndTxData,
|
|
69
|
+
merkleProof
|
|
70
|
+
])
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getGas(data: EVMSwapData): number {
|
|
75
|
+
return BitcoinNoncedOutputClaimHandler.gas;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getType(): ChainSwapType {
|
|
79
|
+
return BitcoinNoncedOutputClaimHandler.type;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {BigIntBufferUtils, ChainSwapType} from "@atomiqlabs/base";
|
|
2
|
+
import {BitcoinCommitmentData, BitcoinWitnessData, IBitcoinClaimHandler} from "./IBitcoinClaimHandler";
|
|
3
|
+
import {Buffer} from "buffer";
|
|
4
|
+
import {keccak256, solidityPackedKeccak256} from "ethers";
|
|
5
|
+
import {EVMTx} from "../../../../chain/modules/EVMTransactions";
|
|
6
|
+
import {Transaction} from "@scure/btc-signer";
|
|
7
|
+
import {EVMSwapData} from "../../../EVMSwapData";
|
|
8
|
+
|
|
9
|
+
export type BitcoinOutputCommitmentData = {
|
|
10
|
+
output: Buffer,
|
|
11
|
+
amount: bigint
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type BitcoinOutputWitnessData = BitcoinWitnessData & {
|
|
15
|
+
vout: number
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export class BitcoinOutputClaimHandler extends IBitcoinClaimHandler<BitcoinOutputCommitmentData, BitcoinOutputWitnessData> {
|
|
19
|
+
|
|
20
|
+
public static readonly type: ChainSwapType = ChainSwapType.CHAIN;
|
|
21
|
+
public static readonly gas: number = 40_000;
|
|
22
|
+
|
|
23
|
+
protected serializeCommitment(data: BitcoinOutputCommitmentData & BitcoinCommitmentData): Buffer {
|
|
24
|
+
const txoHash = solidityPackedKeccak256(["uint64", "bytes32"], [data.amount, keccak256(data.output)]);
|
|
25
|
+
return Buffer.concat([
|
|
26
|
+
Buffer.from(txoHash.substring(2), "hex"),
|
|
27
|
+
super.serializeCommitment(data)
|
|
28
|
+
]);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async getWitness(
|
|
32
|
+
signer: string,
|
|
33
|
+
swapData: EVMSwapData,
|
|
34
|
+
witnessData: BitcoinOutputWitnessData,
|
|
35
|
+
feeRate?: string
|
|
36
|
+
): Promise<{
|
|
37
|
+
initialTxns: EVMTx[];
|
|
38
|
+
witness: Buffer
|
|
39
|
+
}> {
|
|
40
|
+
if(!swapData.isClaimHandler(this.address)) throw new Error("Invalid claim handler");
|
|
41
|
+
|
|
42
|
+
const txBuffer = Buffer.from(witnessData.tx.hex, "hex");
|
|
43
|
+
const parsedBtcTx = Transaction.fromRaw(txBuffer);
|
|
44
|
+
const out = parsedBtcTx.getOutput(witnessData.vout);
|
|
45
|
+
|
|
46
|
+
const {initialTxns, commitment, blockheader, merkleProof} = await this._getWitness(signer, swapData, witnessData, {
|
|
47
|
+
output: Buffer.from(out.script),
|
|
48
|
+
amount: out.amount
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const voutAndTxData = Buffer.concat([
|
|
52
|
+
BigIntBufferUtils.toBuffer(BigInt(witnessData.vout), "be", 4),
|
|
53
|
+
BigIntBufferUtils.toBuffer(BigInt(txBuffer.length), "be", 32),
|
|
54
|
+
txBuffer
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
initialTxns,
|
|
59
|
+
witness: Buffer.concat([
|
|
60
|
+
commitment,
|
|
61
|
+
blockheader,
|
|
62
|
+
voutAndTxData,
|
|
63
|
+
merkleProof
|
|
64
|
+
])
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getGas(data: EVMSwapData): number {
|
|
69
|
+
return BitcoinOutputClaimHandler.gas;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
getType(): ChainSwapType {
|
|
73
|
+
return BitcoinOutputClaimHandler.type;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {ChainSwapType} from "@atomiqlabs/base";
|
|
2
|
+
import {getLogger} from "../../../../../utils/Utils";
|
|
3
|
+
import {BitcoinCommitmentData, BitcoinWitnessData, IBitcoinClaimHandler} from "./IBitcoinClaimHandler";
|
|
4
|
+
import {Buffer} from "buffer";
|
|
5
|
+
import {EVMSwapData} from "../../../EVMSwapData";
|
|
6
|
+
import {EVMTx} from "../../../../chain/modules/EVMTransactions";
|
|
7
|
+
|
|
8
|
+
export type BitcoinTxIdCommitmentData = {
|
|
9
|
+
txId: string
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export class BitcoinTxIdClaimHandler extends IBitcoinClaimHandler<BitcoinTxIdCommitmentData, BitcoinWitnessData> {
|
|
13
|
+
|
|
14
|
+
public static readonly type: ChainSwapType = ChainSwapType.CHAIN_TXID;
|
|
15
|
+
public static readonly gas: number = 10_000;
|
|
16
|
+
|
|
17
|
+
protected serializeCommitment(data: BitcoinTxIdCommitmentData & BitcoinCommitmentData): Buffer {
|
|
18
|
+
return Buffer.concat([
|
|
19
|
+
Buffer.from(data.txId, "hex").reverse(),
|
|
20
|
+
super.serializeCommitment(data)
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getWitness(
|
|
25
|
+
signer: string,
|
|
26
|
+
swapData: EVMSwapData,
|
|
27
|
+
witnessData: BitcoinWitnessData,
|
|
28
|
+
feeRate?: string
|
|
29
|
+
): Promise<{
|
|
30
|
+
initialTxns: EVMTx[];
|
|
31
|
+
witness: Buffer
|
|
32
|
+
}> {
|
|
33
|
+
if(!swapData.isClaimHandler(this.address)) throw new Error("Invalid claim handler");
|
|
34
|
+
|
|
35
|
+
return this._getWitness(signer, swapData, witnessData, {txId: witnessData.tx.txid});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
getGas(data: EVMSwapData): number {
|
|
39
|
+
return BitcoinTxIdClaimHandler.gas;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
getType(): ChainSwapType {
|
|
43
|
+
return BitcoinTxIdClaimHandler.type;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {IClaimHandler} from "../ClaimHandlers";
|
|
2
|
+
import {BigIntBufferUtils, ChainSwapType, RelaySynchronizer} from "@atomiqlabs/base";
|
|
3
|
+
import {EVMBtcRelay} from "../../../../btcrelay/EVMBtcRelay";
|
|
4
|
+
import { EVMBtcStoredHeader } from "../../../../btcrelay/headers/EVMBtcStoredHeader";
|
|
5
|
+
import {EVMTx} from "../../../../chain/modules/EVMTransactions";
|
|
6
|
+
import {getLogger} from "../../../../../utils/Utils";
|
|
7
|
+
import {keccak256} from "ethers";
|
|
8
|
+
import {Buffer} from "buffer";
|
|
9
|
+
import {EVMSwapData} from "../../../EVMSwapData";
|
|
10
|
+
|
|
11
|
+
export type BitcoinCommitmentData = {
|
|
12
|
+
btcRelay: EVMBtcRelay<any>,
|
|
13
|
+
confirmations: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type BitcoinWitnessData = {
|
|
17
|
+
tx: { blockhash: string, confirmations: number, txid: string, hex: string, height: number },
|
|
18
|
+
requiredConfirmations: number,
|
|
19
|
+
commitedHeader?: EVMBtcStoredHeader,
|
|
20
|
+
btcRelay?: EVMBtcRelay<any>,
|
|
21
|
+
synchronizer?: RelaySynchronizer<EVMBtcStoredHeader, EVMTx, any>
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const logger = getLogger("IBitcoinClaimHandler: ");
|
|
25
|
+
|
|
26
|
+
export abstract class IBitcoinClaimHandler<C, W extends BitcoinWitnessData> implements IClaimHandler<C & BitcoinCommitmentData, W> {
|
|
27
|
+
|
|
28
|
+
public readonly address: string;
|
|
29
|
+
|
|
30
|
+
constructor(address: string) {
|
|
31
|
+
this.address = address;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public static readonly address = "";
|
|
35
|
+
public static readonly type: ChainSwapType = ChainSwapType.CHAIN_TXID;
|
|
36
|
+
public static readonly gas: number = 10_000;
|
|
37
|
+
|
|
38
|
+
protected serializeCommitment(data: BitcoinCommitmentData): Buffer {
|
|
39
|
+
const buffer = Buffer.alloc(24);
|
|
40
|
+
buffer.writeUint32BE(data.confirmations, 0);
|
|
41
|
+
Buffer.from(data.btcRelay.contractAddress.substring(2), "hex").copy(buffer, 4, 0, 20);
|
|
42
|
+
return buffer;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
getCommitment(data: C & BitcoinCommitmentData): string {
|
|
46
|
+
return keccak256(this.serializeCommitment(data));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
protected async _getWitness(
|
|
50
|
+
signer: string,
|
|
51
|
+
swapData: EVMSwapData,
|
|
52
|
+
{tx, btcRelay, commitedHeader, synchronizer, requiredConfirmations}: BitcoinWitnessData,
|
|
53
|
+
commitment: C,
|
|
54
|
+
feeRate?: string
|
|
55
|
+
): Promise<{
|
|
56
|
+
initialTxns: EVMTx[];
|
|
57
|
+
witness: Buffer,
|
|
58
|
+
commitment: Buffer,
|
|
59
|
+
blockheader: Buffer,
|
|
60
|
+
merkleProof: Buffer
|
|
61
|
+
}> {
|
|
62
|
+
const serializedCommitment: Buffer = this.serializeCommitment({
|
|
63
|
+
...commitment,
|
|
64
|
+
btcRelay,
|
|
65
|
+
confirmations: requiredConfirmations
|
|
66
|
+
});
|
|
67
|
+
const commitmentHash = keccak256(serializedCommitment);
|
|
68
|
+
|
|
69
|
+
if(!swapData.isClaimData(commitmentHash)) throw new Error("Invalid commit data");
|
|
70
|
+
|
|
71
|
+
const merkleProof = await btcRelay.bitcoinRpc.getMerkleProof(tx.txid, tx.blockhash);
|
|
72
|
+
logger.debug("getWitness(): merkle proof computed: ", merkleProof);
|
|
73
|
+
|
|
74
|
+
const txs: EVMTx[] = [];
|
|
75
|
+
if(commitedHeader==null) {
|
|
76
|
+
const headers = await EVMBtcRelay.getCommitedHeadersAndSynchronize(
|
|
77
|
+
signer, btcRelay,
|
|
78
|
+
[{blockheight: tx.height, requiredConfirmations, blockhash: tx.blockhash}],
|
|
79
|
+
txs, synchronizer, feeRate
|
|
80
|
+
);
|
|
81
|
+
if(headers==null) throw new Error("Cannot fetch committed header!");
|
|
82
|
+
commitedHeader = headers[tx.blockhash];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const serializedHeader = commitedHeader.serialize();
|
|
86
|
+
|
|
87
|
+
const serializedMerkleProof = Buffer.concat([
|
|
88
|
+
BigIntBufferUtils.toBuffer(BigInt(merkleProof.pos), "be", 4),
|
|
89
|
+
BigIntBufferUtils.toBuffer(BigInt(merkleProof.merkle.length), "be", 32),
|
|
90
|
+
...merkleProof.merkle
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
initialTxns: txs,
|
|
95
|
+
witness: Buffer.concat([
|
|
96
|
+
serializedCommitment,
|
|
97
|
+
serializedHeader,
|
|
98
|
+
serializedMerkleProof
|
|
99
|
+
]),
|
|
100
|
+
commitment: serializedCommitment,
|
|
101
|
+
blockheader: serializedHeader,
|
|
102
|
+
merkleProof: serializedMerkleProof
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
abstract getWitness(signer: string, data: EVMSwapData, witnessData: W, feeRate?: string): Promise<{
|
|
107
|
+
initialTxns: EVMTx[];
|
|
108
|
+
witness: Buffer
|
|
109
|
+
}>;
|
|
110
|
+
|
|
111
|
+
abstract getGas(data: EVMSwapData): number;
|
|
112
|
+
|
|
113
|
+
abstract getType(): ChainSwapType;
|
|
114
|
+
|
|
115
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {IHandler} from "../IHandler";
|
|
2
|
+
import {BigIntBufferUtils} from "@atomiqlabs/base";
|
|
3
|
+
import {EVMSwapData} from "../../EVMSwapData";
|
|
4
|
+
import {EVMTx} from "../../../chain/modules/EVMTransactions";
|
|
5
|
+
|
|
6
|
+
export class TimelockRefundHandler implements IHandler<bigint, never> {
|
|
7
|
+
|
|
8
|
+
public readonly address: string;
|
|
9
|
+
public static readonly gas: number = 5_000;
|
|
10
|
+
|
|
11
|
+
constructor(address: string) {
|
|
12
|
+
this.address = address;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public getCommitment(data: bigint): string {
|
|
16
|
+
return "0x"+BigIntBufferUtils.toBuffer(data, "be", 32).toString("hex");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public getWitness(signer: string, data: EVMSwapData): Promise<{
|
|
20
|
+
initialTxns: EVMTx[],
|
|
21
|
+
witness: Buffer
|
|
22
|
+
}> {
|
|
23
|
+
const expiry = TimelockRefundHandler.getExpiry(data);
|
|
24
|
+
const currentTimestamp = BigInt(Math.floor(Date.now()/1000));
|
|
25
|
+
if(expiry > currentTimestamp) throw new Error("Not expired yet!");
|
|
26
|
+
return Promise.resolve({initialTxns: [], witness: Buffer.alloc(0)});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getGas(): number {
|
|
30
|
+
return TimelockRefundHandler.gas;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public static getExpiry(data: EVMSwapData): bigint {
|
|
34
|
+
const expiryDataBuffer = Buffer.from(data.refundData.startsWith("0x") ? data.refundData.substring(2) : data.refundData, "hex");
|
|
35
|
+
return BigIntBufferUtils.fromBuffer(expiryDataBuffer, "be");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { IntermediaryReputationType } from "@atomiqlabs/base";
|
|
2
|
+
import { EVMSwapModule } from "../EVMSwapModule";
|
|
3
|
+
import {TransactionRequest} from "ethers";
|
|
4
|
+
import {EVMFees} from "../../chain/modules/EVMFees";
|
|
5
|
+
import {EVMTx} from "../../chain/modules/EVMTransactions";
|
|
6
|
+
|
|
7
|
+
export class EVMLpVault extends EVMSwapModule {
|
|
8
|
+
|
|
9
|
+
private static readonly GasCosts = {
|
|
10
|
+
WITHDRAW: 100_000,
|
|
11
|
+
DEPOSIT: 100_000
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Action for withdrawing funds from the LP vault
|
|
16
|
+
*
|
|
17
|
+
* @param signer
|
|
18
|
+
* @param token
|
|
19
|
+
* @param amount
|
|
20
|
+
* @param feeRate
|
|
21
|
+
* @private
|
|
22
|
+
*/
|
|
23
|
+
private async Withdraw(signer: string, token: string, amount: bigint, feeRate: string): Promise<TransactionRequest> {
|
|
24
|
+
const tx = await this.swapContract.withdraw.populateTransaction(token, amount, signer);
|
|
25
|
+
tx.from = signer;
|
|
26
|
+
tx.gasLimit = BigInt(EVMLpVault.GasCosts.WITHDRAW);
|
|
27
|
+
EVMFees.applyFeeRate(tx, EVMLpVault.GasCosts.WITHDRAW, feeRate);
|
|
28
|
+
return tx;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Action for depositing funds to the LP vault
|
|
33
|
+
*
|
|
34
|
+
* @param signer
|
|
35
|
+
* @param token
|
|
36
|
+
* @param amount
|
|
37
|
+
* @param feeRate
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
private async Deposit(signer: string, token: string, amount: bigint, feeRate: string): Promise<TransactionRequest> {
|
|
41
|
+
const tx = await this.swapContract.deposit.populateTransaction(token, amount, {
|
|
42
|
+
value: token.toLowerCase()===this.root.getNativeCurrencyAddress().toLowerCase() ? amount : 0n
|
|
43
|
+
});
|
|
44
|
+
tx.from = signer;
|
|
45
|
+
EVMFees.applyFeeRate(tx, EVMLpVault.GasCosts.DEPOSIT, feeRate);
|
|
46
|
+
return tx;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Returns intermediary's reputation & vault balance for a specific token
|
|
51
|
+
*
|
|
52
|
+
* @param address
|
|
53
|
+
* @param token
|
|
54
|
+
*/
|
|
55
|
+
public async getIntermediaryData(address: string, token: string): Promise<{
|
|
56
|
+
balance: bigint,
|
|
57
|
+
reputation: IntermediaryReputationType
|
|
58
|
+
}> {
|
|
59
|
+
const [balance, reputation] = await Promise.all([
|
|
60
|
+
this.getIntermediaryBalance(address, token),
|
|
61
|
+
this.getIntermediaryReputation(address, token)
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
return {balance, reputation};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Returns intermediary's reputation for a specific token
|
|
69
|
+
*
|
|
70
|
+
* @param address
|
|
71
|
+
* @param token
|
|
72
|
+
*/
|
|
73
|
+
public async getIntermediaryReputation(address: string, token: string): Promise<IntermediaryReputationType> {
|
|
74
|
+
const filter = Object.keys(this.contract.claimHandlersByAddress).map(claimHandler => ({owner: address, token, claimHandler}));
|
|
75
|
+
const resp = await this.swapContract.getReputation(filter);
|
|
76
|
+
if(resp.length!==filter.length) throw new Error("getIntermediaryReputation(): Invalid response length");
|
|
77
|
+
|
|
78
|
+
const result: any = {};
|
|
79
|
+
Object.keys(this.contract.claimHandlersByAddress).forEach((address, index) => {
|
|
80
|
+
const handler = this.contract.claimHandlersByAddress[address.toLowerCase()];
|
|
81
|
+
const handlerResp = resp[index];
|
|
82
|
+
result[handler.getType()] = {
|
|
83
|
+
successVolume: handlerResp[0].amount,
|
|
84
|
+
successCount: handlerResp[0].count,
|
|
85
|
+
coopCloseVolume: handlerResp[1].amount,
|
|
86
|
+
coopCloseCount: handlerResp[1].count,
|
|
87
|
+
failVolume: handlerResp[2].amount,
|
|
88
|
+
failCount: handlerResp[2].count,
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
return result as any;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Returns the balance of the token an intermediary has in his LP vault
|
|
96
|
+
*
|
|
97
|
+
* @param address
|
|
98
|
+
* @param token
|
|
99
|
+
*/
|
|
100
|
+
public async getIntermediaryBalance(address: string, token: string): Promise<bigint> {
|
|
101
|
+
const [balance] = await this.swapContract.getBalance([{owner: address, token}]);
|
|
102
|
+
|
|
103
|
+
this.logger.debug("getIntermediaryBalance(): token LP balance fetched, token: "+token.toString()+
|
|
104
|
+
" address: "+address+" amount: "+(balance==null ? "null" : balance.toString()));
|
|
105
|
+
|
|
106
|
+
return balance;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Creates transactions for withdrawing funds from the LP vault, creates ATA if it doesn't exist and unwraps
|
|
111
|
+
* WSOL to SOL if required
|
|
112
|
+
*
|
|
113
|
+
* @param signer
|
|
114
|
+
* @param token
|
|
115
|
+
* @param amount
|
|
116
|
+
* @param feeRate
|
|
117
|
+
*/
|
|
118
|
+
public async txsWithdraw(signer: string, token: string, amount: bigint, feeRate?: string): Promise<EVMTx[]> {
|
|
119
|
+
feeRate ??= await this.root.Fees.getFeeRate();
|
|
120
|
+
const withdrawTx = await this.Withdraw(signer, token, amount, feeRate);
|
|
121
|
+
|
|
122
|
+
this.logger.debug("txsWithdraw(): withdraw TX created, token: "+token.toString()+
|
|
123
|
+
" amount: "+amount.toString(10));
|
|
124
|
+
|
|
125
|
+
return [withdrawTx];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Creates transaction for depositing funds into the LP vault, wraps SOL to WSOL if required
|
|
130
|
+
*
|
|
131
|
+
* @param signer
|
|
132
|
+
* @param token
|
|
133
|
+
* @param amount
|
|
134
|
+
* @param feeRate
|
|
135
|
+
*/
|
|
136
|
+
public async txsDeposit(signer: string, token: string, amount: bigint, feeRate?: string): Promise<EVMTx[]> {
|
|
137
|
+
feeRate ??= await this.root.Fees.getFeeRate();
|
|
138
|
+
|
|
139
|
+
const txs: EVMTx[] = [];
|
|
140
|
+
|
|
141
|
+
//Approve first
|
|
142
|
+
if(token.toLowerCase()!==this.root.getNativeCurrencyAddress().toLowerCase())
|
|
143
|
+
txs.push(await this.root.Tokens.Approve(signer, token, amount, this.contract.contractAddress, feeRate));
|
|
144
|
+
|
|
145
|
+
txs.push(await this.Deposit(signer, token, amount, feeRate));
|
|
146
|
+
|
|
147
|
+
this.logger.debug("txsDeposit(): deposit TX created, token: "+token.toString()+
|
|
148
|
+
" amount: "+amount.toString(10));
|
|
149
|
+
|
|
150
|
+
return txs;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
}
|