Polymarket技术分析

Polymarket技术分析

polymarket介绍:

关键概念:

  • 预测事件: 二元事件,即结果是发生和不发生

    • 例如:
      • 特朗普赢得2024大选,其结果是 YesNo
      • 谁将赢得2024大选? 有多个候选人,但是每个候选人最后的结果只有2种: YesNo
  • shares: 股份, 即持有某个预测的凭证, 实际上是ERC1155代币, 可以理解为股份

  • 用户可以买入或卖出某个事件的 Yes的shares 或 No的shares

  • 关于价格: 0-1美金的价格, 对应当前市场对于该事件的概率(0-1)预测, polymarket使用美分¢ , 1美元 = 100美分

    • 例如: 特朗普赢得2024大选的事件
      • 目前 Yes的Shares的市场价格是 45¢ , 代表目前市场对于特朗普赢得大选的预测的概率是 45%
      • 目前 No的shares的市场价格是 56¢, 即与 Yes的概率相反, 是56%
  • 可以使用 市价限价进行买入卖出

    • 例如:
      • 市价买入, 则买入价格是 卖1的价格;
      • 市价卖出,则卖出价格是 买1的价格
    • 例如:
      • 当前某事件的Yes市价是 45¢, 你挂单 40¢的买入单,则需要等待有40¢卖出单(可以部分成交)才能撮合
  • 关于清算: 如果事件发生了,那么每股清算价格为1$, 即 100¢; 如果事件没有发生,则每股清算价格为 0
    • 例如,你觉得特朗普会赢得2024大选, 那么你按照Yes市价 45¢买入10股,即 450¢, 即4.5$ , 如果特朗普赢了大选, 每股的价格是 100¢, 即1$,那么,你最终将获得是: 100 * 10 = 1000¢ , 那么你的利润是 1000 - 450 = 550, 即 5.5$; 如果特朗普输了大选, 则你损失全部的 450¢ , 即4.5$.
  • 是否可以下注高赔率的事件(加杠杆)?

    • 需要有对手单,polymarket并没有提供杠杆玩法,即polymarket不坐庄,用户实际上是和其他用户做对手单

    • 例如:

      • 你非常不看好特朗普, 觉得他赢得大选概率为0,那么你用 的价格挂一个买入 Yes的单,数量为1000股, 那么, 理论上说,如果事件没有发生,你可以获得 1000$, 利润是 990$, 相当于赔率是 1000倍
      • 但是,你的这笔挂单需要有一个对手单, 即市场上有一另外一个赌徒,他非常看好特朗普,觉得特朗普100%会赢得大选
    • 为了方便起见,使用(BUY, YES, 1) * 1000 表示按照每股1美分的价格买入YES股的1000股

    • 上面的例子: 形成对手单,有2种方式

      • 第一种: 直接方式
        • (BUY, YES, 1) * 1000 的直接对手单是 (SELL, YES, 1) * 1000, 即之前有一个已经有 1000股 YES, 他卖给你
      • 第二种: 间接方式, 因为 YESNO 是共享订单簿的
        • (BUY, YES, 1) * 1000(SELL, NO, 99) * 1000 等价, 可以理解逆否命题
        • (SELL, NO, 99) * 1000 的对手单是 (BUY, NO, 99) * 1000,
        • 因此, (BUY, NO, 99) * 1000 也是 (BUY, YES, 1) * 1000的间接对手单,
        • 可以理解为, 市场上有一个人, 按照 99美分的价格买入1000股YES, 和你形成对手单

ERC20高级充币归集技术

核心技术概括:

  • 使用 CREATE2派生确定的充币地址(合约)
  • 归集时在合约中 使用相同的 salt 和 hash, 创建充币地址(合约)
    • 在合约中执行 ERC20的 approve,授权本合约
    • 调用 selfdestruct销毁合约
  • 转移使用transferFrom转移充币地址中的ERC20代币

实际案例

技术点剖析:

  • 充币地址(接收地址)是一个”临时”合约地址
  • “临时”地址可以派生出来
  • 且,”归集”合约可以操作 “临时”地址进行 approve操作
  • approve完成后即自毁(selfdestruct)了临时合约地址

合约代码分析:

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
// Function that bridges taking amount from the t2bAddress where the user funds are parked.
function bridgeERC20(
uint256 fees,
uint256 nonce,
bytes calldata bridgeData,
bytes calldata signature
) external {
// recovering signer.
address recoveredSigner = ECDSA.recover(
keccak256(
abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
keccak256(
abi.encode(
address(this),
nonce,
block.chainid, // uint256
fees,
bridgeData
)
)
)
),
signature
);

if (signerAddress != recoveredSigner) revert SignerMismatch();
// nonce is used by gated roles and we don't expect nonce to reach the max value of uint256
unchecked {
if (nonce != nextNonce[signerAddress]++) revert InvalidNonce();
}

if (bridgeVerifiers[uint32(bytes4(bridgeData[0:4]))] == address(0))
revert UnsupportedBridge();

// 解析数据
(bool parseSuccess, bytes memory parsedData) = bridgeVerifiers[
uint32(bytes4(bridgeData[0:4]))
].call(bridgeData[4:bridgeData.length - 1]);

if (!parseSuccess) revert VerificationCallFailed();

// 解析数据
IT2BRequest.T2BRequest memory t2bRequest = abi.decode(
parsedData,
(IT2BRequest.T2BRequest)
);

// 获取派生地址
address t2bAddress = getAddressFor(
t2bRequest.recipient,
t2bRequest.toChainId
);

// 判断 allowance
if (
ERC20(t2bRequest.token).allowance(t2bAddress, address(this)) <
t2bRequest.amount
) {
// 计算salt
bytes32 uniqueSalt = keccak256(
abi.encode(t2bRequest.recipient, t2bRequest.toChainId)
);

// 调用 CREATE2 创建临时地址
new T2BApproval{salt: uniqueSalt}(address(this));
}

// 将派生地址的 ERC20代币转移
ERC20(t2bRequest.token).safeTransferFrom(
t2bAddress,
address(this),
t2bRequest.amount + fees
);

//... 其他代码, 略
}
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

// 部署派生地址
function deployApprovalContract(
address receiver,
uint256 toChainId
) public returns (address approvalAddress) {
bytes32 uniqueSalt = keccak256(abi.encode(receiver, toChainId));
approvalAddress = address(new T2BApproval{salt: uniqueSalt}(address(this)));
}

// 获取派生地址
function getAddressFor(
address receiver,
uint256 toChainId
) public view returns (address) {
bytes32 salt = keccak256(abi.encode(receiver, toChainId));
return
address(
uint160(
uint256(
keccak256(

// 可以看下文的 CreateAddress2的实现
abi.encodePacked(
bytes1(0xff), // 固定的
address(this), // 本合约地址
salt, // salt

// 合约代码的 hash
keccak256(
abi.encodePacked(
type(T2BApproval).creationCode, // 合约代码
abi.encode(address(this)) // 合约
)
)
)
)
)
)
);
}
  • T2BApproval 派生地址合约
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
contract T2BApproval {
using SafeTransferLib for ERC20;

error ZeroAddress();
error InvalidTokenAddress();


// Constructor
constructor(address _t2bRouter) {
// Set T2b Router.
IT2BRouter t2bRouter = IT2BRouter(_t2bRouter);

// Set Max Approvals for supported tokens.
uint256 tokenIndex = 0;
while (t2bRouter.supportedTokens(tokenIndex) != address(0)) {

// 进行 approve操作
ERC20(t2bRouter.supportedTokens(tokenIndex)).safeApprove(
address(t2bRouter),
type(uint256).max
);
unchecked {
++tokenIndex;
}
}

// 销毁
selfdestruct(payable(msg.sender));
}
}

安全性:

  • new T2BApproval{salt: uniqueSalt}(address(this));
    • CREATE2 生成的地址是基于部署者地址salt合约字节码的哈希计算的。
1
2
3
//  scope.Contract 是本合约地址
// input 合约代码
res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract, input, gas, &endowment, &salt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Create2 creates a new contract using code as deployment code.
//
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int)
(ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {

// 合约代码的hash
codeAndHash := &codeAndHash{code: code}


contractAddr = crypto.CreateAddress2(caller.Address(), salt.Bytes32(), codeAndHash.Hash().Bytes())
return evm.create(caller, codeAndHash, gas, endowment, contractAddr, CREATE2)
}

生成地址

1
2
3
4
5
// CreateAddress2 creates an ethereum address given the address bytes, initial
// contract code hash and a salt.
func CreateAddress2(b common.Address, salt [32]byte, inithash []byte) common.Address {
return common.BytesToAddress(Keccak256([]byte{0xff}, b.Bytes(), salt[:], inithash)[12:])
}

程序员如何把控自己的职业

https://coolshell.cn/articles/20977.html

  • 第一,如果想要把控技术,应对这个世界的一些变化,需要大致知道这个世界的一些规律和发展趋势,另外还得认识自己,自己到底适合做什么?在这个趋势和规律下属于自己的发挥领域到底是什么?这是我们每个人都需要了解的。

  • 第二,打牢基础,以不变应万变,不管世界怎样变化,我都能很快适应它。基础的重要程度对于你能够飞多高是相当有影响的,懂原理的人比不懂原理的人能做出来的事情或是能解决的问题完全是两个层级的。

  • 第三,提升成长的效率,因为现在社会的节奏实在太快了,比二十年前快得太多,技术层出不穷,所以我们的成长也要更有效率。效率并不单指的快,效率是怎么样更有效,是有用功除以总功,怎么学到更有效的东西,或者怎么更有效学习,是我们需要掌握的另一关键。


打好基础

  • 变化都是表面的东西,内在的东西其实并没有太多的变化。
  • 不懂原理,不懂科学方法,你就不可能成长上去的,

技术的基础,我会把其它成四类:

  • 程序语言:语言的原理,类库的实现,编程技术(并发、异步等),编程范式,设计模式……
  • 系统原理:计算机系统,操作系统,网络协议,数据库原理……
  • 中间件:消息队列,缓存系统,网关代理,调度系统 ……
  • 理论知识:算法和数据结构,数据库范式,网络七层模型,分布式系统……

学习效率

  • 挑选信息源
  • 注重基础和原理
  • 使用知识图谱
  • 举一反三
  • 总结归纳
  • 实践和坚持

技术管理

宏观管理

  • 努力找到好的人
    • 能独挡一面的人。这样交给他的事能独立完成,没有路能自己找路,这样可以省很多管理成本。
    • 沟通能力很强的人。一方面,他们把模糊的事能变清楚,另一方面,他能有效地说服他人。不然就会非常扯皮和消耗时间。
    • 能自管理和自驱动。不能自管理和自驱的人,会增加大量的管理和教育成本。能自驱动的人,都是对负责的事情有认同的人。
  • 设定共同的目标和使命
  • 倾向使用小团队

微观实战

主动,自我驱动,自我管理

  • 文档驱动:文档写作是一种深度思考,当你把你脑子里想的东西写下来的时候,你就会发现你的思考更多了
  • 自动化和简化: 如:自动化测试,自动化部署
  • Owner文化: 每件事都要定义一个Owner
  • Review文化: 很多人以为开会讨论有个议题就行了,其实不够,有效率的开会讨论需要的是议案,而且还是高质量的议案!
  • 目标承诺: 要有工作计划和工作目标, 每个人自己给自己制定的计划最好是在1-2周内。
  • 自我管理:
  • 知识分享会:
  • Copyrights © 2021-2024 youngqqcn

请我喝杯咖啡吧~