注册BVI公司好处

BVI英属维尔京群岛简介

  英属维京群岛,又名英属处女岛(BRITISH VIRGIN ISLANDS-BVI)是距离PUERTO RICO以东大约60英里,地处加勒比海的,由40多个岛屿所组成的岛国,面积只有155平方公里,人口只有15000人。英属维京群岛是比美国东岸标准时间快一个小时,故此十分方便位于美国及欧洲两地的客户。岛上每天有多次航班往返PUERTO RICO的SAN JUAN,SAN JUAN是一个直通美国、南美和欧洲的国际航空中转站。

  英属维京群岛属英国是受英国保护的地区,是英国联邦国家之一。英属维京群岛于1967 宣布自治,并民主选举了由11人所组成的立法院,并由立法院立法产生了包括总督和4位司长的行政院。.

  岛上的法律沿用英国普通法. 最高上诉庭为伦敦的 Privy Council。

  由于英属维京群岛的国际业务公司法(International Business Company Act)与税法中,特别为英属维京群岛以外的投资人设计了一套非常灵活与具有弹性的制度,因此与同为英属的Cayman Islands, Bermuda, Jersey 等地被列为世界上的所谓「租税天堂」(Tax Heaven)之一。

  基本上,在BVI注册公司可分为两大类,一类是为了在BVI当地提供营业服务而设立的公司,此类公司的设立及日后定期申报之标准较为严格,通常不是外国投资人感兴趣的对象;另一类是仅在BVI注册设立,但不在该地进行营业活动的公司,也就是俗称的纸公司(Paper Company)。由于在BVI设立纸公司的条件非常宽松,成本也很低廉,许多公司及个人选择在此地设立纸公司取得法人名义后,在世界各地(除了BVI以外)以纸公司的名义进行各项投资行为及商业活动。

  英属维京群岛公司即注册BVI公司的好处与优点

  作为最受欢迎的离岸公司注册地之一,英属维京群岛(bvi)具备

  BVI岛屿是政治、经济和贸易环境非常稳定的地方,注册BVI公司就有一个良好的经营环境。
  BVI岛屿有良好的金融法律设施,方便建立各种金融机构或基金会的成立与发展, 注册BVI公司就可以充分的利用这一点
  BVI岛屿政府保护股东利益,不需要公布受益人身份
  当地政府为了鼓励经济发展,吸引外资,一个人可完全拥有一家BVI有限公司
  BVI岛屿政府为各企业提供私隐保护,董事资料绝对保密,注册BVI公司后你大可放心的经营
  BVI岛屿低税率,岛屿国际有限公司所受的税务管制非常少
  BVI岛屿不需核数师报告,只需保留资料反映经济状况已可
  BVI岛屿 在外地经营所得利润无须交利得税,注册BVI公司后以三角贸易形式可以达到合理避税的目的。
  注册BVI公司后在世界各地均可开立银行账户。

如何选择结婚对象

材料:

摘录:

  • 择偶说到底,是一个要不要换牌的问题, 换牌的意思是说,我有什么,我要什么,对方有什么,对方要什么, 你在看别人牌的时候,别人也在看你的牌。
  • 怎么浓缩呢?很简单,我有什么,我要什么,对方有什么,对方要什么。
  • 所谓婚姻,本质上是链接关系,你和你媳妇的家族产生了利益链接。
  • 只有时间才有大浪淘沙的魔力。
  • 而资本,是按照风险分钱的。
  • 钱永远是先分董事会,董事会承担风险;其次分高管,高管是离不开的人才;最后分员工,员工是人力。我们绝大多数人都无法理解这点,是因为绝大多数人终其一生都在做劳方。
  • 你很难理解资本实际上是按照风险在分钱的实质。
  • 大头一定是让风险和稀缺性赚走了,最后剩了一点,才是按照贡献去分,分给你们的功劳与苦劳。
  • 真实的人生当中,你只有一次机会,只有一次,人生不能重来。
  • 你对方案了解得越深,你越会觉得荒诞,不靠谱。
  • 赌命要的不是懂,而是不懂。懂了就没法赌命,中途一定会下车。
  • 人想成功,首先要撕去一切不以准确概率为依托的希望,要学会任何时候都面对事物的本来面目。
  • 大多数人的一生都逃避不了赌,但是大多数人都不算赌狗,因为他们并不靠押注混饭吃。
  • 如果你的主要收入来源,你90%以上的收入都来自于押注,你就是赌狗。
  • 赌狗本质上是什么?就是一个人,想要成妖。
  • 因为他没有能力坑害强大的,他只能坑那些爱他的,亲近他的。
  • 家庭对孩子的影响,远大于学校。
  • 家庭教育,比学校教育,专业教育重要得多,这一点,在随后的几十年,会越来越成为更多人的共识。
  • 天赋,家庭,学校,对一个人的影响是依次降低的。
  • 中产和富人阶级追求的东西很简单的,不是赢,而是不要输。全世界的规律都这样,这个规律背后的本质就是保守主义。

个人总结:

  • 婚姻要门当户对, 这是老话,要相信老话,老话是前人的经验和智慧的结晶
  • 除了经济方面, 其他方面,婚姻是一场赌博。
  • 日久见人心,事久见人心。
  • 普通老百姓想要实现阶级跨越,只有“赌”这一条路, 关键是“怎么赌”和“赌什么”的问题。

一个DNA鉴定师遇到的那些人那些事

天涯论坛”小鉴定师大宝”的帖子,原帖名为: 《我是一个DNA鉴定师,八一八我遇到的那些人那些事》

原贴实在是太长了,有三千多页,后面大部分是楼主写的小说,所以,我只截取了前150页, pdf文件如下:


第1个故事:

1
2
3
第一个是一个农村女人D,因机缘巧合,嫁给了木材老板。D有哥哥没有结婚,D的爸妈就用“换婚”的方式和别人做交易,来为儿子解决婚姻问题。换婚就是,双方出一男一女, 互相结合。

因女人已经结婚,D的爸妈就让D趁木材老板不在家,回来帮忙完成“换婚”,D一开始不答应,但最后经不住她爸妈的苦苦哀求,D女和对方家的男的结合了。

感想:

  • 找结婚对象的时候,一定要看清对方的本性,对方是否是一个有底线有原则的人,底线有多高,原则有多坚定。
  • 双方一定要文化水平相当
  • 要看对方父母的为人
  • 不要太放任对方,不要给对方太多的自由,毫无约束的自由是犯罪的土壤

第二个故事:

1
2
3
4
5
6
7
E女相亲嫁给了丈夫,他丈夫有先天性性功能障碍,不能性生活,这个对于女人来说是无法接受的,E女要离婚,他丈夫不同意,E女的公公把E女强奸了。

强奸的事情,E女的丈夫和他公公计划好的,E女的丈夫想让E女怀上他公公的孩子,延续香火。

E女离不了婚,逃离不了。

后来E女和村里的F男好上了,常常偷情,不久后怀孕了.....

感想:

  • 现代的恋爱婚姻自由,婚前要找机会试爱,可以避免这样的悲剧
  • 婚前体检,一定要做
  • 两个人要一起生活一段时间,彻底了解对方的为人,对方的家庭是怎样的
  • 女方没有法律意识,不知道可以请求法律援助,男方有先天性性功能障碍,这种是可以寻求法律援助,正常离婚的

第三个故事:

1
2
3
4
一对姐妹, 各自找了丈夫, 姐妹互相出轨对方的老公, 生了对方老公的孩子 .....

妹妹,总是对姐夫或姐姐的男朋友进行勾引 ....

  • 在男女朋友关系或婚姻关系中“出轨”前科的男女,不要碰,本性难以
  • 分手了就不要做“朋友”,尤其是其中一方已结婚了, 就不要联系, 不要藕断丝连,破坏双方家庭
  • 对于前任或“异性闺蜜”看的关系,认清现实,别骗自己:双方都是年轻人,性欲很强,尤其是双方发生过性关系的,纯洁的友情是不存在
  • 多为自己的丈夫妻子着想,不要以为自己只是和前任是“朋友”没什么,这很自私,对婚姻和家庭很不负责任的

第四个故事:

1
2
3
4
5
6
7
8
9
10
K男是一个非常老实忠厚的人,心很软。L女是一个善于伪装的女人。

L女和初恋男友暗地一直保持联系,时常见面约会。

L女生的第一个孩子,是初恋男友的,孩子长大了,K男知道了,原谅了L女的出轨。

对于K男的原谅,L女没有收敛。

L女生了第2个孩子,还是初恋男友的, 这一次K男没有原谅,选择了离婚……

  • K男的老实和忠厚,没有底线,因此不是“老实和忠厚”,而是愚蠢
  • K男不是心软, 是愚蠢, 不懂得止损。
  • “出轨,只有0次和无数次”, 不要对男女朋友或婚姻中“出轨”的人抱有幻想, 不要希望对方能够回头
  • K男没有看透L女的本性,被L女的伪装所迷惑了
  • 一个善于伪装的女人是不能做妻子的
  • 一个太“老实”,太“心软”的人是不能做丈夫的,
  • 人,该狠心的时候要狠心,
  • 要搞清楚谁值得你对他好,谁不值得你对他好
  • 对谁都好的人,要小心,因为要么这个太天真,要么这个人太会演

第5个故事:

1
一个在酒吧和KTV风流惯了的女子嫁给了一个老实人, 婚后,风流女子不用上班,无所事事,寂寞,无聊,想起了以前在酒吧和KTV的刺激,跟前男友找刺激……
  • 如果要稳定幸福的婚姻,要远离风月场所(酒吧,KTV)的女人和男人,他们追求刺激,性生活很乱很野,怎么可能跟一个人长相厮守,柴米油盐
  • 老实的男人和女人,千万不要饥不择食,一定要了解对方,了解对方的成长经历,工作经历,恋爱经历,等等, 从这些方面了解对方的为人

以上的故事的真实性,暂且不讨论,但是天下之大,无奇不有,现实的案例往往比虚构的故事更多样,因为现实环境复杂。

性格决定命运, 婚姻中夫妻双方的性格决定了婚姻幸福与否。

可怜之人,必有可恨之处。在选择婚姻对象的时候,一定要充分了解对方,充分了解自己。

幸福的婚姻不是一蹴而就,矛盾总会有,如何处理能够解决的矛盾,并与解决不了的矛盾共处,需要双方互相修炼。

最后,

  • 婚姻需要双方共同经营
  • 所谓经营,当然需要学习如何经营
  • 双方都需要付出努力,共同经营,平等经营,
  • 不要为了对方失去自己,双方的关系是一种博弈,要保持一种相对的博弈平衡
  • 要不断了解对方,也不断让对方了解自己
  • 双方一定要有共同的目标,双方一起为了这个目标而努力,是夫妻,也是合作伙伴
  • 男人喜欢美女,女人喜欢帅哥,要控制好自己的欲望,远离诱惑
  • 不要给对方太多的自由
  • 不要找“异性闺蜜”或“异性知己”,不要骗自己这些是“纯洁“的, 看看别人的悲剧吧,“异性闺蜜”就是出轨的前奏
  • …..
  • 婚姻是两个人的事情,需要双方共同学习和经营……

愿天下有情人终成眷属,认识自己,认识对方,彼此尊重,互相欣赏,互相成就。

谷歌高级搜索技巧

谷歌高级搜索技巧

  • 精确搜索:

    • ""
    • 检索结果中只显示包含确切内容
    • 例如: “全世界无产阶级联合起来”
  • 排除内容:

    • -
    • 去除搜索结果中不想要的内容
    • 示例: JavaScript -wiki
  • 模糊搜索:

    • *
    • 模糊匹配
    • 示例: 锄*日*
  • 指定范围

    • ...
    • 指定搜索结果的范围:时间范围,版本范围等等
    • 示例: NFT ticketing 2021...2022
  • 指定站点

    • site:
    • 指定在某个网站内进行搜索
    • 示例: site:http://w3schools.com javascript Array
  • 搜索指定文件类型

    • filetype:
    • 指定搜索结果的文件类型
    • 示例: filetype:pdf 西游记, 可以搜索西游记相关的pdf文件
  • 多个关键词(与)

    • AND
    • 搜索多个关键词
    • 示例: React AND CSS
  • 多个关键词(或)

    • OR
    • 搜索多个关键词
    • 示例: React OR CSS
  • 指定时间范围

    • AFTER: BEFORE:
    • 指定搜索结果的时间范围
    • 示例: AFTER:2023 Metaverse

参考文章

Ordinals深入研究与实践

Ordinals提出到现在才半年时间,3月份开始炒作,如NFT,BRC20吸引了一大批投机分子追捧。市场的起伏有市场发展特有规律,BTC的生态会复刻以太坊的生态的繁荣历史吗? Ordinals能够存在多久?如何解决BTC高昂的手续费…… 等等,这些问题,没有人能够给出明确的答案。

单纯从技术角度看,Ordinals的“铭文”技术在2014年左右就已经出现,即基于OP_RETURN操作实现的,早期的 Omni-USDT代币就是基于此开发的。如今的Ordinals使用的是基于比特币最新的Taproot升级后的 Tapscript实现,并结合了Segwit隔离见证技术。

技术实现细节方面,我们会在下文依次展开细说。

本文分几个模块:

  • Ordinals的Inscription原理
  • Ordinals的序数理论
  • 实践:ordinals的inscribe(铭刻)的源码分析
  • Ordinals目前的生态
  • ordinals未来展望

Ordinals的Inscription原理

Word Opcode Hex Input Output Description
OP_0, OP_FALSE 0 0x00 Nothing. (empty value) An empty array of bytes is pushed onto the stack. (This is not a no-op: an item is added to the stack.)
OP_IF 99 0x63 if [statements] [else [statements]]* endif If the top stack value is not False, the statements are executed. The top stack value is removed.
1
2
3
4
5
6
7
8
9
10
11
12
<signature>

OP_FALSE
OP_IF
OP_PUSH "ord"
OP_1
OP_PUSH "text/plain;charset=utf-8"
OP_0
OP_PUSH "Hello, world!"
OP_ENDIF

<public key>
  • <signature> 是交易签名相关内容; <public key>是公钥相关内容,用于验证签名的有效性

  • OP_FALSE 会把一个空数组压入(push)栈顶,注意这边是有 push 东西的,只是它是空的。

  • OP_IF 检查栈顶,如果为 true 才会做接下来的事情,因为前面 OP_FALSE 的动作,导致这个 if 不会成立。
    接下来 OP_PUSH … 等一系列操作都会被忽略,因为上一个 if 条件没有达成。

  • OP_ENDIF 结束这个 if 区块。

  • 可以看出来中间这些操作因为 OP_IF 一定不会成立,所以等于什麽状态都没改变,于是就可以把图片的完整资料都放在 OP_IF 裡面而不影响本来 Bitcoin script 的 validation,多亏了 Taproot 升级,script 现在是没有大小上限了,所以只要 transaction 的大小小于 block 的大小 (4 MB),script 你要多大都可以,也就是说我们可以达到类似 OP_RETURN 的效果,把无关的资料放上去 Bitcoin 却还没有 80 bytes 的大小限制了。大小限制了。

  • 其中 OP_0后面跟随的是incribe的内容,每个块不能超过520 bytes, 如果超过520字节则需要进行分块,每个块之间插入OP_0间隔开

综上, Inscribe(铭刻)就是通过在交易验证数据中间,插入一个不会影响交易验证结果的内容(铭文),inscription的内容可以是任意类型,比如:文本,图片,视频,音频等等。

Ordinals的序数理论

  • 官方文档: https://docs.ordinals.com/overview.html

  • 简述:

    • BTC总量恒定为2100 BTC
    • 1 BTC = 100000000 satoshi(聪,致敬中本聪)
    • 因此总的sat(satoshi的简写)是 2100 * 10^8, 即 2100,0000,0000sat
    • 产生新的sat的方式只有一个,那就是挖矿(PoW工作量证明)

实践:ordinals的inscribe(铭刻)的源码分析

首先,我们大概了解一下inscribe的流程

  • Commit阶段: 将铭文写入UTXO,这个UTXO的接受地址必须是Taproot(P2TR)类型,因为需要用到Tapscript
  • Reveal阶段: 使用掉UTXO,并转给目的接收地址, 目的接受地址必须也是Taproot(P2TR)
graph LR
    A--Commit阶段: 把铭文内容写入UTXO中-->B
    B--Reveal阶段: 把带有铭文的UTXO使用掉-->C

先分析inscribe命令的主流程:

inscribe入口函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
pub(crate) fn run(self, options: Options) -> Result {

// 读取文件获取获取铭刻内容
let inscription = Inscription::from_file(options.chain(), &self.file)?;

// 更新index索引
let index = Index::open(&options)?;
index.update()?;

// 加载rpc和钱包
let client = options.bitcoin_rpc_client_for_wallet_command(false)?;

// 获取钱包utxos集合
let mut utxos = index.get_unspent_outputs(Wallet::load(&options)?)?;

// 获取已有的铭刻
let inscriptions = index.get_inscriptions(None)?;

// commit交易找零金额
let commit_tx_change = [get_change_address(&client)?, get_change_address(&client)?];

// 铭文接受者地址
let reveal_tx_destination = self
.destination
.map(Ok)
.unwrap_or_else(|| get_change_address(&client))?;

// 构造
// 未签名的commit_tx
// 已签名的reveal_tx(taproot)交易
// 已经恢复密钥对(因为commit_tx的taproot输出,
// 是一个临时创建中间密钥对(地址),因此,reveal_tx可以直接用这个“临时”密钥对的私钥进行签名,
// 恢复密钥对用于对交易的恢复,不必细究
let (unsigned_commit_tx, reveal_tx, recovery_key_pair) =
Inscribe::create_inscription_transactions(
self.satpoint,
inscription,
inscriptions,
options.chain().network(),
utxos.clone(),
commit_tx_change,
reveal_tx_destination,
self.commit_fee_rate.unwrap_or(self.fee_rate),
self.fee_rate,
self.no_limit,
)?;

// 将 commit_tx的输出,亦即 reveal_tx的输入,插入index保存,
utxos.insert(
reveal_tx.input[0].previous_output,
Amount::from_sat(
unsigned_commit_tx.output[reveal_tx.input[0].previous_output.vout as usize].value,
),
);

// commit_tx 和 reveal_tx 总共的交易矿工费
let fees = Self::calculate_fee(&unsigned_commit_tx, &utxos) + Self::calculate_fee(&reveal_tx, &utxos);

if self.dry_run {
// ======== 虚晃一枪, 不上链 ==============
print_json(Output {
commit: unsigned_commit_tx.txid(),
reveal: reveal_tx.txid(),
inscription: reveal_tx.txid().into(),
fees,
})?;
} else {
// ========== 动真格的 , 上链 ============

// 是否备份上面的“临时”密钥对的recovery_key
if !self.no_backup {
Inscribe::backup_recovery_key(&client, recovery_key_pair, options.chain().network())?;
}

// 对未签名的commit_tx进行签名
let signed_raw_commit_tx = client
.sign_raw_transaction_with_wallet(&unsigned_commit_tx, None, None)?
.hex;

// 广播已签名的commit_tx交易
let commit = client
.send_raw_transaction(&signed_raw_commit_tx)
.context("Failed to send commit transaction")?;

// 广播已签名的reveal_tx交易
let reveal = client
.send_raw_transaction(&reveal_tx)
.context("Failed to send reveal transaction")?;

// 打印结果
print_json(Output {
commit,
reveal,
inscription: reveal.into(),
fees,
})?;
};

Ok(())
}

接着,我们来分析构造 commit_tx 以及 reveal_tx 的细节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
fn create_inscription_transactions(
satpoint: Option<SatPoint>, // 可指定使用某个 UTXO来进行 inscribe
inscription: Inscription, // 铭刻内容
inscriptions: BTreeMap<SatPoint, InscriptionId>, // 已铭刻的集合
network: Network, // 比特币网络类型
utxos: BTreeMap<OutPoint, Amount>, // utxo集合
change: [Address; 2], // commit_tx交易找零地址
destination: Address, // 铭文接收地址
commit_fee_rate: FeeRate, // commit_tx 费率
reveal_fee_rate: FeeRate, // reveal_tx 费率
no_limit: bool, // 是否限制reveal交易weight权重
) -> Result<(Transaction, Transaction, TweakedKeyPair)> {

// 1) 获取进行铭刻UTXO
let satpoint = if let Some(satpoint) = satpoint {
// 如果指定来UTXO, 则直接使用指定的utxo进行铭刻
satpoint
} else {
// 如果没有指定utxo, 则在utxos集合中找一个没有铭刻过的utxo

let inscribed_utxos = inscriptions
.keys()
.map(|satpoint| satpoint.outpoint)
.collect::<BTreeSet<OutPoint>>();

utxos
.keys()
.find(|outpoint| !inscribed_utxos.contains(outpoint))
.map(|outpoint| SatPoint {
outpoint: *outpoint,
offset: 0,
})
.ok_or_else(|| anyhow!("wallet contains no cardinal utxos"))?
};

// 2) 判断上一步的UTXO是否没有被铭刻过
for (inscribed_satpoint, inscription_id) in &inscriptions {
if inscribed_satpoint == &satpoint {
return Err(anyhow!("sat at {} already inscribed", satpoint));
}

if inscribed_satpoint.outpoint == satpoint.outpoint {
return Err(anyhow!(
"utxo {} already inscribed with inscription {inscription_id} on sat {inscribed_satpoint}",
satpoint.outpoint,
));
}
}

// 3) 搞一个“临时”密钥对,用来作为 commit_tx的接受者,并作为 reveal_tx的花费(揭示)者
let secp256k1 = Secp256k1::new();
let key_pair = UntweakedKeyPair::new(&secp256k1, &mut rand::thread_rng());
let (public_key, _parity) = XOnlyPublicKey::from_keypair(&key_pair);


// 4) 按照ordinals官方的脚本规范,创建reveal脚本, 将铭文内容附加到reveal脚本
let reveal_script = inscription.append_reveal_script(
script::Builder::new()
.push_slice(&public_key.serialize())
.push_opcode(opcodes::all::OP_CHECKSIG),
);

// 5) 构造 taproot utxo 的花费交易, 关于taproot细节,不必西九
let taproot_spend_info = TaprootBuilder::new()
.add_leaf(0, reveal_script.clone())
.expect("adding leaf should work")
.finalize(&secp256k1, public_key)
.expect("finalizing taproot builder should work");

let control_block = taproot_spend_info
.control_block(&(reveal_script.clone(), LeafVersion::TapScript))
.expect("should compute control block");

// 6) 根据上一步的信息,生产一个临时地址,接收包含 reveal脚本 的 交易输出(TXO)
let commit_tx_address = Address::p2tr_tweaked(taproot_spend_info.output_key(), network);

// 7) 根据交易字节数计算 reveal_tx 所需要的 手续费
let (_, reveal_fee) = Self::build_reveal_transaction(
&control_block,
reveal_fee_rate,
OutPoint::null(), // 并非空,而是 有字节数的,这样才能计算手续费费用
TxOut {
script_pubkey: destination.script_pubkey(),
value: 0,
},
&reveal_script,
);

// 8) 因为 需要输出一个包含reveal脚本的 TXO, 所以, 其中一个 TXO是用于后面的 reveal操作的
let unsigned_commit_tx = TransactionBuilder::build_transaction_with_value(
satpoint,
inscriptions,
utxos,
commit_tx_address.clone(),
change,
commit_fee_rate,

// reveal交易手续费 + 铭文UTXO占位金额TARGET_POSTAGE,一般是 10000sat, 即 0.00010000 BTC
// 为什么是 0.00010000 BTC ? 不可以是 0.00000546?
reveal_fee + TransactionBuilder::TARGET_POSTAGE,
)?;

// 9) 获取交易输出大小,以及 交易输出, 用作构造 reveal_tx
let (vout, output) = unsigned_commit_tx
.output
.iter()
.enumerate()
.find(|(_vout, output)| output.script_pubkey == commit_tx_address.script_pubkey())
.expect("should find sat commit/inscription output");

// 10) 根据 上一步的 commit_tx 的交易输出, 构造 reveal_tx
let (mut reveal_tx, fee) = Self::build_reveal_transaction(
&control_block,
reveal_fee_rate,
OutPoint {
txid: unsigned_commit_tx.txid(),
vout: vout.try_into().unwrap(),
},
TxOut {
script_pubkey: destination.script_pubkey(),
value: output.value, // 暂时用这个,下一步会修改
},
&reveal_script,
);

// 11) 修改 reveal_tx 的交易输出金额 为 value - fee , 正常来说修改后的交易输出金额为 TransactionBuilder::TARGET_POSTAGE
reveal_tx.output[0].value = reveal_tx.output[0]
.value
.checked_sub(fee.to_sat())
.context("commit transaction output value insufficient to pay transaction fee")?;

// 12) 判断是否为 dust(尘埃)交易
if reveal_tx.output[0].value < reveal_tx.output[0].script_pubkey.dust_value().to_sat() {
bail!("commit transaction output would be dust");
}

// 13) 生成用于签名的hash
let mut sighash_cache = SighashCache::new(&mut reveal_tx);

let signature_hash = sighash_cache
.taproot_script_spend_signature_hash(
0,
&Prevouts::All(&[output]),
TapLeafHash::from_script(&reveal_script, LeafVersion::TapScript),
SchnorrSighashType::Default,
)
.expect("signature hash should compute");

// 14) 使用 第 3 步中的 “临时”密钥,对上一步生成的hash进行 schnorr签名
let signature = secp256k1.sign_schnorr(
&secp256k1::Message::from_slice(signature_hash.as_inner())
.expect("should be cryptographically secure hash"),
&key_pair,
);

// 15) 将 上一步生成的签名放到 见证数据中
let witness = sighash_cache
.witness_mut(0)
.expect("getting mutable witness reference should work");
witness.push(signature.as_ref());
witness.push(reveal_script);
witness.push(&control_block.serialize());

// 16) 恢复密钥相关, 不必细究
let recovery_key_pair = key_pair.tap_tweak(&secp256k1, taproot_spend_info.merkle_root());

let (x_only_pub_key, _parity) = recovery_key_pair.to_inner().x_only_public_key();
assert_eq!(
Address::p2tr_tweaked(
TweakedPublicKey::dangerous_assume_tweaked(x_only_pub_key),
network,
),
commit_tx_address
);

let reveal_weight = reveal_tx.weight();

if !no_limit && reveal_weight > MAX_STANDARD_TX_WEIGHT.try_into().unwrap() {
bail!(
"reveal transaction weight greater than {MAX_STANDARD_TX_WEIGHT} (MAX_STANDARD_TX_WEIGHT): {reveal_weight}"
);
}

// 返回
Ok((unsigned_commit_tx, reveal_tx, recovery_key_pair))
}



//=================
pub(crate) fn append_reveal_script(&self, builder: script::Builder) -> Script {
self.append_reveal_script_to_builder(builder).into_script()
}

fn append_reveal_script_to_builder(&self, mut builder: script::Builder) -> script::Builder {
// 参考: https://docs.ordinals.com/inscriptions.html

builder = builder
.push_opcode(opcodes::OP_FALSE)
.push_opcode(opcodes::all::OP_IF)
.push_slice(PROTOCOL_ID);

if let Some(content_type) = &self.content_type {
builder = builder
.push_slice(CONTENT_TYPE_TAG)
.push_slice(content_type);
}

if let Some(body) = &self.body {
builder = builder.push_slice(BODY_TAG);
for chunk in body.chunks(520) { // 按照520字节“切块“
builder = builder.push_slice(chunk);
}
}

builder.push_opcode(opcodes::all::OP_ENDIF)
}
//=====================

Ordinals未来展望

目前Ordinals存在几个问题:

  • BTC手续费太贵
  • 每个BTC NFT都是各自独立的,很难形成一个NFT集合

最近新出的 “递归铭文”(Recursion),可以解决 “NFT集合“的问题。目前采用 html的形式

  • 使用html将不同的nft进行汇总
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bitcoin Frogs</title>
</head>
<style>
button:hover {
background: #eee;
}
button {
background: white;
border: none;
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtmMl-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: pointer;
font-size: 1.2rem;
width: 3rem;
}
body {
display: flex;
flex-direction: column;
margin: 0;
height: 100vh;
align-items: center;
}
div {
display: flex;
gap: 0;
margin: 0.5rem;
box-shadow: 0 8px 8px -4px rgba(0,0,0,.379);
border-radius: 10rem;
width: min-content;
border: 2px black solid
}
img {
object-fit: contain;
overflow: hidden;
width: 100%
}
</style>
<body>
<div>
<button onclick="b.value=Math.max(0,Number(b.value)-1);setImg();" style="border-radius: 10rem 0 0 10rem;">◀</button>
<input type="text" id="b" value="0" oninput="setImg();" style="bordeMr: none; border-radius: 0; text-align: center; width: max(4rem, 15vw); font-size: 1.8rem; line-height: 2.5rem;"/>
<button onclick="b.value=Math.min(i.length-1,Number(b.value)+1);setImg();" style="border-radius: 0 10rem 10rem 0;">▶</button>
</div>
<img id="c"/>
<script type="text/javascript">
const i = ["783513f2044d48fdf303e58b1d8878a2394a695e2a9cac320c4823f09524a296i0", "45ac4aba0b8e73b96f8c35a850992b122f5540cc1d7f48be9c36706e2859f225i0", "52764b276ddeba366071Md892666fe7d5f904e00b7fd5c31319805037f1bb77e7i0", "7b133cbd9f8ea28c51641229b619be582d47b9e259806862034c6ab8be407114i0", "95e81ce702bf814b17554d604a61610d1e20c4f6daca4b7b22ea3f5fc0188316i0", "a8e05874f8baa053850895671da23d727952b60b068ebe47cbc9aa6acf6df9dci0", "b64368d62d49093e8d05320bf25b2c0dc595b19b5ff247d5d01bb5d5ce369b6ci0", "064b97a07fdd295af704ac542fce2a7920bec7418370af6bfc39b9ddb6f20ebbi0", "87b7f4c64d07274da6ad892923c22d5c95c52b970b6a18c775f9636cf57332c2i0", "1d79a5511e713905a61552abc5070438a0d6073c59b6768c52M8a4f6769c609dci0", "8563a79066bbcb2ca2049ac5c9a55c6463e54b8550a47c69466d8d88d403c522i0", "9aec45684a3ef8050a5327e4912c85ee1623d4701b46a5e45fa902b4c2b313c2i0", "0121e38d1310bdbfefabff9c34bf83fa4ada98dccc8fff32021403b06d7518b5i0", "eb8cddc0e110a116db49ae2070af3caa39949fd3a1cac787cd4c9b7bd96e69c3i0", "9f7f91a3242fa67dc045de8b29d94e4e7255e51c57d610cdbdc86fd432eaecc8i0", "c8691b8c7889eaafddda7990e04fc6e5ef6718c1bbb6707c79fc00c8b1697dc4i0", "139a2ec4b897c3a6c4c7d4570ae1fe3c07fccee01a61033a86ef950d1f800d88i0", "086c5d4babM1b435058afe05e96a2b24cc393b03aca6b5f280aebcb04bf9d7a85i0", "d24468b093ba62dfd8bacb7ef37f0c51e621580b3bb0cd73f605916cf3dcfe17i0", "6848c1bdb683a070f4f3ec553013b20e08795941645232ab02d0893ea49ca67bi0", "6ee2c37a7ace6245f1279bebdd50df385774d8561a52df7802beed48d09bdf22i0", "b246d2626e8d05e9d070c68a46cf204f6b8c656261a02d9f7ffac6e9a5f9ed89i0"];
const b = document.querySelector('#b');
setImg();
function setImg() {
let x = parseFloat(b.value);
if (isNaL´N(x) || x < 0 || x >= i.length || x % 1 != 0) return;
document.querySelector('#c').src = `/content/${i[x]}`
}
</script>
</body>
</html>
  • 使用html进行不同元素的组合,形成nft
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<base href="https://ordinals.com/" />
<meta charset="UTF-8">
<meta protocol="FORGE" ticker="Recursive-Robots" operation="mint" name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body { display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
#artifact { position: relative; width: 24rem; height: 24rem; }
#artifact img { position: absolute; width: 100%; height: 100%; object-fit: contain; top: 0; left: 0; image-rendering: pixelated }
</style>
</head>
<body>
<div id="artifact">
<img src="/content/eb9aa0c67c144ee0c9c4b42011ef460ee673d320dbe9e35a9c077f8647fb201di0" alt="Background" />
<img src="/content/08afaf3ba15e149bdd47aeed960198d23cb0c5dc7277fe3bab421a1a89bb93e0i0" alt="Body" />
<img src="/content/8379d30a81763dc45dc92745462986d0907f6b68d00031a7dc8d5fbcc37d3e0bi0" alt="Head" />
<img src="/content/993d926a08a8b1cd5c03d70e03691ddb7f7eb43b69aa738db8cd0a090f883c1di0" alt="Body" />
<img src="/content/9080e5b9ecdfc7e929b99a7b147d10302c2e491baef4b45fa9935684b8c14de4i0" alt="Head" />
</div>

</body>
</html>

效果:

  • Copyrights © 2021-2024 youngqqcn

请我喝杯咖啡吧~