|
2 | 2 | sidebar_position: 2
|
3 | 3 | ---
|
4 | 4 | # 编写第一个合约
|
| 5 | + |
| 6 | +在上一节中我们使用scrypt-cli工具创建了一个demo工程,并且打入了MVC链的补丁,下面我们使用这个项目来部署合约到MVC测试网。 |
| 7 | + |
| 8 | +## 示例合约 |
| 9 | + |
| 10 | +demo工程中有生成一个Demo合约,源码位于src/contracts/demo.ts,合约逻辑为使用一段数据的hash值构造并部署合约,合约unlock时需要输入数据原文。 |
| 11 | + |
| 12 | +```typescript |
| 13 | +import { |
| 14 | + assert, |
| 15 | + ByteString, |
| 16 | + method, |
| 17 | + prop, |
| 18 | + sha256, |
| 19 | + Sha256, |
| 20 | + SmartContract, |
| 21 | +} from 'scrypt-ts' |
| 22 | + |
| 23 | +export class Demo extends SmartContract { |
| 24 | + @prop() |
| 25 | + hash: Sha256 |
| 26 | + |
| 27 | + constructor(hash: Sha256) { |
| 28 | + super(...arguments) |
| 29 | + this.hash = hash |
| 30 | + } |
| 31 | + |
| 32 | + @method() |
| 33 | + public unlock(message: ByteString) { |
| 34 | + assert(sha256(message) == this.hash, 'Hash does not match') |
| 35 | + } |
| 36 | +} |
| 37 | +``` |
| 38 | + |
| 39 | + |
| 40 | +## 部署并调用合约 |
| 41 | + |
| 42 | +原项目中使用项目根目录下的deploy.ts来部署合约,原项目部署适配bsv测试网,下面详述如何改成mvc链 |
| 43 | + |
| 44 | +### 安装依赖包 |
| 45 | + |
| 46 | +- token-core-ts包封装了MVC链的Wallet和Provider,为scrypt-ts提供MVC链接入功能 |
| 47 | +- meta-contact封装了MVC数据服务,提供接入的api |
| 48 | +- @bitcoin-js/tiny-secp256k1-asmjs,ecpair提供Bitcoin标准的Signer interface |
| 49 | + |
| 50 | +```bash |
| 51 | +npm install token-core-ts meta-contract @bitcoin-js/tiny-secp256k1-asmjs ecpair |
| 52 | +``` |
| 53 | + |
| 54 | +### 更新deploy.ts文件 |
| 55 | + |
| 56 | +```typescript |
| 57 | +import { Demo } from './src/contracts/demo' |
| 58 | +import { bsv, sha256, toByteString } from 'scrypt-ts' |
| 59 | +import { MvcWallet, MvcProvider } from 'token-core-ts' |
| 60 | +import * as ecc from '@bitcoin-js/tiny-secp256k1-asmjs' |
| 61 | +import ECPairFactory, { SignerAsync } from 'ecpair' |
| 62 | +const ECPair = ECPairFactory(ecc) |
| 63 | +import * as dotenv from 'dotenv' |
| 64 | +import { API_TARGET } from 'meta-contract' |
| 65 | + |
| 66 | +// Load the .env file |
| 67 | +dotenv.config() |
| 68 | + |
| 69 | +if (!process.env.PRIVATE_KEY) { |
| 70 | + throw new Error( |
| 71 | + 'No "PRIVATE_KEY" found in .env, Please run "npm run genprivkey" to generate a private key' |
| 72 | + ) |
| 73 | +} |
| 74 | + |
| 75 | +const network = bsv.Networks.testnet |
| 76 | + |
| 77 | +const mvcProvider = new MvcProvider(API_TARGET.MVC, network, 1000, true) |
| 78 | + |
| 79 | +// Read the private key from the .env file. |
| 80 | +// The default private key inside the .env file is meant to be used for the Bitcoin testnet. |
| 81 | +// See https://scrypt.io/docs/bitcoin-basics/bsv/#private-keys |
| 82 | +const privateKey = bsv.PrivateKey.fromWIF(process.env.PRIVATE_KEY || '') |
| 83 | +const bip174Signer = ECPair.fromPrivateKey(privateKey.toBuffer()) |
| 84 | + |
| 85 | +const mvcWallet = new MvcWallet( |
| 86 | + bip174Signer as unknown as SignerAsync, |
| 87 | + network, |
| 88 | + mvcProvider |
| 89 | +) |
| 90 | + |
| 91 | +async function main() { |
| 92 | + await Demo.loadArtifact() |
| 93 | + |
| 94 | + // check balance |
| 95 | + const balance = await mvcWallet.getBalance() |
| 96 | + if (balance.confirmed + balance.unconfirmed === 0) { |
| 97 | + console.log('use faucet get mvc testnet coin') |
| 98 | + console.log('https://witnessonchain.com/faucet/tspace') |
| 99 | + console.log( |
| 100 | + 'address: ', |
| 101 | + (await mvcWallet.getDefaultAddress()).toString() |
| 102 | + ) |
| 103 | + return |
| 104 | + } |
| 105 | + console.log('balance', balance) |
| 106 | + |
| 107 | + // TODO: Adjust the amount of satoshis locked in the smart contract: |
| 108 | + const amount = 1 |
| 109 | + |
| 110 | + const msg = toByteString('hello world', true) |
| 111 | + |
| 112 | + const instance = new Demo( |
| 113 | + // TODO: Adjust constructor parameter values: |
| 114 | + sha256(msg) |
| 115 | + ) |
| 116 | + |
| 117 | + // Connect to a signer. |
| 118 | + await instance.connect(mvcWallet) |
| 119 | + |
| 120 | + // Contract deployment. |
| 121 | + const deployTx = await instance.deploy(amount) |
| 122 | + console.log( |
| 123 | + `Demo contract deployed: https://test.mvcscan.com/tx/${deployTx.id}` |
| 124 | + ) |
| 125 | + // Call contract |
| 126 | + const { tx, atInputIndex } = await instance.methods.unlock(msg) |
| 127 | + console.log( |
| 128 | + `Demo contract call at: https://test.mvcscan.com/tx/${tx.id} ${atInputIndex}` |
| 129 | + ) |
| 130 | +} |
| 131 | + |
| 132 | +main() |
| 133 | +``` |
| 134 | + |
| 135 | +### 执行deploy.ts |
| 136 | + |
| 137 | +```bash |
| 138 | +npm run deploy |
| 139 | +``` |
| 140 | +如果测试地址无测试代币请前往MVC测试网[水龙头](https://witnessonchain.com/faucet/space)领取。 |
| 141 | + |
| 142 | + |
| 143 | + |
| 144 | +执行成功如下 |
| 145 | + |
| 146 | + |
| 147 | + |
| 148 | +实例中合约部署在[baf27c3164aecb1e285ef154c2f802eac69ee17b8cea8eb013da2f9d8890dfca](https://test.mvcscan.com/tx/baf27c3164aecb1e285ef154c2f802eac69ee17b8cea8eb013da2f9d8890dfca),在[d18d04c19108ae5c7baeefe7183b1ea07847ef58e23b560fc3d32abcf0bd8f17](https://test.mvcscan.com/tx/d18d04c19108ae5c7baeefe7183b1ea07847ef58e23b560fc3d32abcf0bd8f17)中被调用。 |
0 commit comments